# 결재관리 시스템

> **작성일**: 2026-02-28
> **상태**: Phase 2 구현 완료
> **프로젝트**: SAM MNG (관리자 웹)
> **우선순위**: 🔴 필수

---

## 1. 개요

### 1.1 목적

SAM MNG 전자결재 시스템. 기안부터 최종 승인, 반려, 회수, 보류, 전결, 참조까지 기업 결재 프로세스를 디지털화한다.

### 1.2 문서 구조

| 문서 | 설명 |
|------|------|
| **README.md** (이 문서) | 시스템 전체 개요, 아키텍처, 상태 관리 |
| [form-types.md](form-types.md) | 양식별 필드/JSON 구조/인터랙션 기술 명세 |
| [workflows.md](workflows.md) | 상세 워크플로우 (승인/반려/회수/보류/전결/복사재기안) |
| [api-reference.md](api-reference.md) | API 엔드포인트 명세 |
| [ui-screens.md](ui-screens.md) | 화면별 UI 구성 및 동작 |
| [db-changes-and-model-sync.md](db-changes-and-model-sync.md) | DB 변경사항 및 API/MNG 모델 동기화 현황 |
| [mng-api-comparison.md](mng-api-comparison.md) | MNG↔API 비교 분석 및 React 구현 가이드 |

### 1.3 구현 현황

| Phase | 범위 | 상태 |
|-------|------|------|
| **Phase 1** | 순차결재, 기안/상신/승인/반려/회수 | ✅ 완료 |
| **Phase 2** | 보류/해제, 전결, 참조 열람 추적, 복사 재기안 | ✅ 완료 |
| **Phase 3** | 병렬결재, 위임(대결), 알림 | 미착수 |
| **Phase 4** | ERP 연동, 결재 통계, 관리자 설정 | 미착수 |

---

## 2. 아키텍처

### 2.1 기술 스택

| 계층 | 기술 | 설명 |
|------|------|------|
| 뷰 | Blade + HTMX + Alpine.js | 동적 UI, 부분 렌더링 |
| API | Laravel Controller + Service | JSON API (내부용) |
| 모델 | Eloquent ORM | Multi-tenant 스코프 |
| DB | MySQL 8.0 | API 프로젝트에서 마이그레이션 관리 |

### 2.2 프로젝트 분리

```
API (/home/aweso/sam/api)
├── database/migrations/    ← 모든 결재 테이블 마이그레이션

MNG (/home/aweso/sam/mng)
├── app/Models/Approvals/   ← 모델 (Approval, ApprovalStep, ApprovalForm, ApprovalLine, ApprovalDelegation)
├── app/Services/           ← ApprovalService (비즈니스 로직)
├── app/Http/Controllers/   ← ApprovalController (웹), ApprovalApiController (API)
├── resources/views/approvals/ ← Blade 뷰
└── routes/                 ← 웹 라우트 + API 라우트
```

### 2.3 핵심 클래스

```
ApprovalService
├── 목록 조회: getMyDrafts(), getPendingForMe(), getCompletedByMe(), getReferencesForMe()
├── CRUD: createApproval(), updateApproval(), deleteApproval(), getApproval()
├── 워크플로우: submit(), approve(), reject(), cancel(), hold(), releaseHold(), preDecide(), copyForRedraft()
├── 참조: markAsRead()
└── 유틸: getBadgeCounts(), getApprovalLines(), getApprovalForms(), saveApprovalSteps()
```

---

## 3. 데이터베이스

### 3.1 테이블 관계

```
approval_forms (결재 양식)
    │ 1:N
    ▼
approvals (결재 문서)
    │ 1:N                      │ N:1 (self)
    ▼                          ▼
approval_steps (결재 단계)     approvals (parent_doc_id → 원본 문서)

approval_lines (결재선 템플릿) ← approvals.line_id 참조

approval_delegations (위임 설정) ← Phase 3 준비
```

### 3.2 approvals (결재 문서)

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `id` | BIGINT PK | |
| `tenant_id` | BIGINT | 테넌트 격리 |
| `document_number` | VARCHAR | `APR-YYMMDD-001` 형식 |
| `form_id` | BIGINT FK | 양식 |
| `line_id` | BIGINT FK NULL | 결재선 템플릿 |
| `title` | VARCHAR(200) | 제목 |
| `content` | JSON | 양식 필드 데이터 |
| `body` | TEXT NULL | 본문 |
| `status` | VARCHAR(20) | 문서 상태 (6가지) |
| `is_urgent` | BOOLEAN | 긴급 여부 |
| `drafter_id` | BIGINT FK | 기안자 |
| `department_id` | BIGINT FK NULL | 기안 부서 |
| `current_step` | INT | 현재 결재 단계 번호 |
| `drafted_at` | TIMESTAMP NULL | 상신 일시 |
| `completed_at` | TIMESTAMP NULL | 완료 일시 |
| `recall_reason` | TEXT NULL | 회수 사유 |
| `parent_doc_id` | BIGINT FK NULL | 재기안 원본 문서 |
| `attachments` | JSON NULL | 첨부파일 |

### 3.3 approval_steps (결재 단계)

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `id` | BIGINT PK | |
| `approval_id` | BIGINT FK | 결재 문서 |
| `step_order` | INT | 순서 (1, 2, 3...) |
| `step_type` | VARCHAR | `approval`, `agreement`, `reference` |
| `parallel_group` | INT NULL | 병렬 그룹 (Phase 3) |
| `approver_id` | BIGINT FK | 결재자 |
| `acted_by` | BIGINT FK NULL | 실제 처리자 (대결 시) |
| `approver_name` | VARCHAR | 결재자명 스냅샷 |
| `approver_department` | VARCHAR | 부서 스냅샷 |
| `approver_position` | VARCHAR | 직급 스냅샷 |
| `status` | VARCHAR(20) | 단계 상태 (5가지) |
| `approval_type` | VARCHAR(20) | `normal`, `pre_decided`, `delegated` |
| `comment` | TEXT NULL | 결재 의견 |
| `acted_at` | TIMESTAMP NULL | 처리 일시 |
| `is_read` | BOOLEAN | 참조 열람 여부 |
| `read_at` | TIMESTAMP NULL | 열람 일시 |

### 3.4 approval_delegations (위임 설정, Phase 3)

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `id` | BIGINT PK | |
| `tenant_id` | BIGINT FK | |
| `delegator_id` | BIGINT FK | 위임자 |
| `delegate_id` | BIGINT FK | 대리인 |
| `start_date` | DATE | 위임 시작일 |
| `end_date` | DATE | 위임 종료일 |
| `form_ids` | JSON NULL | 대상 양식 (NULL=전체) |
| `notify_delegator` | BOOLEAN | 대결 시 보고 여부 |
| `is_active` | BOOLEAN | 활성 여부 |
| `reason` | VARCHAR(200) | 위임 사유 |

---

## 4. 상태 관리

### 4.1 문서 상태 (6가지)

| 상태 | 코드 | 라벨 | 색상 | 설명 |
|------|------|------|------|------|
| 임시저장 | `draft` | 임시저장 | gray | 작성 중, 미상신 |
| 진행 | `pending` | 진행 | blue | 결재선 순환 중 |
| 완료 | `approved` | 완료 | green | 최종 승인 |
| 반려 | `rejected` | 반려 | red | 결재자가 반려 |
| 회수 | `cancelled` | 회수 | yellow | 기안자가 회수 |
| 보류 | `on_hold` | 보류 | amber | 결재자가 보류 |

### 4.2 단계 상태 (5가지)

| 상태 | 코드 | 라벨 | 아이콘 | 설명 |
|------|------|------|--------|------|
| 대기 | `pending` | 대기 | 숫자 | 차례 아직 아님 |
| 승인 | `approved` | 승인 | ✓ (녹색) | 승인 완료 |
| 반려 | `rejected` | 반려 | ✗ (적색) | 반려 |
| 건너뜀 | `skipped` | 건너뜀 | — (회색) | 전결/회수로 소멸 |
| 보류 | `on_hold` | 보류 | ⏸ (노란) | 보류 중 |

### 4.3 결재 유형 (approval_type)

| 유형 | 코드 | 아이콘 | 설명 |
|------|------|--------|------|
| 일반결재 | `normal` | ✓ | 기본 승인 |
| 전결 | `pre_decided` | ⚡ (남색) | 이후 단계 모두 건너뛰고 즉시 완료 |
| 대결 | `delegated` | — | 대리인이 처리 (Phase 3) |

### 4.4 참여자 역할 (step_type)

| 역할 | 코드 | 의사결정 | 설명 |
|------|------|---------|------|
| 결재 | `approval` | ✅ 있음 | 승인/반려/보류/전결 가능 |
| 합의 | `agreement` | ✅ 있음 | 타부서 동의 (승인/반려 가능) |
| 참조 | `reference` | ❌ 없음 | 열람만 가능, 열람 추적 |

### 4.5 상태 전이 다이어그램

```
                         ┌─────────────────────────────┐
                         │                             │
 ┌────────┐   submit()  │  ┌─────────┐                │
 │ draft  │────────────→│  │ pending │                │
 └────────┘              │  └────┬────┘                │
     ▲                   │       │                     │
     │                   │  ┌────┼─────────┬───────┐   │
     │ (수정 후 재상신)    │  │    │         │       │   │
     │                   │  │ approve() reject() hold()│
     │                   │  │    │         │       │   │
     │                   │  │    ▼         ▼       ▼   │
     │                   │  │ 다음 step  rejected on_hold│
     │                   │  │  또는       │       │   │
     │                   │  │ approved    │  releaseHold()
     │                   │  │    │        │       │   │
     │                   │  │    │        │       │   │
     │                   │  └────┼────────┼───────┘   │
     │                   │       │        │           │
     │                   │  preDecide()   │           │
     │                   │    → approved  │           │
     │                   │       │        │  cancel() │
     │                   │       │        │     │     │
     │                   │       ▼        │     ▼     │
     │                   │  ┌─────────┐   │ ┌──────────┐
     │                   │  │approved │   │ │cancelled │
     │                   │  └─────────┘   │ └──────────┘
     │                   │       │        │      │
     │                   │       │        │      │
     │                   │  copyForRedraft()     │
     │                   │       │        │      │
     └───────────────────┼───────┴────────┘      │
          (새 draft 생성) │                       │
                         │  copyForRedraft()      │
                         │◀──────────────────────┘
                         └─────────────────────────────┘
```

---

## 5. 권한 매트릭스

### 5.1 누가 무엇을 할 수 있는가

| 액션 | 대상자 | 조건 |
|------|--------|------|
| **기안 작성** | 모든 사용자 | — |
| **수정** | 기안자 | `draft` 또는 `rejected` |
| **삭제** | 기안자 | `draft`만 |
| **상신** | 기안자 | `draft` 또는 `rejected`, 결재선 1명 이상 |
| **승인** | 현재 결재자 | `pending`, 자신이 현재 차례 |
| **반려** | 현재 결재자 | `pending`, 사유 필수 |
| **보류** | 현재 결재자 | `pending`, 사유 필수 |
| **보류 해제** | 보류한 결재자 | `on_hold`, 자신이 보류한 건 |
| **전결** | 현재 결재자 | `pending`, 이후 모든 단계 건너뜀 |
| **회수** | 기안자 | `pending` 또는 `on_hold`, 첫 결재자 미처리 |
| **복사 재기안** | 기안자 | `approved`, `rejected`, `cancelled` |
| **참조 열람** | 참조자 | `reference` step 보유 |

### 5.2 회수 가능 조건 상세

```
회수(cancel) 가능 여부 판단:

1. 문서 상태가 pending 또는 on_hold인가? → 아니면 불가
2. 요청자가 기안자(drafter_id)인가? → 아니면 불가
3. 첫 번째 결재자(approval/agreement)의 상태가 pending 또는 on_hold인가?
   → 이미 approved/rejected이면 불가 (첫 결재자가 이미 처리)
```

---

## 6. 메뉴 구조

```
결재관리
├── 기안함          /approval-mgmt/drafts       ← 내가 기안한 문서
├── 결재 대기함     /approval-mgmt/pending      ← 내가 결재해야 할 문서
├── 처리 완료함     /approval-mgmt/completed    ← 내가 결재한 문서
└── 참조함          /approval-mgmt/references   ← 참조 문서 (열람 추적)
```

### 추가 페이지

| URL | 설명 |
|-----|------|
| `/approval-mgmt/create` | 기안 작성 |
| `/approval-mgmt/{id}` | 상세 조회 |
| `/approval-mgmt/{id}/edit` | 기안 수정 |

---

## 7. 관련 문서

- [결재 양식 기술 명세](form-types.md) — 양식별 필드, JSON 구조, 인터랙션
- [결재관리 워크플로우 상세](workflows.md) — 각 동작의 상세 흐름
- [API 명세](api-reference.md) — 엔드포인트 목록 및 요청/응답 예시
- [UI 화면 구성](ui-screens.md) — 화면별 UI 요소 및 동작
- [기획서 원본](../../plans/approval-management-system-plan.md) — Phase 1~4 전체 기획

---

**최종 업데이트**: 2026-03-06
