# 근태관리 기획서

> **작성일**: 2026-02-26
> **상태**: 1차 구현 완료 / 2차 고도화 예정
> **담당**: MNG 인사관리 모듈

---

## 1. 개요

### 1.1 목적

사원의 일별 출퇴근 및 근태 상태를 체계적으로 관리하여, 급여 산정·인사 평가·법정 근로시간 준수의 기초 데이터를 확보한다.

### 1.2 핵심 원칙

| 원칙 | 설명 |
|------|------|
| **정확성** | 출퇴근 시간·상태를 실시간으로 정확히 기록 |
| **자동화** | 지각/정시 자동 판정, 근무시간 자동 계산 |
| **유연성** | 휴가·출장·외근·재택 등 다양한 근무 형태 지원 |
| **감사 추적** | 모든 등록·수정·삭제에 작업자 기록 |

---

## 2. 화면 구성

### 2.1 메뉴 위치

```
인사관리
├── 사원관리
├── 근태관리 ← 현재 문서
├── 달력 관리
└── (향후 확장)
```

### 2.2 메인 화면 레이아웃

```
┌─────────────────────────────────────────────────────────────┐
│ 근태현황                                    [+ 근태 등록]    │
│ 2026년 2월 현재                                              │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────┐│
│ │ 정시출근 │ │  지각   │ │  결근   │ │  휴가   │ │  기타  ││
│ │   42건  │ │   3건  │ │   0건  │ │   5건  │ │   2건 ││
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └────────┘│
├─────────────────────────────────────────────────────────────┤
│ [검색: 사원명] [부서 ▼] [상태 ▼] [시작일] [종료일] [검색]  │
├─────────────────────────────────────────────────────────────┤
│ 날짜     │ 사원   │ 부서   │ 상태   │ 출근  │ 퇴근  │ 비고 │
│──────────┼────────┼────────┼────────┼───────┼───────┼──────│
│ 02-26    │ 홍길동 │ 개발팀 │ 정시   │ 08:55 │ 18:10 │      │
│ 02-26    │ 김철수 │ 영업팀 │ 지각   │ 09:15 │ 18:30 │      │
│ 02-25    │ 이영희 │ 경영   │ 휴가   │  -    │  -    │ 연차 │
├─────────────────────────────────────────────────────────────┤
│                    ◀ 1  2  3  4  5 ▶                        │
└─────────────────────────────────────────────────────────────┘
```

### 2.3 근태 등록/수정 모달

```
┌──────────────── 근태 등록 ─────────────────┐
│                                             │
│  사원      [홍길동 ▼]                       │
│  날짜      [2026-02-26]                     │
│  상태      [정시출근 ▼]                     │
│  출근시간  [09:00]                          │
│  퇴근시간  [18:00]                          │
│  비고      [                            ]   │
│                                             │
│                      [취소]  [저장]          │
└─────────────────────────────────────────────┘
```

---

## 3. 근태 상태 유형

| 상태 | 코드 | 색상 | 설명 |
|------|------|------|------|
| 정시출근 | `onTime` | 🟢 emerald | 정해진 출근 시간 내 출근 |
| 지각 | `late` | 🟡 amber | 출근 시간 초과 후 출근 |
| 결근 | `absent` | 🔴 red | 무단 미출근 |
| 휴가 | `vacation` | 🔵 blue | 연차·반차·병가 등 |
| 출장 | `businessTrip` | 🟣 purple | 사외 업무 수행 |
| 외근 | `fieldWork` | 🟤 indigo | 외부 근무 |
| 야근 | `overtime` | 🟠 orange | 정규시간 초과 근무 |
| 재택 | `remote` | 🟦 teal | 원격 근무 |

---

## 4. 데이터 구조

### 4.1 attendances 테이블

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `id` | BIGINT PK | 고유 ID |
| `tenant_id` | BIGINT FK | 테넌트 ID |
| `user_id` | BIGINT FK | 사용자 ID |
| `base_date` | DATE | 기준 일자 |
| `status` | ENUM | 근태 상태 (8종) |
| `json_details` | JSON | 상세 정보 (출퇴근 시간, GPS 등) |
| `remarks` | VARCHAR(500) | 비고 |
| `created_by` | BIGINT | 등록자 |
| `updated_by` | BIGINT | 수정자 |
| `deleted_by` | BIGINT | 삭제자 |
| `created_at` | TIMESTAMP | 등록일시 |
| `updated_at` | TIMESTAMP | 수정일시 |
| `deleted_at` | TIMESTAMP | 삭제일시 (Soft Delete) |

**제약 조건**:
- `UNIQUE (tenant_id, user_id, base_date)` — 일자별 사용자당 1건만 허용

### 4.2 json_details 구조

```json
{
  "check_in": "09:00:00",
  "check_out": "18:00:00",
  "check_ins": [
    { "time": "09:00:00", "recorded_at": "2026-02-26T09:00:00+09:00" }
  ],
  "check_outs": [
    { "time": "18:00:00", "recorded_at": "2026-02-26T18:00:00+09:00" }
  ],
  "gps_data": {
    "check_in": { "lat": 37.5665, "lng": 126.9780, "accuracy": 10 },
    "check_out": { "lat": 37.5665, "lng": 126.9780, "accuracy": 10 }
  },
  "work_minutes": 480,
  "break_minutes": 60,
  "overtime_minutes": 0,
  "late_minutes": 0,
  "early_leave_minutes": 0,
  "vacation_type": "annual",
  "external_work": {
    "location": "고객사",
    "purpose": "미팅",
    "start_time": "14:00",
    "end_time": "16:00"
  }
}
```

### 4.3 attendance_settings 테이블

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `tenant_id` | BIGINT UNIQUE | 테넌트별 1건 |
| `use_gps` | BOOLEAN | GPS 출퇴근 사용 여부 |
| `use_auto` | BOOLEAN | 자동 출퇴근 사용 여부 |
| `allowed_radius` | INT | 허용 반경 (m, 기본 100) |
| `hq_address` | VARCHAR(255) | 사업장 주소 |
| `hq_latitude` | DECIMAL(10,8) | 사업장 위도 |
| `hq_longitude` | DECIMAL(11,8) | 사업장 경도 |

---

## 5. 비즈니스 규칙

### 5.1 출퇴근 기록

| 규칙 | 설명 |
|------|------|
| R1 | 같은 날짜 + 사용자 조합은 1건만 존재 (Upsert) |
| R2 | 출근 기록 시 WorkSetting의 `start_time` 기준으로 지각/정시 자동 판정 |
| R3 | 퇴근 기록 시 근무시간 자동 계산: (최초 출근 ~ 최종 퇴근) - 휴게시간 |
| R4 | 다중 출퇴근 기록 지원 — `check_ins`/`check_outs` 배열로 이력 관리 |
| R5 | GPS 기록 시 사업장 반경 내 여부 검증 (Haversine 공식) |

### 5.2 상태 자동 판정

```
출근 시간 기록 시:
├── WorkSetting.start_time 이전 → 상태: 'onTime' (정시출근)
├── WorkSetting.start_time 이후 → 상태: 'late' (지각)
└── WorkSetting 미설정 → 상태: 'onTime' (기본값)
```

### 5.3 근무시간 계산

```
총 근무시간 = (가장 늦은 퇴근시간 - 가장 빠른 출근시간) - 휴게시간

휴게시간 산출:
├── WorkSetting에 break_start/break_end 설정 있음
│   └── 근무시간이 휴게 시간대를 포함하면 차감
└── 미설정 → 휴게시간 0분
```

### 5.4 권한

| 역할 | 조회 | 등록 | 수정 | 삭제 |
|------|:----:|:----:|:----:|:----:|
| 관리자 (admin) | ✅ 전체 | ✅ | ✅ | ✅ |
| 부서장 | ✅ 소속 부서 | ✅ | ✅ | ❌ |
| 일반 사원 | ✅ 본인 | ❌ | ❌ | ❌ |

---

## 6. 기능 목록

### 6.1 1차 구현 (완료)

| 기능 | 상태 | 설명 |
|------|:----:|------|
| 근태 목록 조회 | ✅ | 페이지네이션, 필터링, HTMX 테이블 |
| 근태 등록/수정 | ✅ | 모달 기반 CRUD |
| 근태 삭제 | ✅ | Soft Delete + 확인 대화상자 |
| 월별 통계 카드 | ✅ | 정시/지각/결근/휴가/기타 집계 |
| 필터링 | ✅ | 사원명 검색, 부서/상태/날짜 범위 필터 |
| 출근/퇴근 기록 API | ✅ | check-in/check-out 엔드포인트 |
| 근무시간 자동 계산 | ✅ | 출퇴근 시간 차 - 휴게시간 |
| 상태 자동 판정 | ✅ | WorkSetting 기준 지각/정시 판별 |
| 엑셀 내보내기 | ✅ | 월별 데이터 Excel 다운로드 |
| GPS 설정 | ✅ | 사업장 좌표, 허용 반경 설정 |
| 다중 출퇴근 기록 | ✅ | check_ins/check_outs 배열 관리 |
| 감사 로그 | ✅ | created_by, updated_by, deleted_by |

### 6.2 2차 고도화 (예정)

| 기능 | 우선순위 | 설명 |
|------|:--------:|------|
| 월간 캘린더 뷰 | 🔴 높음 | 달력 형태로 사원별 근태 현황 표시 |
| 일괄 등록 | 🔴 높음 | 다수 사원의 근태를 한 번에 등록 (CSV/엑셀 업로드) |
| 근태 승인 워크플로우 | 🟡 중간 | 휴가/출장 신청 → 부서장 승인 → 확정 |
| 초과근무 알림 | 🟡 중간 | 주 52시간 초과 시 관리자 알림 |
| 사원별 월간 요약 | 🟡 중간 | 개인별 월간 근무일수, 총 근무시간, 지각 횟수 등 |
| GPS 출퇴근 (모바일) | 🟢 낮음 | 모바일 앱에서 GPS 기반 자동 출퇴근 |
| 자동 결근 처리 | 🟢 낮음 | 영업일에 출근 기록 없으면 자동으로 결근 표시 |
| 연차 관리 연동 | 🟢 낮음 | 휴가 상태 등록 시 잔여 연차 자동 차감 |

---

## 7. API 엔드포인트

### 7.1 MNG 내부 API (HTMX)

| Method | Path | 설명 |
|--------|------|------|
| GET | `/api/admin/hr/attendances` | 목록 조회 (HTML/JSON) |
| POST | `/api/admin/hr/attendances` | 등록 |
| PUT | `/api/admin/hr/attendances/{id}` | 수정 |
| DELETE | `/api/admin/hr/attendances/{id}` | 삭제 |

### 7.2 외부 API (sam/api)

| Method | Path | 설명 |
|--------|------|------|
| GET | `/api/v1/attendances` | 목록 조회 (페이지네이션) |
| GET | `/api/v1/attendances/{id}` | 상세 조회 |
| POST | `/api/v1/attendances` | 등록 |
| PATCH | `/api/v1/attendances/{id}` | 수정 |
| DELETE | `/api/v1/attendances/{id}` | 삭제 |
| POST | `/api/v1/attendances/bulk-delete` | 일괄 삭제 |
| POST | `/api/v1/attendances/check-in` | 출근 기록 |
| POST | `/api/v1/attendances/check-out` | 퇴근 기록 |
| GET | `/api/v1/attendances/monthly-stats` | 월별 통계 |
| GET | `/api/v1/attendances/export` | 엑셀 내보내기 |

---

## 8. 프로세스 흐름

### 8.1 관리자 근태 등록

```
관리자 → [근태 등록] 클릭 → 모달 열림
  → 사원 선택, 날짜·상태·시간 입력
  → [저장] 클릭
  → Fetch POST /api/admin/hr/attendances
  → 같은 날짜+사용자 기존 기록 있으면 Upsert
  → 성공 → 테이블 HTMX 새로고침
```

### 8.2 사원 출근 (API)

```
사원(모바일) → [출근] 버튼
  → POST /api/v1/attendances/check-in
    { user_id, check_in_time, gps? }
  → 서버: WorkSetting.start_time 기준 지각/정시 판정
  → 기존 기록 없으면 신규 생성
  → 기존 기록 있으면 check_ins 배열에 추가
  → 응답: 근태 레코드 반환
```

### 8.3 사원 퇴근 (API)

```
사원(모바일) → [퇴근] 버튼
  → POST /api/v1/attendances/check-out
    { user_id, check_out_time, gps? }
  → 서버: 근무시간 자동 계산
    (가장 빠른 출근 ~ 가장 늦은 퇴근) - 휴게시간
  → check_outs 배열에 추가
  → work_minutes, overtime_minutes 업데이트
  → 응답: 근태 레코드 반환
```

---

## 9. 관련 파일

### MNG

| 파일 | 설명 |
|------|------|
| `app/Http/Controllers/HR/AttendanceController.php` | 페이지 렌더링 |
| `app/Http/Controllers/Api/Admin/HR/AttendanceController.php` | HTMX API |
| `app/Models/HR/Attendance.php` | 모델 (Accessor 포함) |
| `app/Services/HR/AttendanceService.php` | 비즈니스 로직 |
| `resources/views/hr/attendances/index.blade.php` | 메인 페이지 |
| `resources/views/hr/attendances/partials/table.blade.php` | 테이블 partial |

### API

| 파일 | 설명 |
|------|------|
| `app/Http/Controllers/Api/V1/AttendanceController.php` | RESTful API |
| `app/Models/Tenants/Attendance.php` | 모델 |
| `app/Models/Tenants/AttendanceSetting.php` | GPS/자동 설정 |
| `app/Services/AttendanceService.php` | 서비스 (642줄) |
| `database/migrations/2025_12_09_*` | 테이블 생성 |

### 문서

| 파일 | 설명 |
|------|------|
| `docs/rules/attendance-api.md` | API 비즈니스 규칙 |
| `docs/system/erp-analysis/03-gps-attendance.md` | GPS 출퇴근 스펙 |
| `docs/system/erp-analysis/04-hr-management.md` | HR 시스템 분석 |

---

**최종 업데이트**: 2026-02-26
