- 개발팀 전용 폴더 dev/ 생성 (standards, guides, quickstart, changes, deploys, data, history, dev_plans 이동) - 프론트엔드 전용 폴더 frontend/ 생성 (api/ → frontend/api-specs/) - 기획팀 폴더 requests/ 생성 - plans/ → dev/dev_plans/ 이름 변경 - README.md 신규 (사람용 안내), INDEX.md 재작성 (Claude Code용) - resources.md 신규 (노션 링크용, assets/brochure 이관 예정) - CURRENT_WORKS.md 삭제, TODO.md → dev/ 이동 - 전체 참조 경로 업데이트 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
460 lines
23 KiB
Markdown
460 lines
23 KiB
Markdown
# 휴가관리 모듈 개발 계획서
|
|
|
|
> **작성일**: 2026-02-26
|
|
> **상태**: 설계 중
|
|
|
|
---
|
|
|
|
## 1. 개요
|
|
|
|
### 1.1 목적
|
|
|
|
근태현황에 포함된 휴가/연차 기능을 **독립된 휴가관리 모듈**로 분리한다.
|
|
근로기준법 기반 연차 자동 계산, 휴가 신청/승인, 잔여 연차 관리를 체계적으로 지원한다.
|
|
|
|
### 1.2 핵심 원칙
|
|
|
|
- 근태현황의 `vacation` 상태는 **결과 기록**으로만 유지 (휴가 승인 완료 시 자동 기록)
|
|
- 휴가 신청/승인/잔여일수 관리는 모두 **휴가관리 모듈**에서 수행
|
|
- 기존 API 테이블/모델(`leaves`, `leave_balances`, `leave_policies`, `leave_grants`)을 최대한 활용
|
|
- MNG에서 관리자 인터페이스(Blade + HTMX) 구현
|
|
|
|
### 1.3 현재 상태 분석
|
|
|
|
| 항목 | API (DB/모델) | MNG (UI/서비스) | 비고 |
|
|
|------|:------------:|:--------------:|------|
|
|
| `leaves` 테이블 | ✅ 마이그레이션 완료 | ❌ 미구현 | 핵심 테이블 |
|
|
| `leave_balances` 테이블 | ✅ 마이그레이션 완료 | ⚠️ 단순 모델만 | 연차 잔액 |
|
|
| `leave_policies` 테이블 | ✅ 마이그레이션 완료 | ❌ 미구현 | 연차 정책 설정 |
|
|
| `leave_grants` 테이블 | ✅ 마이그레이션 완료 | ❌ 미구현 | 연차 부여 이력 |
|
|
| `attendance_requests` 테이블 | ✅ 마이그레이션 완료 | ✅ 신청/승인 구현 | 근태현황에 포함 |
|
|
| 연차 자동 차감 | — | ⚠️ 단순 구현 | 복원 로직 없음 |
|
|
|
|
### 1.4 근태현황과의 역할 분리
|
|
|
|
| 기능 | 근태현황 (유지) | 휴가관리 (신규) |
|
|
|------|:--------------:|:--------------:|
|
|
| 출퇴근 기록 | ✅ | — |
|
|
| 출장/재택/외근 신청·승인 | ✅ | — |
|
|
| `vacation` 상태 표시 | ✅ (결과만) | — |
|
|
| 연차 부여/발생 규칙 | — | ✅ |
|
|
| 휴가 신청·승인 워크플로우 | — | ✅ |
|
|
| 잔여 연차 관리 | — | ✅ |
|
|
| 연차 촉진 알림 | — | ✅ (Phase 3) |
|
|
|
|
---
|
|
|
|
## 2. 기존 DB 스키마
|
|
|
|
> API에 이미 마이그레이션 완료된 테이블들. MNG에서 모델만 생성하여 활용한다.
|
|
|
|
### 2.1 `leaves` 테이블
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────┐
|
|
│ leaves │
|
|
├────────────────┬─────────────┬────────────────────────────┤
|
|
│ id │ bigint PK │ Auto Increment │
|
|
│ tenant_id │ bigint FK │ → tenants.id │
|
|
│ user_id │ bigint FK │ → users.id │
|
|
│ leave_type │ enum │ annual, half_am, half_pm, │
|
|
│ │ │ sick, family, maternity, │
|
|
│ │ │ parental │
|
|
│ start_date │ date │ 시작일 │
|
|
│ end_date │ date │ 종료일 │
|
|
│ days │ decimal(3,1)│ 사용일수 (0.5 = 반차) │
|
|
│ reason │ text │ 사유 │
|
|
│ status │ enum │ pending, approved, rejected, │
|
|
│ │ │ cancelled │
|
|
│ approved_by │ bigint │ 승인자 ID │
|
|
│ approved_at │ datetime │ 승인 일시 │
|
|
│ reject_reason │ text │ 반려 사유 │
|
|
│ created_by/ │ bigint │ 감사 필드 │
|
|
│ updated_by/ │ │ │
|
|
│ deleted_by │ │ │
|
|
│ timestamps │ │ │
|
|
│ soft_deletes │ │ │
|
|
└────────────────┴─────────────┴────────────────────────────┘
|
|
INDEX: (tenant_id, user_id), status, (start_date, end_date)
|
|
```
|
|
|
|
### 2.2 `leave_balances` 테이블
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────┐
|
|
│ leave_balances │
|
|
├────────────────┬─────────────┬────────────────────────────┤
|
|
│ id │ bigint PK │ │
|
|
│ tenant_id │ bigint FK │ │
|
|
│ user_id │ bigint FK │ │
|
|
│ year │ int │ 연도 │
|
|
│ total_days │ decimal(4,1)│ 부여일수 (기본 15) │
|
|
│ used_days │ decimal(4,1)│ 사용일수 │
|
|
│ remaining_days │ decimal(4,1)│ storedAs(total - used) │
|
|
└────────────────┴─────────────┴────────────────────────────┘
|
|
UNIQUE: (tenant_id, user_id, year)
|
|
```
|
|
|
|
### 2.3 `leave_policies` 테이블
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────┐
|
|
│ leave_policies │
|
|
├──────────────────────┬─────────────┬─────────────────────┤
|
|
│ tenant_id │ bigint UNIQUE│ 테넌트당 1개 │
|
|
│ standard_type │ enum │ fiscal / hire │
|
|
│ fiscal_start_month │ tinyint │ 회계연도 시작월 │
|
|
│ fiscal_start_day │ tinyint │ 회계연도 시작일 │
|
|
│ default_annual_leave │ int │ 기본 연차 (15) │
|
|
│ additional_leave_per_year │ int │ 근속 가산 (+1) │
|
|
│ max_annual_leave │ int │ 최대 연차 (25) │
|
|
│ carry_over_enabled │ boolean │ 이월 허용 │
|
|
│ carry_over_max_days │ int │ 이월 한도 │
|
|
│ carry_over_expiry_months │ int │ 이월 소멸 개월 │
|
|
└──────────────────────┴─────────────┴─────────────────────┘
|
|
```
|
|
|
|
### 2.4 `leave_grants` 테이블
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────┐
|
|
│ leave_grants │
|
|
├────────────────┬─────────────┬────────────────────────────┤
|
|
│ tenant_id │ bigint FK │ │
|
|
│ user_id │ bigint FK │ │
|
|
│ grant_type │ enum │ annual, monthly, reward, │
|
|
│ │ │ condolence, other │
|
|
│ grant_date │ date │ 부여일 │
|
|
│ grant_days │ decimal(4,1)│ 부여일수 │
|
|
│ reason │ text │ 부여 사유 │
|
|
└────────────────┴─────────────┴────────────────────────────┘
|
|
INDEX: (tenant_id, user_id), grant_date, grant_type
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Phase 1: 기본 휴가관리 (핵심)
|
|
|
|
> 🔴 **필수** — 연차 조회, 휴가 신청/승인, 잔여일수 관리
|
|
|
|
### 3.1 MNG 모델 생성
|
|
|
|
| 모델 | 파일 | 대상 테이블 |
|
|
|------|------|------------|
|
|
| `Leave` | `app/Models/HR/Leave.php` | `leaves` |
|
|
| `LeavePolicy` | `app/Models/HR/LeavePolicy.php` | `leave_policies` |
|
|
| `LeaveGrant` | `app/Models/HR/LeaveGrant.php` | `leave_grants` |
|
|
| `LeaveBalance` | (기존 수정) | `leave_balances` |
|
|
|
|
### 3.2 LeaveService 생성
|
|
|
|
**파일**: `app/Services/HR/LeaveService.php`
|
|
|
|
| 메서드 | 설명 |
|
|
|--------|------|
|
|
| `getLeaves(array $filters, int $perPage)` | 휴가 목록 조회 (필터: 사원, 유형, 상태, 기간) |
|
|
| `storeLeave(array $data)` | 휴가 신청 등록 (잔여일수 검증 포함) |
|
|
| `approve(int $id)` | 승인 처리 → `leave_balances` 차감 → `attendances` 자동 기록 |
|
|
| `reject(int $id, ?string $reason)` | 반려 처리 |
|
|
| `cancel(int $id)` | 취소 처리 → `leave_balances` 복원 → `attendances` 삭제 |
|
|
| `getBalance(int $userId, ?int $year)` | 사원별 연차 잔여일수 조회 |
|
|
| `getBalanceSummary(?int $year)` | 전체 사원 잔여일수 요약 |
|
|
| `calculateDays(string $type, string $startDate, string $endDate)` | 신청 일수 자동 계산 (주말 제외, 반차=0.5) |
|
|
|
|
### 3.3 LeaveController (API) 생성
|
|
|
|
**파일**: `app/Http/Controllers/Api/Admin/HR/LeaveController.php`
|
|
|
|
| Method | Path | 설명 |
|
|
|--------|------|------|
|
|
| GET | `/admin/hr/leaves` | 휴가 목록 (HTMX/JSON) |
|
|
| POST | `/admin/hr/leaves` | 휴가 신청 등록 |
|
|
| POST | `/admin/hr/leaves/{id}/approve` | 승인 |
|
|
| POST | `/admin/hr/leaves/{id}/reject` | 반려 |
|
|
| POST | `/admin/hr/leaves/{id}/cancel` | 취소 |
|
|
| GET | `/admin/hr/leaves/balance` | 전체 사원 잔여일수 요약 |
|
|
| GET | `/admin/hr/leaves/balance/{userId}` | 개별 사원 잔여일수 |
|
|
| GET | `/admin/hr/leaves/export` | 엑셀(CSV) 내보내기 |
|
|
|
|
### 3.4 MNG 뷰 컨트롤러
|
|
|
|
**파일**: `app/Http/Controllers/HR/LeaveController.php`
|
|
|
|
```
|
|
GET /hr/leaves → index 페이지 (휴가관리 메인)
|
|
```
|
|
|
|
### 3.5 뷰 구성
|
|
|
|
**파일**: `resources/views/hr/leaves/index.blade.php`
|
|
|
|
```
|
|
┌───────────────────────────────────────────────────────┐
|
|
│ 휴가관리 │
|
|
├───────────┬───────────┬─────────────┬─────────────────┤
|
|
│ 휴가신청 │ 잔여연차 │ 사용현황 │ (Phase 2) 설정 │
|
|
│ (탭 1) │ (탭 2) │ (탭 3) │ (탭 4) │
|
|
└───────────┴───────────┴─────────────┴─────────────────┘
|
|
```
|
|
|
|
**탭 1: 휴가신청 목록**
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────┐
|
|
│ [+ 휴가 신청] [엑셀 내보내기] │
|
|
│ │
|
|
│ 필터: [사원 ▼] [유형 ▼] [상태 ▼] [기간 ~] │
|
|
│ │
|
|
│ ┌──────┬──────┬──────┬──────┬─────┬──────┬─────┐ │
|
|
│ │ 사원 │ 유형 │ 기간 │ 일수 │사유 │ 상태 │ 처리│ │
|
|
│ ├──────┼──────┼──────┼──────┼─────┼──────┼─────┤ │
|
|
│ │홍길동│ 연차 │2/24~ │ 1.0 │개인 │ 대기 │승인 │ │
|
|
│ │ │ │ 2/24 │ │사유 │ │반려 │ │
|
|
│ │김영희│ 반차 │2/25 │ 0.5 │병원 │ 승인 │취소 │ │
|
|
│ │ │(오전)│ │ │ │ │ │ │
|
|
│ └──────┴──────┴──────┴──────┴─────┴──────┴─────┘ │
|
|
│ │
|
|
│ [페이지네이션] │
|
|
└─────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**탭 2: 잔여연차 현황**
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────┐
|
|
│ 연도: [2026 ▼] │
|
|
│ │
|
|
│ ┌──────┬──────┬──────┬──────┬──────┬──────────┐ │
|
|
│ │ 사원 │ 부서 │ 입사일│ 부여 │ 사용 │ 잔여 │ │
|
|
│ ├──────┼──────┼──────┼──────┼──────┼──────────┤ │
|
|
│ │홍길동│ 개발 │21.03 │ 20.0 │ 5.0 │ 15.0 │ │
|
|
│ │김영희│ 영업 │23.08 │ 15.0 │ 3.5 │ 11.5 │ │
|
|
│ │이민수│ 총무 │25.06 │ 11.0 │ 2.0 │ 9.0 │ │
|
|
│ └──────┴──────┴──────┴──────┴──────┴──────────┘ │
|
|
└─────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**탭 3: 사용현황 통계**
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────┐
|
|
│ 기간: [2026 ▼] [전체/부서별 ▼] │
|
|
│ │
|
|
│ 유형별 집계: 연차 45건 | 반차 12건 | 병가 3건 │
|
|
│ │
|
|
│ 월별 사용 추이 차트 (선택적) │
|
|
│ │
|
|
│ ┌──────┬──────┬──────┬──────┬──────┬──────────┐ │
|
|
│ │ 사원 │ 연차 │ 반차 │ 병가 │ 경조 │ 합계 │ │
|
|
│ ├──────┼──────┼──────┼──────┼──────┼──────────┤ │
|
|
│ │홍길동│ 3.0 │ 1.0 │ 1.0 │ 0.0 │ 5.0 │ │
|
|
│ │김영희│ 2.0 │ 1.5 │ 0.0 │ 0.0 │ 3.5 │ │
|
|
│ └──────┴──────┴──────┴──────┴──────┴──────────┘ │
|
|
└─────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 3.6 휴가 신청 모달
|
|
|
|
```
|
|
┌──────────────────────────────────────────┐
|
|
│ 휴가 신청 │
|
|
├──────────────────────────────────────────┤
|
|
│ 사원: [홍길동 ▼] 잔여: 15.0일 │
|
|
│ 유형: [연차 ▼] │
|
|
│ 기간: [2026-02-27] ~ [2026-02-28] │
|
|
│ 일수: 2.0일 (자동 계산, 주말 제외) │
|
|
│ 사유: [ ] │
|
|
│ │
|
|
│ [취소] [신청] │
|
|
└──────────────────────────────────────────┘
|
|
```
|
|
|
|
### 3.7 근태현황 연동 로직
|
|
|
|
```
|
|
휴가 승인 시:
|
|
┌──────────┐ ┌──────────────┐ ┌──────────────┐
|
|
│ Leave │──→ │ LeaveBalance │──→ │ Attendance │
|
|
│ approved │ │ used_days +N │ │ status= │
|
|
│ │ │ │ │ vacation │
|
|
└──────────┘ └──────────────┘ └──────────────┘
|
|
|
|
휴가 취소 시:
|
|
┌──────────┐ ┌──────────────┐ ┌──────────────┐
|
|
│ Leave │──→ │ LeaveBalance │──→ │ Attendance │
|
|
│ cancelled │ │ used_days -N │ │ 해당 날짜 │
|
|
│ │ │ │ │ 레코드 삭제 │
|
|
└──────────┘ └──────────────┘ └──────────────┘
|
|
```
|
|
|
|
### 3.8 근태현황 정리 작업
|
|
|
|
Phase 1 구현 후 근태현황에서 다음을 정리:
|
|
|
|
- `AttendanceRequest`의 `vacation` 유형 → 휴가관리로 이관 (출장/재택/외근만 유지)
|
|
- `AttendanceService.deductLeaveBalance()` 제거 → `LeaveService`로 일원화
|
|
- `AttendanceController.leaveBalance()` 제거 → `LeaveController`로 이관
|
|
|
|
---
|
|
|
|
## 4. Phase 2: 연차 정책 및 자동 계산
|
|
|
|
> 🟡 **중요** — 근로기준법 기반 연차 자동 발생, 정책 설정
|
|
|
|
### 4.1 연차 정책 설정 UI
|
|
|
|
**탭 4: 휴가 설정** (Phase 2에서 활성화)
|
|
|
|
```
|
|
┌──────────────────────────────────────────┐
|
|
│ 연차 기준 │
|
|
│ ○ 입사일 기준 ● 회계연도 기준 │
|
|
│ 회계연도 시작: [1]월 [1]일 │
|
|
│ │
|
|
│ 연차 일수 │
|
|
│ 기본 연차: [15]일 │
|
|
│ 2년 초과 시 가산: [1]일/2년 │
|
|
│ 최대 연차: [25]일 │
|
|
│ │
|
|
│ 이월 설정 │
|
|
│ □ 잔여 연차 이월 허용 │
|
|
│ 이월 한도: [5]일 │
|
|
│ 이월 소멸: [3]개월 후 │
|
|
│ │
|
|
│ [저장] │
|
|
└──────────────────────────────────────────┘
|
|
```
|
|
|
|
### 4.2 LeavePolicyService
|
|
|
|
**파일**: `app/Services/HR/LeavePolicyService.php`
|
|
|
|
| 메서드 | 설명 |
|
|
|--------|------|
|
|
| `getPolicy()` | 현재 테넌트 연차 정책 조회 |
|
|
| `updatePolicy(array $data)` | 정책 저장/수정 |
|
|
| `calculateAnnualLeave(int $userId)` | 사원별 연차 자동 계산 (입사일 + 근속년수 기반) |
|
|
| `generateAnnualLeaves()` | 전체 사원 연차 일괄 발생 (연초/입사일 기준) |
|
|
| `processCarryOver()` | 이월 처리 (연말) |
|
|
|
|
### 4.3 연차 발생 규칙 (근로기준법)
|
|
|
|
```php
|
|
// 입사일 기준 연차 계산 로직
|
|
function calculateAnnualDays(Carbon $hireDate): float
|
|
{
|
|
$years = $hireDate->diffInYears(now());
|
|
|
|
if ($years < 1) {
|
|
// 1년 미만: 매월 개근 시 1일 (최대 11일)
|
|
$months = $hireDate->diffInMonths(now());
|
|
return min($months, 11);
|
|
}
|
|
|
|
// 1년 이상: 15일 + (근속년수-1)/2 가산 (최대 25일)
|
|
$base = 15;
|
|
$additional = max(0, floor(($years - 1) / 2));
|
|
return min($base + $additional, 25);
|
|
}
|
|
```
|
|
|
|
### 4.4 연차 부여 이력 관리
|
|
|
|
`leave_grants` 테이블을 활용하여 부여 이력 추적:
|
|
|
|
| grant_type | 설명 | 예시 |
|
|
|-----------|------|------|
|
|
| `annual` | 연차 자동 발생 | 2026년 연차 15일 부여 |
|
|
| `monthly` | 1년 미만 월차 | 2026-03 월차 1일 부여 |
|
|
| `reward` | 포상 휴가 | 우수사원 포상 2일 |
|
|
| `condolence` | 경조사 | 결혼 경조 5일 |
|
|
| `other` | 기타 | 회사 지정 휴가 |
|
|
|
|
---
|
|
|
|
## 5. Phase 3: 고급 기능
|
|
|
|
> 🟢 **권장** — 연차 촉진, 알림, 리포트
|
|
|
|
### 5.1 연차 촉진제도 (근로기준법 제61조)
|
|
|
|
| 시기 | 내용 | 자동화 |
|
|
|------|------|--------|
|
|
| 만료 6개월 전 | 1차 촉진 통보 (미사용 일수 안내) | 카카오 알림톡 발송 |
|
|
| 근로자 미응답 시 | 사용 시기 지정 촉구 | 리마인더 알림 |
|
|
| 만료 2개월 전 | 2차 촉진 통보 (회사 지정) | 카카오 알림톡 + 이력 보관 |
|
|
|
|
### 5.2 알림 기능
|
|
|
|
- 휴가 승인/반려 시 신청자에게 알림톡
|
|
- 잔여 연차 N일 이하 시 사용 권고 알림
|
|
- 연차 소멸 D-30, D-7 자동 알림
|
|
|
|
### 5.3 리포트
|
|
|
|
- 부서별/사원별 연차 사용율 대시보드
|
|
- 연차 대장 엑셀 출력 (노무감사 대비)
|
|
- 월별 사용 추이 통계
|
|
|
|
---
|
|
|
|
## 6. 구현 순서
|
|
|
|
### Phase 1 (기본 — 약 1~2일)
|
|
|
|
| Step | 작업 | 파일 |
|
|
|------|------|------|
|
|
| 1 | MNG 모델 생성 (Leave, LeavePolicy, LeaveGrant) | `app/Models/HR/` |
|
|
| 2 | LeaveService 생성 | `app/Services/HR/LeaveService.php` |
|
|
| 3 | LeaveController (API) 생성 | `app/Http/Controllers/Api/Admin/HR/` |
|
|
| 4 | API 라우트 등록 | `routes/api.php` |
|
|
| 5 | 뷰 컨트롤러 생성 | `app/Http/Controllers/HR/LeaveController.php` |
|
|
| 6 | 웹 라우트 등록 | `routes/web.php` |
|
|
| 7 | index.blade.php 작성 (3개 탭) | `resources/views/hr/leaves/` |
|
|
| 8 | 파셜 뷰 작성 (목록, 잔여, 통계) | `resources/views/hr/leaves/partials/` |
|
|
| 9 | 근태현황 vacation 연동 정리 | AttendanceService 수정 |
|
|
| 10 | 메뉴 등록 안내 | tinker 명령 제공 |
|
|
|
|
### Phase 2 (정책 — 약 1일)
|
|
|
|
| Step | 작업 |
|
|
|------|------|
|
|
| 1 | LeavePolicyService 생성 |
|
|
| 2 | 연차 자동 계산 로직 구현 |
|
|
| 3 | 설정 UI (탭 4) 추가 |
|
|
| 4 | 연차 일괄 발생 Artisan 명령 |
|
|
| 5 | 이월 처리 로직 |
|
|
|
|
### Phase 3 (고급 — 추후)
|
|
|
|
| Step | 작업 |
|
|
|------|------|
|
|
| 1 | 연차 촉진 스케줄러 |
|
|
| 2 | 카카오 알림톡 연동 |
|
|
| 3 | 연차 대장 리포트 |
|
|
| 4 | 대시보드 위젯 |
|
|
|
|
---
|
|
|
|
## 7. 핵심 설계 결정
|
|
|
|
| 항목 | 결정 | 이유 |
|
|
|------|------|------|
|
|
| 신규 테이블 | 불필요 | API에 4개 테이블 이미 존재 |
|
|
| 휴가 신청 테이블 | `leaves` 사용 | `attendance_requests`에서 vacation 분리 |
|
|
| 반차 처리 | `leave_type`=`half_am`/`half_pm`, `days`=0.5 | 기존 enum 활용 |
|
|
| 연차 차감 시점 | 승인 시 즉시 차감 | 잔여일수 실시간 반영 |
|
|
| 근태 연동 | 승인 시 Attendance 자동 생성 | 기존 패턴 유지 |
|
|
| 취소 시 복원 | used_days 복원 + Attendance 삭제 | 데이터 일관성 |
|
|
|
|
---
|
|
|
|
## 관련 문서
|
|
|
|
- `plans/attendance-management-plan.md` — 근태현황 개발 계획
|
|
- `rules/attendance-api.md` — 근태 API 규칙
|
|
|
|
---
|
|
|
|
**최종 업데이트**: 2026-02-26
|