Files
sam-docs/dev/dev_plans/leave-management-plan.md
권혁성 db63fcff85 refactor: [docs] 팀별 폴더 구조 재편 (공유/개발/프론트/기획)
- 개발팀 전용 폴더 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>
2026-03-05 16:46:03 +09:00

23 KiB

휴가관리 모듈 개발 계획서

작성일: 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 구현 후 근태현황에서 다음을 정리:

  • AttendanceRequestvacation 유형 → 휴가관리로 이관 (출장/재택/외근만 유지)
  • 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 연차 발생 규칙 (근로기준법)

// 입사일 기준 연차 계산 로직
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