- Deleted the following files as they are no longer relevant to the current project structure: - 결재 시스템 구현 현황 - 결재 시스템 v2 사용 가이드 - WACE 시스템 문제점 분석 및 개선 계획 - Agent Pipeline 한계점 분석 - AI 기반 화면 자동 생성 시스템 설계서 - WACE ERP Backend - 분석 문서 인덱스 These deletions help streamline the documentation and remove obsolete information, ensuring that only current and relevant resources are maintained.
11 KiB
11 KiB
결재 시스템 v2 사용 가이드
개요
결재 시스템 v2는 기존 순차결재(escalation) 외에 다양한 결재 방식을 지원합니다.
| 결재 유형 | 코드 | 설명 |
|---|---|---|
| 순차결재 (기본) | escalation |
결재선 순서대로 한 명씩 처리 |
| 전결 (자기결재) | self |
상신자 본인이 직접 승인 (결재자 불필요) |
| 합의결재 | consensus |
같은 단계에 여러 결재자 → 전원 승인 필요 |
| 후결 | post |
먼저 실행 후 나중에 결재 (결재 전 상태에서도 업무 진행) |
추가 기능:
- 대결 위임: 부재 시 다른 사용자에게 결재 위임
- 통보 단계: 결재선에 통보만 하는 단계 (자동 승인 처리)
- 긴급도:
normal/urgent/critical - 혼합형 결재선: 한 결재선에 결재/합의/통보 단계를 자유롭게 조합
DB 스키마 변경사항
마이그레이션 적용
# 개발 DB에 마이그레이션 적용
psql -h 39.117.244.52 -p 11132 -U postgres -d plm -f db/migrations/1051_approval_system_v2.sql
psql -h 39.117.244.52 -p 11132 -U postgres -d plm -f db/migrations/1052_rename_proxy_id_to_id.sql
변경된 테이블
approval_requests (추가 컬럼)
| 컬럼 | 타입 | 기본값 | 설명 |
|---|---|---|---|
| approval_type | VARCHAR(20) | 'escalation' | self/escalation/consensus/post |
| is_post_approved | BOOLEAN | FALSE | 후결 처리 완료 여부 |
| post_approved_at | TIMESTAMPTZ | NULL | 후결 처리 시각 |
| urgency | VARCHAR(20) | 'normal' | normal/urgent/critical |
approval_lines (추가 컬럼)
| 컬럼 | 타입 | 기본값 | 설명 |
|---|---|---|---|
| step_type | VARCHAR(20) | 'approval' | approval/consensus/notification |
| proxy_for | VARCHAR(50) | NULL | 대결 시 원래 결재자 ID |
| proxy_reason | TEXT | NULL | 대결 사유 |
| is_required | BOOLEAN | TRUE | 필수 결재 여부 |
approval_proxy_settings (신규)
| 컬럼 | 타입 | 설명 |
|---|---|---|
| id | SERIAL PK | |
| company_code | VARCHAR(20) NOT NULL | |
| original_user_id | VARCHAR(50) | 원래 결재자 |
| proxy_user_id | VARCHAR(50) | 대결자 |
| start_date | DATE | 위임 시작일 |
| end_date | DATE | 위임 종료일 |
| reason | TEXT | 위임 사유 |
| is_active | CHAR(1) | 'Y'/'N' |
API 엔드포인트
모든 API는 /api/approval 접두사 + JWT 인증 필수.
결재 요청 (Requests)
| Method | Endpoint | 설명 |
|---|---|---|
| GET | /requests |
목록 조회 |
| GET | /requests/:id |
상세 조회 (lines 포함) |
| POST | /requests |
결재 요청 생성 |
| POST | /requests/:id/cancel |
결재 회수 |
| POST | /requests/:id/post-approve |
후결 처리 |
결재 요청 생성 Body
{
title: string;
target_table: string;
target_record_id: string;
approval_type?: "self" | "escalation" | "consensus" | "post"; // 기본: escalation
urgency?: "normal" | "urgent" | "critical"; // 기본: normal
definition_id?: number;
target_record_data?: Record<string, any>;
approvers: Array<{
approver_id: string;
step_order: number;
step_type?: "approval" | "consensus" | "notification"; // 기본: approval
}>;
}
결재 유형별 요청 예시
전결 (self): 결재자 없이 본인 즉시 승인
await createApprovalRequest({
title: "긴급 출장비 전결",
target_table: "expense",
target_record_id: "123",
approval_type: "self",
approvers: [],
});
합의결재 (consensus): 같은 step_order에 여러 결재자
await createApprovalRequest({
title: "프로젝트 예산안 합의",
target_table: "budget",
target_record_id: "456",
approval_type: "consensus",
approvers: [
{ approver_id: "user1", step_order: 1, step_type: "consensus" },
{ approver_id: "user2", step_order: 1, step_type: "consensus" },
{ approver_id: "user3", step_order: 1, step_type: "consensus" },
],
});
혼합형 결재선: 결재 → 합의 → 통보 조합
await createApprovalRequest({
title: "신규 채용 승인",
target_table: "recruitment",
target_record_id: "789",
approval_type: "escalation",
approvers: [
{ approver_id: "teamLead", step_order: 1, step_type: "approval" },
{ approver_id: "hrManager", step_order: 2, step_type: "consensus" },
{ approver_id: "cfo", step_order: 2, step_type: "consensus" },
{ approver_id: "ceo", step_order: 3, step_type: "approval" },
{ approver_id: "secretary", step_order: 4, step_type: "notification" },
],
});
후결 (post): 먼저 실행 후 나중에 결재
await createApprovalRequest({
title: "긴급 자재 발주",
target_table: "purchase_order",
target_record_id: "101",
approval_type: "post",
urgency: "urgent",
approvers: [
{ approver_id: "manager", step_order: 1, step_type: "approval" },
],
});
결재 처리 (Lines)
| Method | Endpoint | 설명 |
|---|---|---|
| GET | /my-pending |
내 결재 대기 목록 |
| POST | /lines/:lineId/process |
승인/반려 처리 |
승인/반려 Body
{
action: "approved" | "rejected";
comment?: string;
proxy_reason?: string; // 대결 시 사유
}
대결 처리: 원래 결재자가 아닌 사용자가 처리하면 자동으로 대결 설정 확인 후 proxy_for, proxy_reason 기록.
대결 위임 설정 (Proxy Settings)
| Method | Endpoint | 설명 |
|---|---|---|
| GET | /proxy-settings |
위임 목록 |
| POST | /proxy-settings |
위임 생성 |
| PUT | /proxy-settings/:id |
위임 수정 |
| DELETE | /proxy-settings/:id |
위임 삭제 |
| GET | /proxy-settings/check/:userId |
활성 대결자 확인 |
대결 생성 Body
{
original_user_id: string;
proxy_user_id: string;
start_date: string; // "2026-03-10"
end_date: string; // "2026-03-20"
reason?: string;
is_active?: "Y" | "N";
}
템플릿 (Templates)
| Method | Endpoint | 설명 |
|---|---|---|
| GET | /templates |
템플릿 목록 |
| GET | /templates/:id |
템플릿 상세 (steps 포함) |
| POST | /templates |
템플릿 생성 |
| PUT | /templates/:id |
템플릿 수정 |
| DELETE | /templates/:id |
템플릿 삭제 |
프론트엔드 화면
1. 결재 요청 모달 (ApprovalRequestModal)
경로: frontend/components/approval/ApprovalRequestModal.tsx
- 결재 유형 선택: 상신결재 / 전결 / 합의결재 / 후결
- 템플릿 불러오기: 등록된 템플릿에서 결재선 자동 세팅
- 전결 시 결재자 섹션 숨김 + "본인이 직접 승인합니다" 안내
- 합의결재 시 결재자 레이블 "합의 결재자"로 변경
- 후결 시 안내 배너 표시
- 혼합형 step_type 뱃지 표시 (결재/합의/통보)
2. 결재함 (/admin/approvalBox)
경로: frontend/app/(main)/admin/approvalBox/page.tsx
탭 구성:
- 수신함: 내가 결재할 건 목록
- 상신함: 내가 요청한 건 목록
- 대결 설정: 대결 위임 CRUD
대결 설정 기능:
- 위임자/대결자 사용자 검색 (디바운스 300ms)
- 시작일/종료일 설정
- 활성/비활성 토글
- 기간 중복 체크 (서버 측)
- 등록/수정/삭제 모달
3. 결재 템플릿 관리 (/admin/approvalTemplate)
경로: frontend/app/(main)/admin/approvalTemplate/page.tsx
- 템플릿 목록/검색
- 등록/수정 Dialog
- 단계별 결재 유형 설정 (결재/합의/통보)
- 합의 단계: "합의자 추가" 버튼으로 같은 step_order에 복수 결재자
- 결재자 사용자 검색
4. 결재 단계 컴포넌트 (v2-approval-step)
경로: frontend/lib/registry/components/v2-approval-step/
화면 디자이너에서 사용하는 결재 단계 시각화 컴포넌트:
- 가로형/세로형 스테퍼
- step_order 기준 그룹핑 (합의결재 시 가로 나열)
- step_type 아이콘: 결재(CheckCircle), 합의(Users), 통보(Bell)
- 상태별 색상: 승인(success), 반려(destructive), 대기(warning)
- 대결/후결/전결 뱃지
- 긴급도 표시 (urgent: 주황 dot, critical: 빨강 배경)
API 클라이언트 사용법
import {
// 결재 요청
createApprovalRequest,
getApprovalRequests,
getApprovalRequest,
cancelApprovalRequest,
postApproveRequest,
// 대결 위임
getProxySettings,
createProxySetting,
updateProxySetting,
deleteProxySetting,
checkActiveProxy,
// 템플릿 단계
getTemplateSteps,
createTemplateStep,
updateTemplateStep,
deleteTemplateStep,
// 타입
type ApprovalProxySetting,
type CreateApprovalRequestInput,
type ApprovalLineTemplateStep,
} from "@/lib/api/approval";
핵심 로직 설명
동시성 보호 (FOR UPDATE)
결재 처리(processApproval)에서 동시 승인/반려 방지:
SELECT * FROM approval_lines WHERE line_id = $1 FOR UPDATE
SELECT * FROM approval_requests WHERE request_id = $1 FOR UPDATE
대결 자동 감지
결재자가 아닌 사용자가 결재 처리하면:
approval_proxy_settings에서 활성 대결 설정 확인- 대결 설정이 있으면 →
proxy_for,proxy_reason자동 기록 - 없으면 → 403 에러
통보 단계 자동 처리
step_type = 'notification'인 단계가 활성화되면:
- 해당 단계의 모든 결재자를 자동
approved처리 comment = '자동 통보 처리'기록activateNextStep()재귀 호출로 다음 단계 진행
합의결재 단계 완료 판정
같은 step_order의 모든 결재자가 approved여야 다음 단계로:
SELECT COUNT(*) FROM approval_lines
WHERE request_id = $1 AND step_order = $2
AND status NOT IN ('approved', 'skipped')
하나라도 rejected면 전체 결재 반려.
메뉴 등록
결재 관련 화면을 메뉴에 등록하려면:
| 화면 | URL | 메뉴명 예시 |
|---|---|---|
| 결재함 | /admin/approvalBox |
결재함 |
| 결재 템플릿 관리 | /admin/approvalTemplate |
결재 템플릿 |
| 결재 유형 관리 | /admin/approvalMng |
결재 유형 (기존) |
파일 구조
backend-node/src/
├── controllers/
│ ├── approvalController.ts # 결재 유형/템플릿/요청/라인 처리
│ └── approvalProxyController.ts # 대결 위임 CRUD
└── routes/
└── approvalRoutes.ts # 라우트 등록
frontend/
├── app/(main)/admin/
│ ├── approvalBox/page.tsx # 결재함 (수신/상신/대결)
│ ├── approvalTemplate/page.tsx # 템플릿 관리
│ └── approvalMng/page.tsx # 결재 유형 관리 (기존)
├── components/approval/
│ └── ApprovalRequestModal.tsx # 결재 요청 모달
└── lib/
├── api/approval.ts # API 클라이언트
└── registry/components/v2-approval-step/
├── ApprovalStepComponent.tsx # 결재 단계 시각화
└── types.ts # 확장 타입
db/migrations/
├── 1051_approval_system_v2.sql # v2 스키마 확장
└── 1052_rename_proxy_id_to_id.sql # PK 컬럼명 통일