docs: [approvals] 결재관리 시스템 문서 4종 작성

- README.md: 시스템 개요, 아키텍처, DB 스키마, 상태 관리, 권한 매트릭스
- workflows.md: 워크플로우 상세 (승인/반려/회수/보류/전결/복사재기안)
- api-reference.md: API 엔드포인트 20개 명세
- ui-screens.md: UI 화면 구성 및 인터랙션
- INDEX.md에 결재관리 문서 등록
This commit is contained in:
김보곤
2026-02-28 00:09:08 +09:00
parent 359dc5d029
commit 490477421d
5 changed files with 2085 additions and 130 deletions

View File

@@ -1,30 +1,27 @@
# SAM 프로젝트 문서 인덱스
> **Claude Code 작업 전 필수 확인** - 작업 유형에 맞는 문서를 먼저 읽고 시작하세요.
> **Claude Code 작업 전 필수 확인** 작업 유형에 맞는 문서를 먼저 읽고 시작하세요.
> **최종 갱신**: 2026-02-28
---
## 🎯 작업별 필수 문서 (반드시 먼저 확인)
## 🎯 작업별 필수 문서
| 작업 유형 | 필수 문서 | 용도 |
|----------|----------|------|
| **TODO 확인** | `TODO.md` | 긴급/중요 이슈 및 개선사항 추적 |
| **API 개발** | `standards/api-rules.md` | Service-First, FormRequest, i18n 규칙 |
| **DB 변경** | `specs/database-schema.md` | 테이블 구조, 관계, 컬럼 규칙 |
| **새 기능 구현** | `architecture/system-overview.md` | 전체 아키텍처 이해 |
| **보안 관련** | `architecture/security-policy.md` | 인증/인가, 보안 규칙 |
| **DB 변경** | `system/database/README.md` | 테이블 구조, 관계, 컬럼 규칙 |
| **새 기능 구현** | `system/overview.md` | 전체 아키텍처 이해 |
| **보안 관련** | `system/security-policy.md` | 인증/인가, 보안 규칙 |
| **Git 커밋** | `standards/git-conventions.md` | 커밋 메시지, 브랜치 전략 |
| **품질 검증** | `standards/quality-checklist.md` | 코드 품질 체크리스트 |
| **Swagger 작성** | `guides/swagger-guide.md` | API 문서 작성 방법 |
| **품목관리** | `rules/item-policy.md` | 품목 정책 (유형, 예약어, API 규칙) |
| **게시판** | `specs/board-system-spec.md` | 게시판 시스템 설계 |
| **단가관리** | `rules/pricing-policy.md` | 원가/판매가 계산, 리비전 관리 |
| **운영 배포** | `plans/production-deployment-plan.md` | 운영 환경 배포 계획 (CI/CD, 서버 아키텍처) |
| **서버 동작 원리** | `guides/server-how-it-works.md` | 요청 흐름, 배포 원리 이해 |
| **과금정책 (고객용)** | `rules/customer-pricing.md` | 고객 안내용 서비스 요금표 |
| **과금정책 (파트너)** | `rules/partner-commission.md` | 영업파트너 수당 체계 및 정산 |
| **과금정책 (내부용)** | `rules/billing-policy.md` | 내부용 원가/마진/코드참조 (CONFIDENTIAL) |
| **견적관리** | `features/quotes/README.md` | 견적 시스템, BOM 계산, 10단계 로직 |
| **결재관리** | `features/approvals/README.md` | 결재 시스템 (워크플로우, API, UI) |
| **운영 배포** | `plans/production-deployment-plan.md` | 운영 환경 배포 계획 |
| **서버 운영** | `deploys/ops-manual/README.md` | 서버 운영 매뉴얼 |
| **MES 개발** | `projects/mes/README.md` | MES 프로젝트 개요 |
---
@@ -33,27 +30,67 @@
```
docs/
├── plans/ # 🆕 개발 계획 - 임시 (작업 완료 후 정리 → 삭제)
├── standards/ # 개발 표준 - "어떻게 코드를 작성할 것인가"
├── architecture/ # 아키텍처 - "왜 이렇게 설계하는가"
├── rules/ # 비즈니스 규칙 - "무엇이 유효한 데이터인가"
├── specs/ # 기술 스펙 - "무엇을 구현할 것인가"
├── guides/ # 구현 가이드 - "어떻게 구현할 것인가"
├── quickstart/ # 빠른 시작 - 핵심 요약
├── front/ # 프론트엔드 공유 문서
├── features/ # 기능별 상세 문서
├── projects/ # 프로젝트별 문서 (MES, Legacy)
├── history/ # 히스토리 및 로드맵
├── contracts/ # 전자계약서 버전 관리
├── changes/ # 변경 이력
── data/ # 데이터 분석
├── system/ # 시스템 현황 — 아키텍처, DB 스키마, 인프라 (architecture/ + specs/ 통합)
├── standards/ # 개발 표준 "어떻게 코드를 작성할 것인가"
├── rules/ # 비즈니스 규칙 — "무엇이 유효한 데이터인가"
├── features/ # 기능별 상세 — 도메인별 기능 문서
├── guides/ # 구현 가이드 — "어떻게 구현할 것인가"
├── quickstart/ # 빠른 시작 — 핵심 요약, 명령어
├── plans/ # 작업 추적 — 예정 → 진행 → 완료 → archive/
├── projects/ # 프로젝트 자료 — 프로젝트성 분석, 설계, 참고
├── deploys/ # 운영 매뉴얼 — 서버 운영, 배포
├── changes/ # 변경 이력
├── data/ # 데이터 분석
├── history/ # 히스토리 기록
├── api/ # API 통합 문서
── requests/ # 요청/기획 문서
└── assets/ # BI 등 정적 자산
```
---
## 📚 폴더별 문서 목록
### standards/ - 개발 표준
### system/ — 시스템 현황
> 아키텍처, DB 스키마, 기술 스펙, 인프라 (기존 architecture/ + specs/ 통합)
| 문서 | 설명 |
|------|------|
| [overview.md](system/overview.md) | 전체 시스템 아키텍처 (api/react/mng 구조, 기술 스택) |
| [api-structure.md](system/api-structure.md) | API 서버 구조 (~1,027 엔드포인트, 18 도메인) |
| [react-structure.md](system/react-structure.md) | React 프론트엔드 구조 (249 페이지, 612 컴포넌트) |
| [mng-structure.md](system/mng-structure.md) | MNG 관리자 패널 구조 (171 컨트롤러, 436 뷰) |
| [docker-setup.md](system/docker-setup.md) | Docker 환경 + CI/CD (7 서비스, Jenkins) |
| [database/README.md](system/database/README.md) | DB 스키마 인덱스 (220 모델, 32 도메인, 459 마이그레이션) |
**DB 도메인별 스키마:**
| 문서 | 포함 도메인 |
|------|-----------|
| [database/tenants.md](system/database/tenants.md) | 테넌트, 사용자, 권한 (63 모델) |
| [database/products.md](system/database/products.md) | 제품, 품목, 설계 (21 모델) |
| [database/sales.md](system/database/sales.md) | 영업, 수주, 견적 (18 모델) |
| [database/production.md](system/database/production.md) | 생산, 시공, 자재, 품질 (20 모델) |
| [database/finance.md](system/database/finance.md) | 재무, 회계 |
| [database/hr.md](system/database/hr.md) | 인사, 면접 |
| [database/documents.md](system/database/documents.md) | 문서, 전자서명 (19 모델) |
| [database/commons.md](system/database/commons.md) | 공통, 게시판, 감사 (17 모델) |
| [database/stats.md](system/database/stats.md) | 통계 (21 모델, sam_stat DB) |
**이관 완료 (architecture/ + specs/ → system/):**
| 문서 | 설명 |
|------|------|
| [security-policy.md](system/security-policy.md) | 보안 정책 (다층 방어, Sanctum, RBAC) |
| [scaling-roadmap.md](system/scaling-roadmap.md) | 10K 테넌트 스케일링 로드맵 |
| [board-system-spec.md](system/board-system-spec.md) | 게시판 시스템 설계 스펙 |
| [item-master-integration.md](system/item-master-integration.md) | 품목 마스터 통합 설계 |
| [remote-work-setup.md](system/remote-work-setup.md) | 원격 개발 설정 (DEPRECATED) |
| [erp-analysis/](system/erp-analysis/) | ERP 스토리보드 분석 (9개 파일) |
---
### standards/ — 개발 표준
> 코딩 컨벤션, 스타일 가이드, 품질 기준
| 문서 | 설명 | 필수 확인 시점 |
@@ -61,40 +98,56 @@ docs/
| [api-rules.md](standards/api-rules.md) | API 개발 규칙 (Service-First, FormRequest, i18n) | API 개발 전 |
| [git-conventions.md](standards/git-conventions.md) | Git 커밋 메시지, 브랜치 전략 | 커밋 전 |
| [quality-checklist.md](standards/quality-checklist.md) | 코드 품질 체크리스트 | PR 전 |
| [pagination-policy.md](standards/pagination-policy.md) | 페이지네이션 표준 | 목록 API 구현 시 |
| [options-column-policy.md](standards/options-column-policy.md) | JSON options 컬럼 표준 정책 (마이그레이션, 모델, 쿼리) | 테이블 생성/확장 시 |
### architecture/ - 아키텍처 & 설계 원칙
> 시스템 설계, 보안 정책, 아키텍처 결정
---
| 문서 | 설명 | 필수 확인 시점 |
|------|------|--------------|
| [system-overview.md](architecture/system-overview.md) | 전체 시스템 아키텍처 | 새 기능 설계 전 |
| [security-policy.md](architecture/security-policy.md) | 인증/인가, 보안 규칙 | 보안 관련 작업 전 |
| [scaling-roadmap-10k-tenants.md](architecture/scaling-roadmap-10k-tenants.md) | 10,000 테넌트 스케일링 로드맵 | 확장 전략 검토 시 |
### rules/ - 비즈니스 규칙
> 도메인 로직, 검증 규칙, 상태 전이
### rules/ — 비즈니스 규칙
> 도메인 로직, 검증 규칙, 정책
| 문서 | 설명 | 필수 확인 시점 |
|------|------|--------------|
| [README.md](rules/README.md) | 비즈니스 규칙 개요 | 도메인 로직 구현 전 |
| [item-policy.md](rules/item-policy.md) | 품목 정책 (유형 체계, 예약어, API 규칙) | 품목 관련 작업 전 |
| [pricing-policy.md](rules/pricing-policy.md) | 단가 정책 (원가/판매가 계산, 리비전 관리) | 단가 관련 작업 전 |
| [item-policy.md](rules/item-policy.md) | 품목 정책 (유형, 예약어, API 규칙) | 품목 관련 작업 전 |
| [pricing-policy.md](rules/pricing-policy.md) | 단가 정책 (원가/판매가, 리비전) | 단가 관련 작업 전 |
| [customer-pricing.md](rules/customer-pricing.md) | 고객 안내용 서비스 요금표 | 고객 요금 안내 시 |
| [partner-commission.md](rules/partner-commission.md) | 영업파트너 수당 체계 및 정산 | 수당/정산 관련 작업 전 |
| [billing-policy.md](rules/billing-policy.md) | 내부용 원가/마진/코드참조 (CONFIDENTIAL) | 과금 코드 개발 전 |
| [client-policy.md](rules/client-policy.md) | 고객사 관리 정책 | 고객 관련 작업 전 |
| [attendance-api.md](rules/attendance-api.md) | 근태 API 규칙 | 근태 관련 작업 전 |
| [department-tree-api.md](rules/department-tree-api.md) | 부서 트리 API 규칙 | 부서 관련 작업 전 |
| [employee-api.md](rules/employee-api.md) | 직원 API 규칙 | 직원 관련 작업 전 |
| [numbering-rules.md](rules/numbering-rules.md) | 채번규칙 (패턴 기반 자동 번호 생성) | 채번 로직 수정 전 |
### specs/ - 기술 스펙
> 구현 명세, DB 스키마, 시스템 설정
---
| 문서 | 설명 | 필수 확인 시점 |
|------|------|--------------|
| [database-schema.md](specs/database-schema.md) | DB 구조 및 관계도 | DB 변경 전 |
| [board-system-spec.md](specs/board-system-spec.md) | 게시판 시스템 설계 | 게시판 작업 전 |
| [item-master-integration.md](specs/item-master-integration.md) | 품목관리 연동 설계 | 품목 연동 구현 시 |
| [docker-setup.md](specs/docker-setup.md) | Docker 환경 구성 | 환경 설정 시 |
| [remote-work-setup.md](specs/remote-work-setup.md) | 원격 개발 설정 | 원격 작업 시 |
### features/ — 기능별 문서
> 도메인별 기능 상세 (기능 설명 + 엔드포인트 경로 + Swagger 참조)
### guides/ - 구현 가이드
| 문서 | 설명 |
|------|------|
| [quotes/README.md](features/quotes/README.md) | 견적 시스템 (BOM 계산, 10단계 로직) |
| [boards/README.md](features/boards/README.md) | 게시판 시스템 구현 |
| [boards/mng-implementation.md](features/boards/mng-implementation.md) | MNG 게시판 구현 상세 |
| [hr/attendance-management-spec.md](features/hr/attendance-management-spec.md) | 근태관리 기획서 |
| [hr/hr-api-analysis.md](features/hr/hr-api-analysis.md) | HR API 분석 (근태/직원/부서) |
| [barobill-kakaotalk/README.md](features/barobill-kakaotalk/README.md) | 바로빌 카카오톡 + 세금계산서 연동 |
| ~~business-card-request.md~~ | 명함신청 관리 (DB 마이그레이션만 존재, 문서 미작성) |
| [sales/README.md](features/sales/README.md) | 영업 관리 (면접 시나리오 포함) |
| [crm/README.md](features/crm/README.md) | CRM (거래처, 미수금, 미지급금) |
| [finance/README.md](features/finance/README.md) | 재무 관리 (14개 하위 문서) |
| [card-vehicle/README.md](features/card-vehicle/README.md) | 법인카드·차량 관리 |
| [settlement/README.md](features/settlement/README.md) | 정산 관리 |
| [esign/README.md](features/esign/README.md) | 전자서명 (계약·OTP·PDF 합성) |
| [documents/README.md](features/documents/README.md) | 문서관리 (EAV 기반 서식·결재) |
| [ai/README.md](features/ai/README.md) | AI 분석 리포트 (Gemini 연동) |
| [equipment/README.md](features/equipment/README.md) | 설비관리 (MNG 전용) |
| [approvals/README.md](features/approvals/README.md) | 결재관리 시스템 (순차결재, 보류/전결/참조/복사재기안) |
---
### guides/ — 구현 가이드
> 특정 기능 구현을 위한 단계별 매뉴얼
| 문서 | 설명 | 필수 확인 시점 |
@@ -103,35 +156,75 @@ docs/
| [file-storage-guide.md](guides/file-storage-guide.md) | 파일 업로드/다운로드 구현 | 파일 기능 구현 전 |
| [item-management-migration.md](guides/item-management-migration.md) | Item 시스템 전환 가이드 | 마이그레이션 작업 전 |
| [project-launch-roadmap.md](guides/project-launch-roadmap.md) | 런칭 준비 현황 | 런칭 관련 작업 시 |
| [production-env-sync.md](guides/production-env-sync.md) | 운영 전환 시 .env 동기화 절차 | 테스트→운영 전환 시 |
| [server-how-it-works.md](guides/server-how-it-works.md) | 서버 인프라 시리즈 ① 서버 동작 원리 | 신규 합류 시 |
| [nginx-fastcgi-guide.md](guides/nginx-fastcgi-guide.md) | 서버 인프라 시리즈 ② Nginx & FastCGI | Nginx/FastCGI 개념 이해 시 |
| [php-fpm-guide.md](guides/php-fpm-guide.md) | 서버 인프라 시리즈 ③ PHP-FPM | PHP-FPM 개념 이해 시 |
| [jenkins-setup-guide.md](guides/jenkins-setup-guide.md) | Jenkins CI/CD 셋업 가이드 | Jenkins 설치/설정 시 |
| [production-env-sync.md](guides/production-env-sync.md) | 운영 전환 시 .env 동기화 | 테스트→운영 전환 시 |
| [server-how-it-works.md](guides/server-how-it-works.md) | 서버 동작 원리 | 신규 합류 시 |
| [nginx-fastcgi-guide.md](guides/nginx-fastcgi-guide.md) | Nginx & FastCGI 가이드 | 서버 이해 시 |
| [php-fpm-guide.md](guides/php-fpm-guide.md) | PHP-FPM 가이드 | 서버 이해 시 |
| [jenkins-setup-guide.md](guides/jenkins-setup-guide.md) | Jenkins CI/CD 셋업 | Jenkins 설치/설정 시 |
| [auto-login-guide.md](guides/auto-login-guide.md) | MNG→DEV 자동 로그인 | 자동 로그인 구현 시 |
| [erp-api-list.md](guides/erp-api-list.md) | ERP API 목록 (List vs Detail 구분) | 프론트 API 연동 시 |
| [erp-api-detail.md](guides/erp-api-detail.md) | ERP API 상세 스펙 | 프론트 API 연동 시 |
| [item-master-guide.md](guides/item-master-guide.md) | 품목기준관리 페이지-섹션-필드 구조 | 품목 UI 구현 시 |
| [item-master-items-api.md](guides/item-master-items-api.md) | ItemMaster & Items API 문서 | 품목 API 연동 시 |
### quickstart/ - 빠른 시작
---
### quickstart/ — 빠른 시작
> 핵심 규칙 요약, 자주 쓰는 명령어
| 문서 | 설명 | 필수 확인 시점 |
|------|------|--------------|
| [quick-start.md](quickstart/quick-start.md) | 프로젝트 핵심 규칙 요약 | 세션 시작 시 |
| [dev-commands.md](quickstart/dev-commands.md) | 일상 개발 명령어 모음 | 명령어 확인 시 |
### front/ - 프론트엔드 공유 문서
> API 연동 가이드, 프론트엔드 스펙
| 문서 | 설명 |
|------|------|
| [item-master-guide.md](front/item-master-guide.md) | 품목기준관리 페이지-섹션-필드 구조 |
| [quick-start.md](quickstart/quick-start.md) | 프로젝트 핵심 규칙 요약 |
| [dev-commands.md](quickstart/dev-commands.md) | 일상 개발 명령어 모음 |
> 날짜별 API 요청 문서는 `history/2025-11/front-requests/`로 이동됨
---
### data/ - 데이터 분석
> 시스템 분석, 데이터 모델링
### plans/ — 작업 추적
> 예정 → 진행 → 완료 → archive/ (이미 정리 완료, 현행 유지)
| 문서 | 설명 |
|------|------|
| [index_plans.md](plans/index_plans.md) | 계획 인덱스 (ACTIVE + PLANNED) |
| [GUIDE.md](plans/GUIDE.md) | 계획 문서 작성 가이드 |
---
### projects/ — 프로젝트 자료
> 프로젝트성 분석, 설계, 참고 자료 (지속 보관)
| 프로젝트 | 문서 | 설명 |
|---------|------|------|
| [index_projects.md](projects/index_projects.md) | 프로젝트 인덱스 | |
| **MES** | [README.md](projects/mes/README.md) | MES 프로젝트 개요 |
| **MES** | [MES_PROJECT_ROADMAP.md](projects/mes/MES_PROJECT_ROADMAP.md) | 개발 로드맵 |
| **5130 이관** | [MASTER_PLAN.md](projects/5130-migration/MASTER_PLAN.md) | 레거시 이관 마스터 플랜 |
| **API 연동** | [MASTER_PLAN.md](projects/api-integration/MASTER_PLAN.md) | React↔API 연동 |
| **Legacy** | [draw-module.md](projects/legacy-5130/draw-module.md) | 레거시 드로우 모듈 |
| **견적** | [quotation/](projects/quotation/) | 견적 프로젝트 자료 |
| **전자서명** | [e-sign/](projects/e-sign/) | 전자서명 프로젝트 자료 |
---
### deploys/ — 운영 매뉴얼
> 서버 운영, 배포 (현행 유지)
| 문서 | 설명 |
|------|------|
| [ops-manual/README.md](deploys/ops-manual/README.md) | 서버 운영 매뉴얼 (11부 구성) |
---
### changes/ — 변경 이력
> 파일명 형식: `YYYYMMDD_description.md`
---
### data/ — 데이터 분석
| 문서 | 설명 |
|------|------|
| [analysis/item-db-analysis.md](data/analysis/item-db-analysis.md) | Item DB/API 분석 최종본 |
| [analysis/bom-item-mapping-analysis.md](data/analysis/bom-item-mapping-analysis.md) | BOM-품목 매핑 분석 |
### contracts/ - 전자계약서 버전 관리
> DOCX 배포본 + Markdown 추적본 + 자동화 스크립트
@@ -157,13 +250,13 @@ docs/
| [production-deployment-plan.md](plans/production-deployment-plan.md) | 운영 환경 배포 계획 (CI/CD, 서버 아키텍처) |
| [attendance-management-plan.md](plans/attendance-management-plan.md) | 근태현황 개발 계획 (Phase 1~2, HTMX 기반) |
| [leave-management-plan.md](plans/leave-management-plan.md) | 휴가관리 모듈 개발 계획 (연차 발생/신청/승인/정책) |
| [approval-management-system-plan.md](plans/approval-management-system-plan.md) | 결재관리 시스템 기획서 (전자결재 전체 설계: 기안~회수, DB 설계, 17개 양식, 4 Phase) |
### features/ - 기능별 문서
| 문서 | 설명 |
|------|------|
| [barobill-kakaotalk/README.md](features/barobill-kakaotalk/README.md) | 바로빌 카카오톡 (알림톡/친구톡) 연동 |
| [barobill-kakaotalk/esign-notification-guide.md](features/barobill-kakaotalk/esign-notification-guide.md) | 전자계약 알림톡/SMS 환경별 설정 가이드 |
| [boards/README.md](features/boards/README.md) | 게시판 시스템 구현 |
| [boards/mng-implementation.md](features/boards/mng-implementation.md) | MNG 게시판 구현 상세 |
| [hr/attendance-management-spec.md](features/hr/attendance-management-spec.md) | 근태관리 기획서 (화면/데이터/비즈니스규칙/API) |
@@ -171,6 +264,10 @@ docs/
| [quotes/README.md](features/quotes/README.md) | 견적 시스템 분석 (BOM 계산, 10단계 로직) |
| [business-card-request.md](features/business-card-request.md) | 명함신청 관리 (3단계 워크플로우: 요청→제작의뢰→처리완료) |
| [academy/fire-shutter-image-prompts.md](features/academy/fire-shutter-image-prompts.md) | 방화셔터 백과사전 이미지 생성 프롬프트 (Gemini용) |
| [approvals/README.md](features/approvals/README.md) | 결재관리 시스템 개요 (아키텍처, DB, 상태관리, 권한) |
| [approvals/workflows.md](features/approvals/workflows.md) | 결재관리 워크플로우 상세 (승인/반려/회수/보류/전결/복사재기안) |
| [approvals/api-reference.md](features/approvals/api-reference.md) | 결재관리 API 명세 (20개 엔드포인트) |
| [approvals/ui-screens.md](features/approvals/ui-screens.md) | 결재관리 UI 화면 구성 (Blade + HTMX) |
### projects/ - 프로젝트별 문서
@@ -190,89 +287,112 @@ docs/
---
## 🏗️ 서브프로젝트 문서
### 서브프로젝트 문서
각 서브프로젝트는 독립적인 `docs/` 디렉토리를 가집니다.
| 프로젝트 | 문서 경로 | 설명 |
|---------|----------|------|
| **API** | [api/docs/INDEX.md](../api/docs/INDEX.md) | REST API 프로젝트 |
| **MNG** | [mng/docs/INDEX.md](../mng/docs/INDEX.md) | Plain Laravel 관리자 (운영 주력) |
| **API** | [api/docs/](../api/docs/) | REST API 프로젝트 |
| **MNG** | [mng/docs/](../mng/docs/) | Plain Laravel 관리자 |
| **React** | [react/docs/](../react/docs/) | Next.js 프론트엔드 |
---
## 📝 문서 작성 가이드
### 새 문서 작성 시
1. **적절한 폴더 선택**: 위 폴더 구조 참고
2. **파일명**: 소문자 + 하이픈 (kebab-case)
3. **크기 목표**: 10KB 이하
4. **INDEX 업데이트**: 새 문서는 반드시 이 파일에 추가
## 📝 문서 작성 규칙
### 폴더 선택 기준
- **"개발 계획/작업 예정"** → `plans/` (임시, 완료 후 삭제)
- **"어떻게 코드 작성?"** → `standards/`
- **"왜 이렇게 설계?"** → `architecture/`
- **"무엇이 유효한 데이터?"** → `rules/`
- **"무엇을 구현?"** → `specs/`
- **"어떻게 구현?"** → `guides/`
### plans/ 워크플로우
1. 개발 계획 문서를 `plans/`에 작성
2. 작업 진행
3. 완료 후 결과물을 해당 프로젝트 docs에 정리
4. plan 문서 삭제
| 질문 | 폴더 |
|------|------|
| "시스템이 현재 어떤 상태인가?" | `system/` |
| "어떻게 코드를 작성할 것인가?" | `standards/` |
| "무엇이 유효한 데이터인가?" | `rules/` |
| "이 기능은 어떻게 동작하는가?" | `features/` |
| "어떻게 구현할 것인가?" | `guides/` |
| "무슨 작업을 할 것인가?" | `plans/` |
| "프로젝트 자료를 보관하고 싶다" | `projects/` |
| "무엇이 변경되었는가?" | `changes/` |
### plans/flow-tests/
API Flow Tester에서 생성되는 JSON 파일 저장 경로
- 경로: `plans/flow-tests/*.json`
- 용도: MNG API Flow Tester 테스트 시나리오
- 예시: `item-master-page-api-flow.json`, `client-api-flow.json`
### 파일명 규칙
| 유형 | 규칙 | 예시 |
|------|------|------|
| 기술 문서 (코드 참조) | 영문 kebab-case | `api-rules.md`, `database-schema.md` |
| 업무/비즈니스 문서 | 한글 허용 | `영업파트너가이드북.md`, `수당지급.md` |
| 변경 이력 | `YYYYMMDD_description.md` | `20260205_sus_inspection_template.md` |
| 폴더 인덱스 | `README.md` (대문자) | `features/finance/README.md` |
| **혼용 금지** | 한글+영문 섞지 않음 | ❌ `영업partner가이드.md` |
### 크기 제한
- **목표**: 10KB 이하
- 초과 시 도메인별로 분할
### 문서 구조 템플릿
#### 정책/규칙 문서 (`rules/`, `standards/`)
```markdown
# 제목
> **작성일**: YYYY-MM-DD
> **상태**: 설계 확정
---
## 🔄 문서 구조 변경 이력
## 1. 개요
## 2. 핵심 원칙
## 3. 상세 규칙
## 4. API 엔드포인트 (해당 시)
## 관련 문서
- **2026-01-28**: API 라우터 분리 및 버전 폴백 시스템 구현
- `routes/api.php` → 13개 도메인별 파일로 분리 (1,479줄 → 61줄)
- `ApiVersionMiddleware` 추가 (헤더/쿼리 기반 버전 선택, v2→v1 폴백)
- `standards/api-rules.md` 라우팅 섹션 업데이트
- `architecture/system-overview.md` 라우팅 구조 업데이트
---
- **2025-12-09**: 품목 정책 통합 문서 생성
- `rules/item-policy.md` 생성 (4개 문서 통합)
- 삭제: `specs/ITEM-MASTER-INDEX.md`, `specs/item-master-field-key-validation.md`, `specs/item-master-field-integration.md`, `plans/items-api-unified-plan.md`
- 품목 관련 정책을 rules/ 디렉토리로 이동
**최종 업데이트**: YYYY-MM-DD
```
- **2025-12-09**: Item Master 문서 정리 및 인덱스 생성
- `specs/ITEM-MASTER-INDEX.md` 생성 (개발 현황/필요 항목 정리)
- `history/2025-11/item-master-archived/` 생성 (구버전 문서 아카이브)
- 중복 문서 정리 (front-requests → history 이동)
#### 변경 이력 문서 (`changes/`)
- **2025-12-09**: 문서 정리 및 통합
- 중복 분석 문서 삭제 (v2, DB_Modeling)
- `SAM_Item_DB_API_Analysis_v3_FINAL.md``item-db-analysis.md` 리네임
- `ITEM_MASTER_FIELD_INTEGRATION_PLAN.md``item-master-field-integration.md` 리네임
- `HR_API_ANALYSIS.md``features/hr/hr-api-analysis.md` 이동
- 날짜 접두사 front 문서 → `history/2025-11/front-requests/` 이동
- api/docs에서 프로젝트 문서 분리 (swagger, api-flows만 유지)
```markdown
# 변경 내용 요약
- **2025-12-09**: api/docs 문서 통합
- `api/docs/analysis/``docs/data/analysis/` 이동
- `api/docs/front/``docs/front/` 병합
- `api/docs/specs/``docs/specs/` 병합
- api/docs에는 API 구성/설정 문서만 유지 (swagger, api-flows)
**날짜:** YYYY-MM-DD
- **2025-12-09**: `plans/` 폴더 추가
- 개발 계획 문서용 임시 폴더
- 작업 완료 후 정리 → 삭제 워크플로우
## 변경 개요
## 수정된 파일
## 상세 변경 사항
## 테스트 체크리스트
```
- **2025-12-05**: 폴더 구조 대폭 재정리
- `reference/``standards/`, `architecture/`, `quickstart/`로 분리
- `principles/``architecture/`로 통합
- 작업별 필수 문서 가이드 추가
### 작성 스타일
- **2025-11-20**: 문서 구조 대규모 재정리
- claudedocs → docs/ 체계화
- 각 서브프로젝트별 docs/ 디렉토리 생성
| 항목 | 규칙 |
|------|------|
| **언어** | 한글 기본, 코드/경로/기술 식별자만 영어 |
| **어조** | 서술형 ("X 한다") |
| **경고** | `> **경고: ...**` 블록인용 |
| **금지/필수** | `❌` 금지, `✅` 필수 |
| **우선순위** | `🔴 필수`, `🟡 중요`, `🟢 권장` |
| **코드 블록** | 반드시 언어 지정 (```php, ```bash 등) |
| **인라인 코드** | 파일 경로, 메서드명, 변수명에 백틱 |
| **구분선** | `---` 주요 섹션 사이 |
### 새 문서 작성 시 체크리스트
- [ ] 적절한 폴더에 배치
- [ ] 파일명 규칙 준수
- [ ] 문서 구조 템플릿 준수
- [ ] 이 INDEX.md에 등록
---
## 🔄 문서 정비 진행 현황
> 참조: [docs-comprehensive-update-plan.md](plans/docs-comprehensive-update-plan.md)
| Phase | 작업 | 상태 |
|-------|------|------|
| **Phase 0** | 문서 정책 재정립 | ✅ 완료 |
| **Phase 1** | 시스템 현황 문서화 (DB, API, React, MNG, Docker) | ✅ 완료 (14개 문서) |
| **Phase 2** | 기존 문서 정비 (architecture/+specs/ → system/ 이관) | ⏳ 대기 |
| **Phase 3** | 신규 도메인 기능 문서 작성 | ⏳ 대기 |
| **Phase 4** | 최종 검증 및 INDEX 갱신 | ⏳ 대기 |

View File

@@ -0,0 +1,295 @@
# 결재관리 시스템
> **작성일**: 2026-02-28
> **상태**: Phase 2 구현 완료
> **프로젝트**: SAM MNG (관리자 웹)
> **우선순위**: 🔴 필수
---
## 1. 개요
### 1.1 목적
SAM MNG 전자결재 시스템. 기안부터 최종 승인, 반려, 회수, 보류, 전결, 참조까지 기업 결재 프로세스를 디지털화한다.
### 1.2 문서 구조
| 문서 | 설명 |
|------|------|
| **README.md** (이 문서) | 시스템 전체 개요, 아키텍처, 상태 관리 |
| [workflows.md](workflows.md) | 상세 워크플로우 (승인/반려/회수/보류/전결/복사재기안) |
| [api-reference.md](api-reference.md) | API 엔드포인트 명세 |
| [ui-screens.md](ui-screens.md) | 화면별 UI 구성 및 동작 |
### 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. 관련 문서
- [결재관리 워크플로우 상세](workflows.md) — 각 동작의 상세 흐름
- [API 명세](api-reference.md) — 엔드포인트 목록 및 요청/응답 예시
- [UI 화면 구성](ui-screens.md) — 화면별 UI 요소 및 동작
- [기획서 원본](../../plans/approval-management-system-plan.md) — Phase 1~4 전체 기획
---
**최종 업데이트**: 2026-02-28

View File

@@ -0,0 +1,594 @@
# 결재관리 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

View File

@@ -0,0 +1,381 @@
# 결재관리 UI 화면 구성
> **작성일**: 2026-02-28
> **상태**: Phase 2 구현 완료
> **기술**: Blade + HTMX + Alpine.js + Tailwind CSS
> **관련**: [README.md](README.md) | [워크플로우](workflows.md) | [API 명세](api-reference.md)
---
## 1. 개요
결재관리 화면은 MNG(관리자 웹)에서 Blade 템플릿으로 구현되며, API 호출은 `fetch()`를 사용한다.
### 1.1 파일 구조
```
resources/views/approvals/
├── drafts.blade.php ← 기안함 (목록)
├── pending.blade.php ← 결재 대기함 (목록)
├── completed.blade.php ← 처리 완료함 (목록)
├── references.blade.php ← 참조함 (목록)
├── create.blade.php ← 기안 작성
├── edit.blade.php ← 기안 수정
├── show.blade.php ← 상세 조회 + 결재 처리
└── partials/
├── _status-badge.blade.php ← 상태 뱃지 컴포넌트
└── _step-progress.blade.php ← 결재 단계 진행 표시
```
---
## 2. 목록 화면
### 2.1 기안함 (`/approval-mgmt/drafts`)
내가 기안한 모든 문서를 표시한다.
**UI 구성:**
```
┌──────────────────────────────────────────────────────────┐
│ 기안함 [+ 새 기안] │
├──────────────────────────────────────────────────────────┤
│ [검색] [상태 필터 ▼] [긴급만 □] [날짜 범위] │
├──────────────────────────────────────────────────────────┤
│ 문서번호 │ 제목 │ 양식 │ 상태 │ 기안일 │
│ APR-260228-001│ 휴가 신청 │ 휴가서 │ 🟢완료 │ 02-28 │
│ APR-260228-002│ 출장 보고 │ 출장서 │ 🔵진행 │ 02-28 │
│ APR-260227-001│ 경비 청구 │ 경비서 │ ⬜임시 │ 02-27 │
├──────────────────────────────────────────────────────────┤
│ [◀ 이전] 1 / 3 [다음 ▶] │
└──────────────────────────────────────────────────────────┘
```
**상태 필터:** 전체, 임시저장, 진행, 완료, 반려, 회수, 보류
---
### 2.2 결재 대기함 (`/approval-mgmt/pending`)
내가 현재 결재해야 할 문서를 표시한다.
**UI 구성:**
```
┌──────────────────────────────────────────────────────────┐
│ 결재 대기함 [뱃지: 3건] │
├──────────────────────────────────────────────────────────┤
│ 문서번호 │ 제목 │ 기안자 │ 양식 │ 상신일 │
│ 🔴 APR-260..│ 긴급 승인 │ 홍길동 │ 구매서 │ 02-28 │
│ APR-260..│ 휴가 신청 │ 김영희 │ 휴가서 │ 02-27 │
└──────────────────────────────────────────────────────────┘
```
> 긴급 문서는 🔴 아이콘과 함께 상단에 표시
---
### 2.3 참조함 (`/approval-mgmt/references`)
내가 참조자로 지정된 문서를 표시한다.
**UI 구성:**
```
┌──────────────────────────────────────────────────────────┐
│ 참조함 │
├──────────────────────────────────────────────────────────┤
│ [전체] [미열람 (5)] [열람완료] │
├──────────────────────────────────────────────────────────┤
│ 문서번호 │ 제목 │ 기안자 │ 상태 │ 열람 │
│ APR-260228-001│ 회의록 │ 박부장 │ 🟢완료 │ ❌미열람│
│ APR-260227-003│ 인사발령 │ 이팀장 │ 🔵진행 │ ✅열람 │
└──────────────────────────────────────────────────────────┘
```
**열람 추적:**
- 문서 클릭 시 `mark-read` API가 자동 호출된다
- 미열람/열람완료 탭으로 필터링 가능
- 미열람 건수가 뱃지로 표시된다
---
## 3. 상세 화면 (`/approval-mgmt/{id}`)
### 3.1 전체 레이아웃
```
┌──────────────────────────────────────────────────────────┐
│ 결재 상세 [수정] [목록으로] │
│ APR-260228-001 │
├──────────────────────────────────────────────────────────┤
│ │
│ 상태: [🔵 진행] [🔴 긴급] │
│ 양식: 휴가신청서 기안자: 홍길동 │
│ 기안일: 2026-02-28 10:05 완료일: - │
│ 원본 문서: APR-260225-003 (재기안 시 표시) │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 회수 사유 (cancelled 상태에서만) │ │
│ │ 내용 수정이 필요하여 회수합니다. │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ 제목: 2월 연차 사용 신청 │
│ 본문: 2월 27일~28일 연차 사용합니다... │
│ │
├──────────────────────────────────────────────────────────┤
│ │
│ 결재 진행 │
│ ┌────────────────────────────────────────────────┐ │
│ │ [결재 단계 프로그레스 바] │ │
│ │ ✓김과장(승인) → ●박부장(대기) → ③이사(대기) │ │
│ └────────────────────────────────────────────────┘ │
│ │
│ 결재 의견 │
│ ┌────────────────────────────────────────────────┐ │
│ │ ✓ 김과장 2026-02-28 11:00 │ │
│ │ 승인합니다. │ │
│ └────────────────────────────────────────────────┘ │
│ │
├──────────────────────────────────────────────────────────┤
│ │
│ 결재 처리 (현재 결재자에게만 표시) │
│ [결재 의견 textarea] │
│ [승인] [반려] [보류] [전결] │
│ │
├──────────────────────────────────────────────────────────┤
│ 보류 해제 (on_hold + 보류한 본인에게만) │
│ [보류 해제] │
├──────────────────────────────────────────────────────────┤
│ 회수 (기안자 + pending/on_hold) │
│ [회수 사유 textarea] │
│ [결재 회수] │
├──────────────────────────────────────────────────────────┤
│ 복사 재기안 (기안자 + approved/rejected/cancelled) │
│ [복사하여 재기안] │
└──────────────────────────────────────────────────────────┘
```
### 3.2 조건부 섹션 표시
| 섹션 | 표시 조건 |
|------|----------|
| **수정 버튼** | 기안자 + `draft`/`rejected` |
| **회수 사유** | `cancelled` + `recall_reason` 존재 |
| **원본 문서 링크** | `parent_doc_id` 존재 (재기안 문서) |
| **결재 처리** | `pending` + 현재 결재자 |
| **보류 해제** | `on_hold` + 보류한 본인 |
| **회수** | 기안자 + `pending`/`on_hold` |
| **복사 재기안** | 기안자 + `approved`/`rejected`/`cancelled` |
---
## 4. 파셜 컴포넌트
### 4.1 상태 뱃지 (`_status-badge.blade.php`)
문서 상태를 색상 뱃지로 표시한다.
| 상태 | 라벨 | 스타일 |
|------|------|--------|
| `draft` | 임시저장 | `bg-gray-100 text-gray-700` |
| `pending` | 진행 | `bg-blue-100 text-blue-700` |
| `approved` | 완료 | `bg-green-100 text-green-700` |
| `rejected` | 반려 | `bg-red-100 text-red-700` |
| `cancelled` | 회수 | `bg-yellow-100 text-yellow-700` |
| `on_hold` | 보류 | `bg-amber-100 text-amber-700` |
---
### 4.2 결재 단계 프로그레스 (`_step-progress.blade.php`)
결재선의 각 단계를 가로 프로그레스 바로 표시한다.
**단계 아이콘:**
| 상태 | 아이콘 | 배경색 | 텍스트색 |
|------|--------|--------|---------|
| `approved` (normal) | ✓ | `bg-green-500` | white |
| `approved` (pre_decided) | ⚡ | `bg-indigo-500` | white |
| `rejected` | ✗ | `bg-red-500` | white |
| `on_hold` | ⏸ | `bg-amber-400` | white |
| `skipped` | — | `bg-gray-300` | gray |
| `pending` (현재 차례) | 번호 | `bg-blue-500` | white |
| `pending` (대기) | 번호 | `bg-gray-200` | gray |
**레이아웃:**
```
┌──────────────────────────────────────────────────────┐
│ │
│ ✓ ──── ⚡ ──── — ──── — ──── ● ──── 3 │
│ 김과장 박부장 이사장 팀장 최대리 참조자 │
│ 경영팀 경영팀 대표실 개발팀 개발팀 인사팀 │
│ (승인) (전결) (건너뜀)(건너뜀)(대기) (참조) │
│ │
└──────────────────────────────────────────────────────┘
```
**특수 표시:**
- **전결** step: ⚡ 아이콘 + "전결" 라벨 (남색)
- **보류** step: ⏸ 아이콘 + "보류" 라벨 (노란색)
- **건너뜀** step: 이름에 취소선 (line-through)
- **참조** step: 별도 구분 없이 동일 프로그레스 바에 표시
- **연결선**: 단계 사이 가로선 (`border-t-2`)
---
## 5. 결재 처리 인터랙션
### 5.1 승인
```
[승인 버튼 클릭]
→ confirm("승인하시겠습니까?")
→ POST /api/admin/approvals/{id}/approve
body: { comment: "의견 텍스트" }
→ 성공 시: 토스트("승인되었습니다") + 페이지 리로드
```
### 5.2 반려
```
[반려 버튼 클릭]
→ comment 빈 값 체크 → 경고 토스트("반려 시 사유를 입력해주세요")
→ confirm("반려하시겠습니까?")
→ POST /api/admin/approvals/{id}/reject
body: { comment: "사유" }
→ 성공 시: 토스트("반려되었습니다") + 페이지 리로드
```
### 5.3 보류
```
[보류 버튼 클릭]
→ comment 빈 값 체크 → 경고 토스트("보류 사유를 입력해주세요")
→ confirm("이 결재를 보류하시겠습니까?")
→ POST /api/admin/approvals/{id}/hold
body: { comment: "사유" }
→ 성공 시: 토스트("보류되었습니다") + 페이지 리로드
```
### 5.4 전결
```
[전결 버튼 클릭]
→ confirm("전결 처리하시겠습니까?\n이후 모든 결재를 건너뛰고 문서를 최종 승인합니다.")
→ POST /api/admin/approvals/{id}/pre-decide
body: { comment: "의견(선택)" }
→ 성공 시: 토스트("전결 처리되었습니다") + 페이지 리로드
```
### 5.5 보류 해제
```
[보류 해제 버튼 클릭]
→ confirm("보류를 해제하시겠습니까?")
→ POST /api/admin/approvals/{id}/release-hold
→ 성공 시: 토스트("보류가 해제되었습니다") + 페이지 리로드
```
### 5.6 회수
```
[결재 회수 버튼 클릭]
→ confirm("결재를 회수하시겠습니까? 이 작업은 되돌릴 수 없습니다.")
→ POST /api/admin/approvals/{id}/cancel
body: { recall_reason: "사유(선택)" }
→ 성공 시: 토스트("결재가 회수되었습니다") + 페이지 리로드
```
### 5.7 복사 재기안
```
[복사하여 재기안 버튼 클릭]
→ confirm("이 문서를 복사하여 새 결재를 작성하시겠습니까?")
→ POST /api/admin/approvals/{id}/copy
→ 성공 시: 토스트("문서가 복사되었습니다")
→ /approval-mgmt/{newId}/edit로 이동
```
---
## 6. 결재 의견 표시
상세 페이지에서 결재 의견이 있는 step을 카드 형태로 표시한다.
```
┌──────────────────────────────────────┐
│ ✓ 김과장 2026-02-28 11:00 │
│ 승인합니다. │
├──────────────────────────────────────┤
│ ⚡ 박부장 (전결) 2026-02-28 14:00 │
│ 전결 처리합니다. │
├──────────────────────────────────────┤
│ ⏸ 이사장 (보류) 2026-02-28 15:00 │
│ 추가 자료 검토 필요 │
├──────────────────────────────────────┤
│ ✗ 팀장 2026-02-28 16:00 │
│ 예산 초과로 반려합니다. │
└──────────────────────────────────────┘
```
**아이콘 색상:**
- ✓ 승인: 녹색 (`bg-green-100 text-green-600`)
- ⚡ 전결: 남색 (`bg-indigo-100 text-indigo-600`)
- ⏸ 보류: 노란색 (`bg-amber-100 text-amber-600`)
- ✗ 반려: 적색 (`bg-red-100 text-red-600`)
---
## 7. 참조함 열람 추적 UI
### 7.1 탭 필터
```
[전체] [미열람 (5)] [열람완료]
```
- 탭 클릭 시 `is_read` 파라미터로 API 재호출
- 미열람 탭에 건수 뱃지 표시
### 7.2 열람 상태 표시
| 상태 | 표시 |
|------|------|
| 미열람 | `bg-red-100 text-red-700` "미열람" |
| 열람완료 | `bg-green-100 text-green-700` "열람완료" |
### 7.3 자동 열람 처리
문서 행 클릭 시:
1. `mark-read` API 호출 (비동기)
2. 상세 페이지로 이동
---
## 8. 버튼 스타일 가이드
| 버튼 | 색상 | Tailwind 클래스 |
|------|------|----------------|
| 승인 | 녹색 | `bg-green-600 hover:bg-green-700` |
| 반려 | 적색 | `bg-red-600 hover:bg-red-700` |
| 보류 | 노란색 | `bg-amber-500 hover:bg-amber-600` |
| 전결 | 남색 | `bg-indigo-600 hover:bg-indigo-700` |
| 보류 해제 | 노란색 | `bg-amber-500 hover:bg-amber-600` |
| 회수 | 노란색 | `bg-yellow-500 hover:bg-yellow-600` |
| 복사 재기안 | 회색 | `bg-gray-600 hover:bg-gray-700` |
| 수정 | 회색 | `bg-gray-600 hover:bg-gray-700` |
---
## 관련 문서
- [README.md](README.md) — 시스템 전체 개요
- [워크플로우 상세](workflows.md) — 각 동작의 상세 흐름
- [API 명세](api-reference.md) — 엔드포인트별 요청/응답
---
**최종 업데이트**: 2026-02-28

View File

@@ -0,0 +1,565 @@
# 결재관리 워크플로우 상세
> **작성일**: 2026-02-28
> **상태**: Phase 2 구현 완료
> **관련**: [README.md](README.md) | [API 명세](api-reference.md) | [UI 화면](ui-screens.md)
---
## 1. 개요
이 문서는 결재관리 시스템의 각 동작(Action)에 대한 상세 워크플로우를 정의한다.
모든 워크플로우는 `ApprovalService`에서 트랜잭션으로 처리된다.
### 1.1 용어 정의
| 용어 | 설명 |
|------|------|
| **기안자** | 결재 문서를 작성한 사람 (`drafter_id`) |
| **현재 결재자** | 결재선에서 현재 차례인 사람 (가장 작은 `step_order``pending` step) |
| **결재자** | `step_type``approval` 또는 `agreement`인 참여자 |
| **참조자** | `step_type``reference`인 참여자 (의사결정 권한 없음) |
| **전결** | 현재 결재자가 이후 모든 결재를 건너뛰고 즉시 최종 승인 |
---
## 2. 기안 작성 (createApproval)
### 2.1 흐름
```
사용자 → [양식 선택] → [제목/본문 입력] → [결재선 설정] → [임시저장]
새 Approval 생성
status = 'draft'
current_step = 0
```
### 2.2 조건
- 모든 로그인 사용자가 작성 가능
- `form_id` 필수 (양식 선택)
- 결재선(steps)은 저장 시 선택사항 (상신 시 필수)
### 2.3 처리 로직
1. 문서번호 자동 채번 (`APR-YYMMDD-001` 형식)
2. `numbering_sequences` 테이블로 일일 순번 관리
3. 결재선 설정 시 `approval_steps` 저장 + 사용자 정보 스냅샷 (이름, 부서, 직급)
4. `status = 'draft'`, `current_step = 0`
---
## 3. 상신 (submit)
### 3.1 흐름
```
기안자 → [상신 버튼] → 유효성 검사 → 결재선 검사 → 상신 완료
status = 'pending'
current_step = 1
drafted_at = now()
```
### 3.2 조건
| 조건 | 설명 |
|------|------|
| 문서 상태 | `draft` 또는 `rejected` |
| 결재선 | 결재/합의 step 1명 이상 필수 |
| 요청자 | 기안자만 |
### 3.3 처리 로직
1. `isSubmittable()` 검증 → `draft` 또는 `rejected`인지 확인
2. 결재/합의 step 존재 확인
3. **반려 후 재상신인 경우**: 모든 step을 `pending`으로 초기화 (comment, acted_at도 초기화)
4. `status → pending`, `drafted_at → now()`, `current_step → 1`
### 3.4 반려 후 재상신
```
rejected 문서
├── 기안자가 내용 수정 (updateApproval)
└── 상신 (submit)
├── 모든 steps → pending (초기화)
├── status → pending
└── current_step → 1 (처음부터 다시)
```
> 반려 후 재상신 시 결재선이 초기화되므로, 이전 결재 의견(comment)은 사라진다.
---
## 4. 승인 (approve)
### 4.1 흐름
```
현재 결재자 → [의견 입력(선택)] → [승인 버튼]
┌──────────┴──────────┐
│ 현재 step │
│ status → 'approved' │
│ comment → (입력값) │
│ acted_at → now() │
└──────────┬──────────┘
┌─────────────────┴─────────────────┐
│ │
다음 pending step 있음 마지막 결재자
│ │
current_step 갱신 status → 'approved'
(다음 순서 결재자 대기) completed_at → now()
```
### 4.2 조건
| 조건 | 설명 |
|------|------|
| 문서 상태 | `pending` |
| 요청자 | 현재 차례 결재자 (`approver_id === auth()->id()`) |
### 4.3 처리 로직
1. `isActionable()` 검증 → `pending` 상태인지 확인
2. `getCurrentApproverStep()` → 현재 차례 step 조회
3. 현재 step → `approved` + comment + acted_at
4. 다음 pending 결재/합의 step 조회
- **있으면**: `current_step` 갱신
- **없으면**: 문서 `approved` + `completed_at`
### 4.4 순차결재 순서 결정
```
step_order = 1 (결재) → step_order = 2 (합의) → step_order = 3 (결재)
│ │ │
1번째 승인 → 2번째 승인 → 3번째 승인 → 문서 완료
```
> 결재와 합의는 동일한 순차 흐름을 따른다. `step_order` 순서대로 처리된다.
---
## 5. 반려 (reject)
### 5.1 흐름
```
현재 결재자 → [반려 사유 입력(필수)] → [반려 버튼]
┌──────────┴──────────┐
│ 현재 step │
│ status → 'rejected' │
│ comment → (사유) │
│ acted_at → now() │
└──────────┬──────────┘
문서 status → 'rejected'
completed_at → now()
```
### 5.2 조건
| 조건 | 설명 |
|------|------|
| 문서 상태 | `pending` |
| 요청자 | 현재 차례 결재자 |
| 반려 사유 | **필수** (빈 값 불가) |
### 5.3 처리 로직
1. `isActionable()` 검증
2. 현재 결재자 확인
3. 반려 사유 빈 값 체크
4. 현재 step → `rejected` + comment + acted_at
5. 문서 → `rejected` + completed_at
### 5.4 반려 후 가능한 동작
```
rejected 문서
├── 기안자가 수정 → 재상신 (submit)
│ └── 결재선 초기화, 처음부터 다시 진행
└── 기안자가 복사 재기안 (copyForRedraft)
└── 새 문서 생성 (draft), 원본은 그대로 유지
```
---
## 6. 회수 (cancel)
### 6.1 흐름
```
기안자 → [회수 사유 입력(선택)] → [회수 버튼]
┌──────────┴──────────┐
│ 회수 가능 여부 판단 │
│ (첫 결재자 미처리?) │
└──────────┬──────────┘
┌───────────┴───────────┐
│ │
첫 결재자 첫 결재자 이미
pending/on_hold 승인/반려
│ │
회수 진행 회수 불가
│ (에러 반환)
모든 pending/on_hold steps → 'skipped'
문서 status → 'cancelled'
recall_reason → (입력값)
completed_at → now()
```
### 6.2 조건
| 조건 | 설명 |
|------|------|
| 문서 상태 | `pending` 또는 `on_hold` |
| 요청자 | 기안자만 (`drafter_id === auth()->id()`) |
| 첫 결재자 상태 | `pending` 또는 `on_hold` (이미 처리했으면 불가) |
### 6.3 회수 가능 판단 로직
```php
// 1단계: 문서 상태 확인
$approval->isCancellable() // pending 또는 on_hold
// 2단계: 기안자 확인
$approval->drafter_id === auth()->id()
// 3단계: 첫 결재자 상태 확인
$firstStep = steps.approvalOnly().orderBy('step_order').first()
$firstStep->status === 'pending' || 'on_hold' // 미처리 상태여야 함
```
### 6.4 처리 로직
1. `isCancellable()` 검증 → `pending` 또는 `on_hold`
2. 기안자 확인
3. 첫 번째 결재/합의 step의 상태 확인 → `pending`/`on_hold`이 아니면 거부
4. 모든 `pending`/`on_hold` steps → `skipped`
5. 문서 → `cancelled` + `recall_reason` + `completed_at`
---
## 7. 보류 (hold)
### 7.1 흐름
```
현재 결재자 → [보류 사유 입력(필수)] → [보류 버튼]
┌──────────┴──────────┐
│ 현재 step │
│ status → 'on_hold' │
│ comment → (사유) │
│ acted_at → now() │
└──────────┬──────────┘
문서 status → 'on_hold'
```
### 7.2 조건
| 조건 | 설명 |
|------|------|
| 문서 상태 | `pending` (`isHoldable()`) |
| 요청자 | 현재 차례 결재자 |
| 보류 사유 | **필수** (빈 값 불가) |
### 7.3 처리 로직
1. `isHoldable()` 검증 → `pending` 상태인지 확인
2. `getCurrentApproverStep()` → 현재 차례 step 조회
3. 현재 결재자 확인 (`approver_id === auth()->id()`)
4. 보류 사유 빈 값 체크
5. 현재 step → `on_hold` + comment + acted_at
6. 문서 → `on_hold`
### 7.4 보류 상태의 영향
```
on_hold 상태에서:
├── 다른 결재자는 아무 동작 불가 (결재 흐름 중단)
├── 기안자는 회수 가능 (첫 결재자가 미처리 상태이면)
└── 보류한 결재자만 보류 해제 가능
```
---
## 8. 보류 해제 (releaseHold)
### 8.1 흐름
```
보류한 결재자 → [보류 해제 버튼]
┌──────────┴──────────┐
│ on_hold step │
│ status → 'pending' │
│ comment → null │
│ acted_at → null │
└──────────┬──────────┘
문서 status → 'pending'
(결재 흐름 재개)
```
### 8.2 조건
| 조건 | 설명 |
|------|------|
| 문서 상태 | `on_hold` (`isHoldReleasable()`) |
| 요청자 | 보류한 본인만 (`on_hold` step의 `approver_id === auth()->id()`) |
### 8.3 처리 로직
1. `isHoldReleasable()` 검증 → `on_hold` 상태인지 확인
2. `on_hold` 상태인 step 조회
3. 해당 step의 `approver_id`가 현재 사용자인지 확인
4. step → `pending` + comment/acted_at 초기화
5. 문서 → `pending`
---
## 9. 전결 (preDecide)
### 9.1 흐름
```
현재 결재자 → [의견 입력(선택)] → [전결 버튼] → 확인 팝업
┌──────────┴──────────┐
│ 현재 step │
│ status → 'approved' │
│ approval_type → │
│ 'pre_decided' │
│ comment → (입력값) │
│ acted_at → now() │
└──────────┬──────────┘
이후 모든 pending
approval/agreement steps
→ status = 'skipped'
문서 status → 'approved'
completed_at → now()
```
### 9.2 조건
| 조건 | 설명 |
|------|------|
| 문서 상태 | `pending` (`isActionable()`) |
| 요청자 | 현재 차례 결재자 |
### 9.3 처리 로직
1. `isActionable()` 검증
2. `getCurrentApproverStep()` → 현재 차례 step 조회
3. 현재 결재자 확인
4. 현재 step → `approved` + `approval_type = 'pre_decided'` + comment + acted_at
5. 이후 모든 pending 결재/합의 steps → `skipped`
6. 문서 → `approved` + `completed_at`
### 9.4 전결 예시
```
step_order=1 (이사장, 결재) → approved (normal)
step_order=2 (부장, 결재) → approved (pre_decided) ← 여기서 전결
step_order=3 (과장, 합의) → skipped (전결로 건너뜀)
step_order=4 (팀장, 결재) → skipped (전결로 건너뜀)
step_order=5 (참조자, 참조) → (참조는 영향 없음, 그대로 유지)
문서 → approved, completed_at = now()
```
> 전결은 결재/합의 step만 건너뛴다. 참조 step은 영향받지 않는다.
---
## 10. 복사 재기안 (copyForRedraft)
### 10.1 흐름
```
기안자 → [복사하여 재기안 버튼]
┌─────────────────────────────┐
│ 원본 문서에서 복사 │
│ ├── form_id │
│ ├── title │
│ ├── content (양식 데이터) │
│ ├── body │
│ ├── is_urgent │
│ ├── department_id │
│ └── 결재선 (모두 pending) │
└─────────────┬───────────────┘
새 문서 생성 (status = 'draft')
parent_doc_id = 원본.id
새 문서번호 채번
수정 페이지로 이동
(/approval-mgmt/{newId}/edit)
```
### 10.2 조건
| 조건 | 설명 |
|------|------|
| 원본 문서 상태 | `approved`, `rejected`, `cancelled` (`isCopyable()`) |
| 요청자 | 기안자만 (`drafter_id === auth()->id()`) |
### 10.3 처리 로직
1. `isCopyable()` 검증 → `approved`/`rejected`/`cancelled` 중 하나
2. 기안자 확인
3. 새 문서 생성:
- 새 문서번호 채번
- 원본의 양식, 제목, 내용, 본문, 긴급 여부, 부서 복사
- `parent_doc_id = 원본.id`
- `status = 'draft'`, `current_step = 0`
4. 결재선 복사: 원본의 모든 steps를 새 문서에 복사 (모두 `pending` 상태)
5. 새 문서의 edit 페이지로 리다이렉트
### 10.4 원본과의 관계
```
원본 문서 (approved/rejected/cancelled)
└── parent_doc_id로 연결
새 문서 (draft)
├── 상세 페이지에서 "원본 문서" 링크 표시
└── 기안자가 내용 수정 후 상신 가능
```
---
## 11. 참조 열람 추적 (markAsRead)
### 11.1 흐름
```
참조자 → [참조함 목록에서 문서 클릭]
├── markAsRead API 호출
│ ├── is_read → true
│ └── read_at → now()
└── 상세 페이지로 이동
```
### 11.2 조건
| 조건 | 설명 |
|------|------|
| 요청자 | 해당 문서의 참조자 (`step_type = 'reference'`) |
### 11.3 처리 로직
1. 현재 사용자의 참조 step 조회
2. `is_read = false`인 step → `is_read = true`, `read_at = now()`
3. 이미 열람한 경우 중복 업데이트 없음 (`where('is_read', false)`)
---
## 12. 전체 상태 전이 요약
```
┌───────────────────────────────────────────────────────────────────┐
│ │
│ draft ──submit()──→ pending ──approve()──→ (다음 step 또는) │
│ ▲ │ │ approved │
│ │ │ │ │
│ │ │ ├──reject()──→ rejected │
│ │ │ │ │ │
│ │ │ │ ├── 수정 → submit() │
│ │ │ │ │ (재상신, draft X) │
│ │ │ │ │ │
│ │ │ │ └── copyForRedraft() │
│ │ │ │ → 새 draft 생성 │
│ │ │ │ │
│ │ │ ├──hold()──→ on_hold │
│ │ │ │ │ │
│ │ │ │ ├── releaseHold() │
│ │ │ │ │ → pending 복원 │
│ │ │ │ │ │
│ │ │ │ └── cancel() (기안자) │
│ │ │ │ → cancelled │
│ │ │ │ │
│ │ │ ├──preDecide()──→ approved │
│ │ │ │ (이후 steps → skipped) │
│ │ │ │ │
│ │ │ └──cancel()──→ cancelled │
│ │ │ (기안자, 첫결재자 미처리 시) │
│ │ │ │ │
│ │ │ └── copyForRedraft() │
│ │ │ → 새 draft 생성 │
│ │ │ │
│ │ └── approved ──copyForRedraft() │
│ │ → 새 draft 생성 │
│ │ │
│ └── updateApproval() (draft/rejected 상태에서 수정) │
│ │
└───────────────────────────────────────────────────────────────────┘
```
---
## 13. 에러 케이스 정리
| 동작 | 에러 조건 | 에러 메시지 |
|------|----------|------------|
| submit | 상태가 draft/rejected 아님 | "상신할 수 없는 상태입니다." |
| submit | 결재선 없음 | "결재선을 설정해주세요." |
| approve | 상태가 pending 아님 | "승인할 수 없는 상태입니다." |
| approve | 현재 결재자 아님 | "현재 결재자가 아닙니다." |
| reject | 상태가 pending 아님 | "반려할 수 없는 상태입니다." |
| reject | 사유 미입력 | "반려 사유를 입력해주세요." |
| cancel | 상태가 pending/on_hold 아님 | "회수할 수 없는 상태입니다." |
| cancel | 기안자 아님 | "기안자만 회수할 수 있습니다." |
| cancel | 첫 결재자 이미 처리 | "첫 번째 결재자가 이미 처리하여 회수할 수 없습니다." |
| hold | 상태가 pending 아님 | "보류할 수 없는 상태입니다." |
| hold | 현재 결재자 아님 | "현재 결재자가 아닙니다." |
| hold | 사유 미입력 | "보류 사유를 입력해주세요." |
| releaseHold | 상태가 on_hold 아님 | "보류 해제할 수 없는 상태입니다." |
| releaseHold | 보류한 본인 아님 | "보류한 결재자만 해제할 수 있습니다." |
| preDecide | 상태가 pending 아님 | "전결할 수 없는 상태입니다." |
| preDecide | 현재 결재자 아님 | "현재 결재자가 아닙니다." |
| copyForRedraft | 상태가 approved/rejected/cancelled 아님 | "복사할 수 없는 상태입니다." |
| copyForRedraft | 기안자 아님 | "기안자만 복사할 수 있습니다." |
| update | 상태가 draft/rejected 아님 | "수정할 수 없는 상태입니다." |
| delete | 상태가 draft 아님 | "삭제할 수 없는 상태입니다." |
---
## 관련 문서
- [README.md](README.md) — 시스템 전체 개요
- [API 명세](api-reference.md) — 엔드포인트별 요청/응답
- [UI 화면 구성](ui-screens.md) — 화면별 동작
---
**최종 업데이트**: 2026-02-28