# 결재관리 API 명세 > **작성일**: 2026-02-28 > **상태**: Phase 2 구현 완료 > **Base URL**: `/api/admin/approvals` > **미들웨어**: `web`, `auth`, `hq.member` > **관련**: [README.md](README.md) | [워크플로우](workflows.md) | [UI 화면](ui-screens.md) --- ## 1. 개요 모든 API는 JSON 응답을 반환한다. 인증은 세션 기반이며, CSRF 토큰이 필요하다. ### 1.1 공통 응답 형식 **성공:** ```json { "success": true, "message": "처리 메시지", "data": { ... } } ``` **실패 (400):** ```json { "success": false, "message": "에러 메시지" } ``` ### 1.2 공통 헤더 ``` Content-Type: application/json Accept: application/json X-CSRF-TOKEN: {csrf_token} ``` --- ## 2. 목록 조회 API ### 2.1 기안함 내가 기안한 문서 목록을 조회한다. ``` GET /api/admin/approvals/drafts ``` **Query Parameters:** | 파라미터 | 타입 | 설명 | |---------|------|------| | `search` | string | 제목/문서번호 검색 | | `status` | string | 상태 필터 (`draft`, `pending`, `approved`, `rejected`, `cancelled`, `on_hold`) | | `is_urgent` | boolean | 긴급 문서만 | | `date_from` | date | 시작일 (YYYY-MM-DD) | | `date_to` | date | 종료일 (YYYY-MM-DD) | | `per_page` | int | 페이지당 건수 (기본 15) | | `page` | int | 페이지 번호 | **응답:** Laravel 페이지네이션 형식 ```json { "data": [ { "id": 1, "document_number": "APR-260228-001", "title": "휴가 신청", "status": "pending", "is_urgent": false, "form": { "id": 1, "name": "휴가신청서" }, "steps": [...], "created_at": "2026-02-28T10:00:00", "drafted_at": "2026-02-28T10:05:00" } ], "current_page": 1, "last_page": 3, "per_page": 15, "total": 42 } ``` --- ### 2.2 결재 대기함 내가 현재 결재해야 할 문서 목록을 조회한다. ``` GET /api/admin/approvals/pending ``` **Query Parameters:** | 파라미터 | 타입 | 설명 | |---------|------|------| | `search` | string | 제목/문서번호 검색 | | `is_urgent` | boolean | 긴급 문서만 | | `date_from` | date | 시작일 | | `date_to` | date | 종료일 | | `per_page` | int | 페이지당 건수 | > 현재 사용자가 결재 차례인 문서만 표시된다. 이미 승인/반려한 문서는 표시되지 않는다. --- ### 2.3 처리 완료함 내가 승인 또는 반려한 문서 목록을 조회한다. ``` GET /api/admin/approvals/completed ``` **Query Parameters:** | 파라미터 | 타입 | 설명 | |---------|------|------| | `search` | string | 제목/문서번호 검색 | | `status` | string | 상태 필터 | | `date_from` | date | 시작일 | | `date_to` | date | 종료일 | | `per_page` | int | 페이지당 건수 | --- ### 2.4 참조함 내가 참조자로 지정된 문서 목록을 조회한다. ``` GET /api/admin/approvals/references ``` **Query Parameters:** | 파라미터 | 타입 | 설명 | |---------|------|------| | `search` | string | 제목/문서번호 검색 | | `is_read` | string | 열람 상태 필터 (`true`=열람완료, `false`=미열람) | | `date_from` | date | 시작일 | | `date_to` | date | 종료일 | | `per_page` | int | 페이지당 건수 | --- ## 3. CRUD API ### 3.1 상세 조회 ``` GET /api/admin/approvals/{id} ``` **응답:** ```json { "success": true, "data": { "id": 1, "tenant_id": 1, "document_number": "APR-260228-001", "form_id": 1, "line_id": null, "title": "휴가 신청", "content": {}, "body": "2월 27일~28일 연차 사용 신청합니다.", "status": "pending", "is_urgent": false, "drafter_id": 10, "department_id": 3, "current_step": 2, "drafted_at": "2026-02-28T10:05:00", "completed_at": null, "recall_reason": null, "parent_doc_id": null, "form": { "id": 1, "name": "휴가신청서" }, "drafter": { "id": 10, "name": "홍길동" }, "line": null, "steps": [ { "id": 1, "step_order": 1, "step_type": "approval", "approver_id": 20, "approver_name": "김과장", "approver_department": "경영지원팀", "approver_position": "과장", "status": "approved", "approval_type": "normal", "comment": "승인합니다.", "acted_at": "2026-02-28T11:00:00", "is_read": false, "read_at": null }, { "id": 2, "step_order": 2, "step_type": "approval", "approver_id": 30, "approver_name": "박부장", "approver_department": "경영지원팀", "approver_position": "부장", "status": "pending", "approval_type": "normal", "comment": null, "acted_at": null, "is_read": false, "read_at": null } ] } } ``` --- ### 3.2 생성 (임시저장) ``` POST /api/admin/approvals ``` **Request Body:** ```json { "form_id": 1, "title": "휴가 신청", "body": "2월 27일~28일 연차 사용", "is_urgent": false, "steps": [ { "user_id": 20, "step_type": "approval" }, { "user_id": 30, "step_type": "approval" }, { "user_id": 40, "step_type": "reference" } ] } ``` **Validation:** | 필드 | 규칙 | |------|------| | `form_id` | required, exists:approval_forms,id | | `title` | required, string, max:200 | | `body` | nullable, string | | `is_urgent` | boolean | | `steps` | nullable, array | | `steps.*.user_id` | required_with:steps, exists:users,id | | `steps.*.step_type` | required_with:steps, in:approval,agreement,reference | **응답 (201):** ```json { "success": true, "message": "결재 문서가 저장되었습니다.", "data": { ... } } ``` --- ### 3.3 수정 ``` PUT /api/admin/approvals/{id} ``` > `draft` 또는 `rejected` 상태에서만 수정 가능 **Request Body:** (생성과 동일, 모든 필드 선택) **Validation:** | 필드 | 규칙 | |------|------| | `title` | sometimes, string, max:200 | | `body` | nullable, string | | `is_urgent` | boolean | | `steps` | nullable, array | --- ### 3.4 삭제 ``` DELETE /api/admin/approvals/{id} ``` > `draft` 상태에서만 삭제 가능 **응답:** ```json { "success": true, "message": "결재 문서가 삭제되었습니다." } ``` --- ## 4. 워크플로우 API ### 4.1 상신 ``` POST /api/admin/approvals/{id}/submit ``` > 기안자가 `draft`/`rejected` 문서를 결재 요청한다. **Request Body:** 없음 **응답:** `{ "success": true, "message": "결재가 상신되었습니다.", "data": {...} }` --- ### 4.2 승인 ``` POST /api/admin/approvals/{id}/approve ``` > 현재 결재자가 승인한다. **Request Body:** ```json { "comment": "승인합니다." // 선택 } ``` **응답:** `{ "success": true, "message": "승인되었습니다.", "data": {...} }` --- ### 4.3 반려 ``` POST /api/admin/approvals/{id}/reject ``` > 현재 결재자가 반려한다. 사유 필수. **Request Body:** ```json { "comment": "예산 초과로 반려합니다." // 필수 } ``` **Validation:** `comment` — required, string, max:1000 **응답:** `{ "success": true, "message": "반려되었습니다.", "data": {...} }` --- ### 4.4 회수 ``` POST /api/admin/approvals/{id}/cancel ``` > 기안자가 `pending`/`on_hold` 문서를 회수한다. 첫 결재자 미처리 시에만 가능. **Request Body:** ```json { "recall_reason": "내용 수정 필요" // 선택 } ``` **응답:** `{ "success": true, "message": "결재가 회수되었습니다.", "data": {...} }` --- ### 4.5 보류 ``` POST /api/admin/approvals/{id}/hold ``` > 현재 결재자가 결재를 보류한다. 사유 필수. **Request Body:** ```json { "comment": "추가 자료 검토 필요" // 필수 } ``` **Validation:** `comment` — required, string, max:1000 **응답:** `{ "success": true, "message": "보류되었습니다.", "data": {...} }` --- ### 4.6 보류 해제 ``` POST /api/admin/approvals/{id}/release-hold ``` > 보류한 결재자가 보류를 해제한다. **Request Body:** 없음 **응답:** `{ "success": true, "message": "보류가 해제되었습니다.", "data": {...} }` --- ### 4.7 전결 ``` POST /api/admin/approvals/{id}/pre-decide ``` > 현재 결재자가 이후 모든 결재를 건너뛰고 최종 승인한다. **Request Body:** ```json { "comment": "전결 처리합니다." // 선택 } ``` **응답:** `{ "success": true, "message": "전결 처리되었습니다.", "data": {...} }` --- ### 4.8 복사 재기안 ``` POST /api/admin/approvals/{id}/copy ``` > 기안자가 `approved`/`rejected`/`cancelled` 문서를 복사하여 새 draft를 생성한다. **Request Body:** 없음 **응답:** ```json { "success": true, "message": "문서가 복사되었습니다.", "data": { "id": 15, "document_number": "APR-260228-003", "parent_doc_id": 1, "status": "draft", ... } } ``` > 응답의 `data.id`를 사용하여 `/approval-mgmt/{id}/edit`로 이동한다. --- ### 4.9 참조 열람 추적 ``` POST /api/admin/approvals/{id}/mark-read ``` > 참조자가 문서를 열람했음을 기록한다. **Request Body:** 없음 **응답:** `{ "success": true, "message": "열람 처리되었습니다." }` --- ## 5. 유틸리티 API ### 5.1 결재선 템플릿 목록 ``` GET /api/admin/approvals/lines ``` **응답:** ```json { "success": true, "data": [ { "id": 1, "name": "일반 결재선", "steps": [...] } ] } ``` --- ### 5.2 양식 목록 ``` GET /api/admin/approvals/forms ``` **응답:** ```json { "success": true, "data": [ { "id": 1, "name": "휴가신청서", "is_active": true } ] } ``` --- ### 5.3 미처리 건수 (뱃지) ``` GET /api/admin/approvals/badge-counts ``` **응답:** ```json { "success": true, "data": { "pending": 3, "draft": 1, "reference_unread": 5 } } ``` | 필드 | 설명 | |------|------| | `pending` | 내가 결재해야 할 문서 수 | | `draft` | 내 임시저장 문서 수 | | `reference_unread` | 미열람 참조 문서 수 | --- ## 6. 라우트 전체 목록 | Method | Path | 컨트롤러 메서드 | 이름 | 설명 | |--------|------|---------------|------|------| | GET | `/drafts` | `drafts` | `drafts` | 기안함 | | GET | `/pending` | `pending` | `pending` | 결재 대기함 | | GET | `/completed` | `completed` | `completed` | 처리 완료함 | | GET | `/references` | `references` | `references` | 참조함 | | GET | `/lines` | `lines` | `lines` | 결재선 템플릿 | | GET | `/forms` | `forms` | `forms` | 양식 목록 | | GET | `/badge-counts` | `badgeCounts` | `badge-counts` | 뱃지 건수 | | POST | `/` | `store` | `store` | 생성 | | GET | `/{id}` | `show` | `show` | 상세 | | PUT | `/{id}` | `update` | `update` | 수정 | | DELETE | `/{id}` | `destroy` | `destroy` | 삭제 | | POST | `/{id}/submit` | `submit` | `submit` | 상신 | | POST | `/{id}/approve` | `approve` | `approve` | 승인 | | POST | `/{id}/reject` | `reject` | `reject` | 반려 | | POST | `/{id}/cancel` | `cancel` | `cancel` | 회수 | | POST | `/{id}/hold` | `hold` | `hold` | 보류 | | POST | `/{id}/release-hold` | `releaseHold` | `release-hold` | 보류 해제 | | POST | `/{id}/pre-decide` | `preDecide` | `pre-decide` | 전결 | | POST | `/{id}/copy` | `copyForRedraft` | `copy` | 복사 재기안 | | POST | `/{id}/mark-read` | `markAsRead` | `mark-read` | 열람 추적 | --- ## 관련 문서 - [README.md](README.md) — 시스템 전체 개요 - [워크플로우 상세](workflows.md) — 각 동작의 상세 흐름 - [UI 화면 구성](ui-screens.md) — 화면별 동작 --- **최종 업데이트**: 2026-02-28