- README.md: 시스템 개요, 아키텍처, DB 스키마, 상태 관리, 권한 매트릭스 - workflows.md: 워크플로우 상세 (승인/반려/회수/보류/전결/복사재기안) - api-reference.md: API 엔드포인트 20개 명세 - ui-screens.md: UI 화면 구성 및 인터랙션 - INDEX.md에 결재관리 문서 등록
595 lines
11 KiB
Markdown
595 lines
11 KiB
Markdown
# 결재관리 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
|