feat(approvals): Approval Flow v2 프런트엔드 전면 개편

- 환경/라우터 모듈에 approval_flow_v2 토글을 추가하고 FeatureFlags 초기화를 연결 (.env*, lib/core/**)
- ApiClient 빌더·ApiRoutes 확장과 ApprovalRepositoryRemote 리팩터링으로 include·액션 시그니처를 정합화
- ApprovalFlow·ApprovalDraft 엔티티/레포/유즈케이스를 도입해 서버 초안과 단계 액션(승인·회수·재상신)을 지원
- Approval 컨트롤러·히스토리·템플릿 페이지와 공유 위젯을 재작성해 감사 로그·회수 UX·템플릿 CRUD를 반영
- Inbound/Outbound/Rental 컨트롤러·페이지에 결재 섹션을 삽입하고 대시보드 pending 카드 요약을 갱신
- SuperportDialog·FormField 등 공통 위젯을 보강하고 승인 위젯 가이드를 추가해 UI 가이드를 정리
- 결재/재고 테스트 픽스처와 단위·위젯·통합 테스트를 확장하고 flutter_test_config로 스테이징 호스트를 허용
- Approval Flow 레포트/플랜 문서를 업데이트하고 ApprovalFlow_System_Integration_and_ChangePlan.md를 추가
- 실행: flutter analyze, flutter test
This commit is contained in:
JiWoong Sul
2025-10-31 01:05:39 +09:00
parent 259b056072
commit d76f765814
133 changed files with 13878 additions and 947 deletions

View File

@@ -0,0 +1,202 @@
## Approval Step Creation and Management System Full Revision Plan
---
### 🎯 Objective
Add an **Approval Step Configuration** feature to the *Inbound, Outbound,* and *Rental Registration* screens,
and expand the existing “Approval Management” and “Approval History” menus into a unified, fully functional approval workflow.
Both **backend and frontend modifications are permitted** as needed,
but all changes must be designed and deployed carefully to **avoid any side effects** and ensure **system stability**.
---
## 1. Core Principles
* Existing **data structures, responses, and UI** may be changed if necessary.
However, every change must be **controlled and validated** to ensure compatibility and prevent unintended side effects.
* Prefer **append-only** design, but allow structural refactoring when the current design causes inefficiency or redundancy.
* Every change must include **test coverage, rollback strategy, and observability** before release.
* Draft approvals must persist across browser sessions so submitters can resume from Approval Management, and pending transactions remain hidden from the primary lists until final approval.
---
## 2. Approval Step Logic and Workflow
1. **Approval Flow**
* The **submitter** is automatically set as the logged-in user (not editable).
* **Intermediate approvers** must be other users (the submitter cannot approve their own request).
* Up to **98 approval steps** can be added dynamically.
* **Final approver** is mandatory and always visible.
* **Admins** (highest privilege users) can designate themselves as the final approver.
2. **Status Transitions**
* SUBMIT → IN_PROGRESS → APPROVED / REJECTED / RECALLED
* Rejection immediately terminates the process.
* The submitter can **recall** a request only if the **first approver** has not acted yet.
* Recalled requests can be **edited and resubmitted (RESUBMIT)**.
* All state transitions must be logged in an **Audit Table** with timestamp, actor, and action.
3. **User Roles & Permissions**
* Each approver can approve/reject only their assigned step.
* Earlier steps are visible for reference but cannot be modified.
* Notes or memos visibility follows permission tiers (own, higher-level, or approvers only).
* Submitters and approvers who have already completed their step retain read access; future-step approvers (including the final approver before their turn) cannot see the document in lists or detail views and receive a `403` when attempting access.
* **terabits (Super Admin)** can view all approvals and logs but cannot modify them.
---
## 3. Frontend Revision Plan
1. **UI Additions**
* Add an **Approval Step Configuration** section (or modal) to the existing Inbound / Outbound / Rental registration forms.
* Default fields:
* Submitter (auto-filled, read-only)
* Final Approver (search/dropdown input)
* Intermediate approvers added dynamically via **“+ Add Approver”** button (max 98).
* Each row displays: Order, Approver, Role, Delete(X).
* Include **Template Selector** to load previously saved approval configurations.
* On save, send both registration data and approval configuration together.
* Draft submissions must be saved server-side and restorable from the Approval Management menu even after the browser window is closed.
2. **Approval Management Menu**
* Show user-created approval templates with step summaries (e.g., “1: Team Lead → 2: Director → Final: Executive”).
* Allow template creation, modification, and deletion.
* During submission, a user can choose a template to auto-populate steps.
* Provide `Draft`/`Pending` filters so submitters can reopen saved approvals while restricting visibility for future-step approvers.
3. **Approval History Menu**
* Display list of submitted approvals with current state, responsible approver, and timestamp.
* In detail view, show all steps with status, timestamp, and memo timeline.
* If eligible, show **Recall** button; after recall, allow **Resubmit**.
* **terabits (Super Admin)** can view all approvals globally (read-only).
* Enforce visibility so only the submitter and already-acting approvers can open pending documents; final approvers gain access only when their step is activated.
4. **Validation & Integration**
* Validation must match the current frontend logic and framework conventions.
* Reuse existing UI components (dropdowns, toasts, validation rules).
* Enforce constraints:
* No duplicate approvers
* Submitter cannot self-approve
* Final approver is mandatory
* Default inventory lists surface only fully approved transactions; drafts and submitted items live in dedicated "Pending Approvals" views.
---
## 4. Backend Revision Plan
1. **Data Model**
* Existing schemas and API responses **can be modified** when justified,
but every change must maintain backward compatibility and prevent side effects.
* Key entities (if not already present):
* `approval_requests`: Approval request header
* `approval_steps`: Per-step status tracking
* `approval_templates`: Saved approval flow templates
* `approval_template_steps`: Template step definitions
* `approval_audits`: Activity and state transition logs
2. **Core Logic**
* Enforce strict sequential flow between steps.
* Each approval/rejection triggers a state change and audit log entry.
* Recall allowed only if **step 1 approver** has not acted.
* Resubmission allowed only from recalled/rejected states.
* All transitions must be **atomic** and **transaction-safe**.
3. **API Design**
* Existing endpoints may be extended with new parameters or response fields if needed.
* Main APIs:
* `POST /approval/submit`
* `POST /approval/approve`
* `POST /approval/reject`
* `POST /approval/recall`
* `POST /approval/resubmit`
* `GET /approval/history`
* `GET /approval/templates`
* Responses should remain backward-compatible while exposing additional fields (e.g., `approvalStatus`, `currentStep`).
4. **Auditing and Monitoring**
* Log all actions (create, submit, approve, reject, recall, resubmit) in `approval_audits`.
* Each entry records user ID, timestamp, action type, and metadata.
* Emit state-change events (e.g., Kafka or WebSocket) for real-time tracking.
---
## 5. Change Control and Stability
1. **Side-Effect Prevention**
* Schema updates must include **pre-migration validation, backup, and rollback scripts**.
* Deploy via **staging → production**, with feature toggles for controlled rollout.
* Critical operations (approval/rejection) must be **idempotent** and transaction-safe.
2. **Consistency and Concurrency**
* Prevent duplicate approvers or skipped steps.
* Apply **optimistic locking/version control** for step updates.
* Centralize all approval state changes in a single service (e.g., `ApprovalService`).
3. **Testing Criteria**
* Existing modules (inbound/outbound/rental) must work with or without approval data.
* Verify all state transitions: submit → approve → final approve, reject, recall, resubmit.
* terabits can view all but not modify.
* Audit log integrity check for every state transition.
---
## 6. Operations and Collaboration
* **Frontend and Backend may both be modified** if agreed upon during design review.
* All changes must be documented and version-controlled.
* Updated response specs must be reflected in OpenAPI/Swagger documentation.
* **Feature Toggles** must allow enabling/disabling approval features per environment.
* **Monitoring and Alerts:**
* Track approval error rates, delays, and recall/resubmission frequency.
---
## 7. Deliverables
* **Frontend:**
* `ApprovalStepUI` Component
* `ApprovalTemplateManager`, `ApprovalHistoryViewer` Modules
* **Backend:**
* `ApprovalController`, `ApprovalService`, `ApprovalAuditService`
* Migration + Rollback Scripts
* Updated OpenAPI Documentation
* **Task Plans:**
* Backend 세부 작업 계획 — `../superport_api_v2/doc/approval_flow_backend_task_plan.md`
* Frontend 세부 작업 계획 — `doc/approval_flow_frontend_task_plan.md`
---
## 8. Final Directive
* Backend and frontend **may be modified freely when necessary**,
but every modification must be **safely designed to prevent side effects**.
* The approval system must support **real workflow tracking** — including
role-based visibility, note sharing, audit logging, recall/resubmission,
and seamless integration with existing registration processes.
* The guiding principles are:
**Controlled Change**, **Traceability**, and **Operational Safety**.

View File

@@ -69,6 +69,13 @@
- [x] 이력(`/approval-histories`): 조회 전용 테이블 (현황: AppLayout 기반 필터·페이지네이션 테이블과 기간 선택/엑셀 비활성 버튼까지 구현, 다운로드 API 연동은 후속 예정)
- [x] 템플릿(`/approval-templates`): 목록/헤더+단계 반복 폼 (현황: AppLayout + FilterBar + 페이지네이션 테이블과 생성/수정/삭제/복구 플로우를 구현했고 단계 등록 API까지 연동 완료, 승인자 자동완성·권한 제어 등 추가 UX는 후속 예정)
### Approval Flow v2 (신규)
- [ ] 입고/출고/대여 등록 폼에 결재 단계 구성 섹션 추가 (`ApprovalStepConfigurator` 모달/섹션, `ShadTable` 기반 리스트)
- [ ] 결재 템플릿 관리자 UI 리디자인(단계 요약 칼럼, 템플릿 버전/적용 흐름, CRUD 모달 연동)
- [ ] 결재 이력 뷰어 확장(감사 로그, 회수/재상신 버튼, 권한 기반 노출, 타임라인 뷰)
- [ ] DTO/Repository/UseCase 개편으로 `/approval/submit|approve|reject|recall|resubmit`, `/approval/templates` 엔드포인트 연동 (DTO/Repository 확장 1차 완료, UseCase/컨트롤러 전환 대기)
- [ ] 위젯/통합 테스트 추가: 단계 98개 제한, 중복 승인자 검증, 회수/재상신 플로우 (`test/features/approvals/`, `integration_test/approvals_flow_test.dart`)
## 8) 우편번호 검색 모달(UI)
- [x] 입력: 검색어 텍스트 (현황: `/utilities/postal-search` 화면이 AppLayout 미리보기로 전환되어 `ShadInput`·검색 버튼으로 모달을 열고 초기 키워드 자동 검색까지 지원)
- [x] 결과 테이블: 우편번호/시도/시군구/도로명/건물번호 (현황: 모달에서 `SuperportTable`로 컬럼을 렌더링하며 로딩/오류/빈 상태 메시지를 처리)

View File

@@ -0,0 +1,79 @@
# Approval Flow 정합성 점검
## 개요
- 점검 일시: 2025-10-31 (KST)
- 대상 저장소: `superport_v2`(프런트엔드), `superport_api_v2`(백엔드)
- 범위: Approval Flow v2 도입 이후 프런트·백엔드 계약 준수 여부
## 발견 사항 (2025-10-30)
### 1. 결재 상세 조회에 전표 동기화 정보 누락
- 프런트의 결재 상세 API 호출이 `include=transaction`을 전달하지 않아 전표 `updated_at` 정보를 수신하지 못한다 (`lib/features/approvals/data/repositories/approval_repository_remote.dart:68-81`, `lib/features/approvals/presentation/controllers/approval_controller.dart:344-348`, `lib/features/approvals/history/presentation/controllers/approval_history_controller.dart:200-235`).
- 회수·재상신 UI는 `transactionUpdatedAt` 값을 필수로 확인하며 없을 경우 즉시 토스트를 띄우고 작업을 중단한다 (`lib/features/approvals/history/presentation/pages/approval_history_page.dart:1153-1238`).
- 백엔드는 회수/재상신 시 결재와 전표의 최종 수정 시각이 모두 일치해야 한다고 검증한다 (`backend/src/app/services/approvals.rs:760-784`) ; `transaction_expected_updated_at`이 빠지면 `TRANSACTION_VERSION_MISMATCH`가 발생한다.
- 영향: 사용자는 실제로 최신 데이터를 보고 있어도 전표 타임스탬프를 확보할 방법이 없어 회수·재상신을 실행할 수 없다.
- 권장 조치:
- 상세 조회 기본 include에 `transaction`(및 필요 시 `requested_by`)을 추가하도록 `ApprovalRepositoryRemote.fetchDetail`을 수정하고, 동일 로직을 사용하는 컨트롤러들이 별도 옵션 없이 최신 값을 받도록 한다.
- 회수/재상신 전 UI가 자동으로 재조회하면서 실패 시 재시도 안내를 제공하도록 낙관적 잠금 UX를 보완한다.
#### 작업 항목
- **프런트엔드**
- [x] `ApprovalRepositoryRemote.fetchDetail`에서 `includeParts` 기본값에 `transaction`을 추가하고, 필요 시 `requested_by`까지 묶어서 전달한다 (`lib/features/approvals/data/repositories/approval_repository_remote.dart`).
- [x] `ApprovalController.selectApproval``ApprovalHistoryController.loadApprovalFlow`가 옵션 없이 전표 정보를 수신하도록 fetch 호출부를 점검하고, `ApprovalFlow.transactionUpdatedAt` 캐시 로직을 재검증한다.
- [x] 회수/재상신 트리거 시 `refreshFlow` 재조회가 실패하면 재시도 문구를 안내하도록 토스트 메시지를 보완하고, 낙관적 잠금 시나리오 위젯 테스트를 추가한다 (`lib/features/approvals/history/presentation/pages/approval_history_page.dart`).
- **백엔드**
- [x] `ApprovalDetailResponse` 직렬화에 `transaction.updated_at`이 항상 포함되는지 통합 테스트로 보증하고(`backend/tests/api/approvals_flow.rs`), 누락 시 `ApprovalRepository::find_by_id` 결과 매핑을 점검한다.
### 2. 결재 목록 “전체 상태” 조회에서 `include_pending` 누락
- 프런트 목록 API 호출은 상태 필터가 `all`일 때도 `include_pending=true`를 전달하지 않고 있다 (`lib/features/approvals/data/repositories/approval_repository_remote.dart:36-53`).
- 스펙과 도메인 모델은 기본값이 승인·완료 상태만 반환하도록 정의하며, 대기/진행 중 건을 포함하려면 `include_pending=true` 또는 `status=draft,submitted,in_progress`를 명시해야 한다 (`stock_approval_system_api_v4.md:1231-1236`, `backend/src/domain/approvals/models.rs:146-189`).
- 영향: 백엔드가 스펙대로 기본 필터를 적용하면 UI의 “전체 상태” 목록이 승인·완료 건만 노출되어 사용자 기대와 불일치가 발생한다.
- 권장 조치:
- 컨트롤러에서 상태 필터가 `all`일 때 `include_pending=true`를 전달하도록 쿼리 파라미터를 확장하고, 필요 시 `status` 문자열 필터로 명시적인 다중 상태 조회를 지원한다.
- 목록 헤더/필터 라벨이 실제 반환 범위와 일치하도록 UX 문구도 함께 재검토한다.
#### 작업 항목
- **프런트엔드**
- [x] `ApprovalRepositoryRemote.list` 호출 시 `ApprovalStatusFilter.all`이면 `include_pending=true`를 쿼리에 추가하고, 필터에 따라 `status` 문자열을 조립하도록 로직을 갱신한다.
- [x] `ApprovalController` 필터 상태(`_statusIdFor`, `_statusCodeFor`)가 새 쿼리 파라미터에 맞춰 동작하도록 단위 테스트를 추가하고, 목록/필터 위젯 테스트를 보완한다.
- [x] “전체 상태” UI 라벨과 도움말이 실제 반환 범위를 설명하도록 변경한다 (`lib/features/approvals/presentation/pages` 관련 위젯).
- **백엔드**
- [x] `GET /approvals`에서 `include_pending` 동작이 스펙과 일치하는지 e2e 테스트를 추가하고, 요청 파라미터가 누락될 경우 기본 필터가 승인·완료로 제한됨을 문서(`stock_approval_system_api_v4.md`)에 재확인한다. (저장소 상태 필터 적용 및 정규화 테스트 보강)
## 발견 사항 (2025-10-31)
### 3. 결재 목록 조회 시 상신자·전표 요약 누락
- 프런트 목록 API는 기본 include에 `steps`/`histories`만 추가하고 있어 `requester`·`transaction` 정보를 요청하지 않는다 (`lib/features/approvals/data/repositories/approval_repository_remote.dart:27-57`). 이에 따라 DTO가 비어 있는 맵을 파싱하면서 상신자 ID가 0, 이름이 `-`로 대체되고 전표 번호도 누락된다 (`lib/features/approvals/data/dtos/approval_dto.dart:85-143`, `lib/features/approvals/data/dtos/approval_dto.dart:195-204`).
- 백엔드는 `include.requested_by` / `include.transaction` 플래그가 켜졌을 때만 해당 요약을 조인하므로, 목록 응답에 최소 정보조차 제공되지 않는다 (`backend/src/adapters/repositories/approvals.rs:162-210`).
- 영향: 결재 목록의 “상신자/전표번호” 열이 항상 `-`로 표시되고, 선택 항목에서 상신자 ID가 0으로 초기화되어 재상신·필터 유지 등 후속 동작에서 상신자 정보를 잃는다.
- 권장 조치:
- 목록 조회 기본 include에 `requested_by`, `transaction`을 추가해 UI가 필요한 요약 데이터를 항상 수신하도록 한다.
- DTO 파싱 시에도 최악의 경우를 대비해 `requested_by_id` 등 기본 필드로 최소한의 ID 정보를 보존한다.
#### 작업 항목
- **프런트엔드**
- [x] `ApprovalRepositoryRemote.list` 기본 include에 `requested_by`, `transaction`을 더하고 관련 위젯/단위 테스트를 갱신한다 (`lib/features/approvals/data/repositories/approval_repository_remote.dart`).
- [x] `ApprovalDto.fromJson``requester_id` 등 단일 필드를 이용해 ID를 보강하도록 로직을 보완한다 (`lib/features/approvals/data/dtos/approval_dto.dart`).
- **백엔드**
- [x] (선택) 하위 호환을 위해 include 미지정 시 최소 `requester` 요약을 포함할지 검토한다 (`backend/src/adapters/repositories/approvals.rs`).
### 4. 서버 임시저장(Approval Draft) API 미연동
- 백엔드는 `/api/v1/approval-drafts`에서 초안 목록/조회/저장/삭제 기능을 제공하지만 (`backend/src/api/v1/approval_drafts.rs:12-99`, `backend/src/app/services/approvals.rs:1196-1286`), 프런트에는 해당 엔드포인트를 호출하는 레포지토리나 use case가 없다.
- 현재 프런트 컨트롤러는 메모리 내 `_submissionDraft`만 유지하며 세션이 끊기거나 다른 기기로 이동하면 초안을 복구할 방법이 없다 (`lib/features/approvals/presentation/controllers/approval_controller.dart:398-415`, `lib/features/inventory/inbound/presentation/controllers/inbound_controller.dart:145-151`).
- 영향: 서버 기반 임시저장 기능을 활용하지 못해 다중 기기/장시간 작업 시 초안 복구 요구사항을 충족하지 못한다.
- 권장 조치:
- Approval Draft 전용 경로/DTO/레포지토리를 추가하고, 결재 작성 및 인벤토리 폼 컨트롤러가 서버 초안을 저장·복원할 수 있도록 통합한다.
- 초안 저장/복원 흐름에 대한 위젯·통합 테스트와 문서화를 추가한다.
#### 작업 항목
- **프런트엔드**
- [x] `ApiRoutes``/approval-drafts` 경로를 추가하고 원격 레포지토리/DTO/유즈케이스를 구현한다 (신규 파일, `lib/core/network/api_routes.dart`).
- [x] `ApprovalRequestController` 및 인벤토리 컨트롤러에 서버 초안 저장·복구 흐름을 연결하고 의존성 주입을 갱신한다 (`lib/features/approvals/request/presentation/controllers/approval_request_controller.dart` 등).
- [x] 초안 관련 위젯/통합 테스트를 추가해 회귀를 방지한다 (`test/features/approvals/**`).
- **백엔드**
- [ ] 초안 엔드포인트 사용 예시를 스펙 문서에 보강하고 프런트 연동용 샘플을 공유한다 (`stock_approval_system_api_v4.md`, `doc/ApprovalFlow_System_Integration_and_ChangePlan.md`).
## 권장 후속 절차
- 위 항목 개선 후 `flutter analyze`, `flutter test`, `cargo test`를 실행해 회 regressions 여부를 확인한다.
- 낙관적 잠금 관련 시나리오는 `backend/tests/api/approvals_flow.rs` 및 대응 위젯 테스트를 추가/보강해 재현 가능성을 확보한다.
- 작업 완료 시 본 문서를 업데이트하고 관련 QA 체크리스트에 반영 상황을 기록한다.

View File

@@ -0,0 +1,82 @@
# Approval Flow 프런트엔드 작업 계획
- 기준 문서: `doc/ApprovalFlow_System_Integration_and_ChangePlan.md`, 백엔드 계획(`../superport_api_v2/doc/approval_flow_backend_task_plan.md`)
- 범위: 입고/출고/대여 등록 화면 결재 단계 구성 UI, 결재 템플릿/이력 메뉴 전면 개편, 감사 로그/회수/재상신 UX 정비
- 작업 순서: 사전 정비 → 데이터 계층 → UI/상호작용 → 검증/UI/테스트 → 문서/배포
---
## 0. 킥오프 & 환경 준비
- [x] **F0-1** 백엔드 스키마/엔드포인트 변경 리뷰 및 DTO 영향 범위 표 정리 (`doc/frontend_backend_alignment_report.md` 갱신)
- [x] **F0-2** 기능 토글(`feature.approval_flow_v2`) 주입 경로 설계 (`lib/core/config/feature_flags.dart`, `Environment.initialize`)
- [x] **F0-3** QA용 샘플 데이터(결재 단계 1~5단계, 회수/반려 케이스) 확보 후 `test/fixtures/approvals/`에 JSON 추가
## 1. 데이터 계층 업데이트
- [x] **F1-1** `ApprovalRequestDto`/`ApprovalStepDto`/`ApprovalAuditDto` 추가 및 기존 DTO 개편 (`lib/features/approvals/data/dtos/`)
- [x] **F1-2** `ApprovalRepositoryRemote` API 시그니처 확장: 제출/승인/반려/회수/재상신/템플릿 CRUD(`/approval/*`) 연동 (유즈케이스 연결은 F2 단계에서 후속 진행)
- [x] **F1-3** `StockTransactionDto`/`StockTransactionInput`에 결재 구성 필드 추가 (`lib/features/inventory/data/dtos/`)
- [x] **F1-4** `ApiClient` 요청 헬퍼에 새 엔드포인트 경로/쿼리 빌더 추가 (`lib/core/network/api_client.dart`)
- [x] **F1-5** `lib/injection_container.dart` 의존성 갱신: 신규 레포지터리/유즈케이스 바인딩
## 2. 도메인 & 유즈케이스
- [x] **F2-1** `ApprovalFlowEntity` 정의: 제출자/최종 승인자/단계/이력/상태 요약 포함 (`lib/features/approvals/domain/entities/approval_flow.dart`)
- [x] **F2-2** 제출/승인/반려/회수/재상신 유즈케이스 구현 (`lib/features/approvals/domain/usecases/submit_approval_use_case.dart` 등)
- [x] **F2-3** 템플릿 CRUD 유즈케이스 분리(`SaveApprovalTemplate`, `ApplyApprovalTemplate`)
- [x] **F2-4** `Inventory` 도메인에 결재 설정 전달용 값 객체 추가 (`lib/features/inventory/*/domain/entities/create_*_request_input.dart`)
## 3. 상태관리 & 컨트롤러
- [x] **F3-1** `ApprovalRequestController` 재구성: 단계 98개 제한, 중복 승인자 검사, 제출자/최종 승인자 바인딩
- [x] **F3-2** `ApprovalTemplateController` 확장: 템플릿 목록/저장/삭제/적용, 버전 체크
- [x] **F3-3** `ApprovalHistoryController` 개선: recall/resubmit 액션, 감사 로그 탭 분리
- [x] **F3-4** `Inbound/Outbound/Rental` 페이지 컨트롤러에서 결재 구성 상태 저장 및 제출 요청 병합
- [x] **F3-5** `AuthGuard`/`Router`에 결재 템플릿/이력 메뉴 권한 플래그 연결
- [x] **F3-6** 임시저장/재개 플로우 구현: 결재 관리 목록에 `draft` 필터 추가, 세션 종료 후 초안 복구 UX 설계
## 4. UI 구성 요소
- [x] **F4-1** `ApprovalStepConfigurator` 모달/섹션 구현 (`lib/features/approvals/request/presentation/widgets/`)
- [x] **F4-2** `ApprovalStepRow` 컴포넌트: 순번, 승인자 검색, 역할, 삭제 버튼, 오류 표시
- [x] **F4-3** `ApprovalTemplatePicker` UI: 템플릿 선택/미리보기/적용/새로 저장 플로우
- [x] **F4-4** `ApprovalTemplateManagerPage` 리디자인: `ShadTable` 적용, 단계 요약 칼럼, CRUD 모달 연동
- [x] **F4-5** `ApprovalHistoryPage` 리디자인: 상태 타임라인, 감사 로그, 회수/재상신 버튼 상태 표시
- [x] **F4-6** 입고/출고/대여 등록 폼에 Approval 섹션 삽입(`lib/features/inventory/*/presentation/pages/`)
- [x] **F4-7** `SuperportDialog`/`ShadTable` 커스텀 컬럼 추가: 승인자 아바타, 상태 뱃지, 메모 툴팁
## 5. 검증 & UX 개선
- [x] **F5-1** 제출 폼 검증: 최종 승인자 필수, 제출자 자기 승인 금지, 중복 승인자 방지
- [x] **F5-2** 단계 정렬/Drag & Drop 옵션 검토(필수 아님) 및 순서 변경 UX 결정
- [x] **F5-3** 회수 가능 조건(첫 승인자 미행동) UI 표시 및 비활성화 처리
- [x] **F5-4** 반려/회수/재상신 토스트/다이얼로그 메시지 표준화 (한국어)
- [x] **F5-5** 감사 로그 뷰어에 필터(행위자, 액션, 기간) 추가
- [x] **F5-6** 대시보드 `pending approvals` 카드가 새 상태/요약을 노출하도록 업데이트
- [x] **F5-7** 결재 열람 권한/최종대기 노출 제한 UX: 상신자·기결재자만 상세 접근, 최종 승인 대기 전표 기본 목록 비노출 및 대기 섹션 분리
## 6. 테스트
- [x] **F6-1** 단위 테스트: DTO 직렬화/역직렬화, 유즈케이스 권한 체크 (`test/features/approvals/domain/`)
- [x] **F6-2** 위젯 테스트: 결재 구성 모달, 템플릿 적용, 회수/재상신 흐름 (`test/features/approvals/presentation/`)
- [x] **F6-3** 통합(골든) 테스트: 입고 등록 → 결재 제출 → 승인자 전환 UI (`integration_test/approvals_flow_test.dart`)
- [x] **F6-4** 모킹 대신 스테이징 API 더블 사용을 위한 HttpOverrides 정비(토글 기반)
`flutter_test_config.dart`에서 `USE_APPROVAL_STAGING_DOUBLE` 토글 시 허용 호스트 기반 HttpOverrides를 주입하도록 구성
- [x] **F6-5** 테스트 데이터 정비: 승인자 목록/권한/템플릿 샘플 업데이트
`test/helpers/fixture_loader.dart` 추가, `test/fixtures/approvals/*.json``ApprovalApproverCatalog`를 스테이징 샘플과 동기화
- [x] **F6-6** 권한/노출 테스트: 초안 복구, 비도달 승인자 403, 최종 승인 전 리스트 비노출 시나리오
`approval_controller_test.dart`, `approval_history_controller_test.dart`, `approval_form_initializer_test.dart` 등에서 초안 복구/403 차단/목록 비노출 플로우 검증
## 7. 문서 & 개발자 경험
- [x] **F7-1** `doc/IMPLEMENTATION_TASKS.md`에 Approval Flow 섹션 추가 및 진행 상태 트래킹
- [x] **F7-2** `doc/frontend_api_alignment_plan.md`에 엔드포인트/계약 변화 반영
- [x] **F7-3** `doc/frontend_backend_alignment_report.md`에 프런트 측 후속 작업 연결
- [x] **F7-4** `lib/widgets/` 컴포넌트 가이드에 결재 위젯 사용법 추가 (필요 시)
- [x] **F7-5** 완료 시 `notify.py` 워크플로 실행 및 알림 (`/Users/maximilian.j.sul/.codex/notify.py`)
## 8. 배포 & 롤백
- [ ] **F8-1** 기능 토글 기본 비활성 상태로 머지 → 백엔드 배포/마이그레이션 완료 후 활성화
- [ ] **F8-2** 스테이징 UAT 체크리스트: 제출/승인/반려/회수/재상신/템플릿 CRUD/대시보드 반영
- [ ] **F8-3** 운영 배포 전 QA 결과 공유 및 위험 항목 점검, 롤백 시 토글 비활성화 절차 문서화
- [ ] **F8-4** 배포 후 모니터링: 에러 토스트/네트워크 실패 레포트 수집, 사용자 피드백 채널 열람
---
### 참고 링크
- 백엔드 계획: `../superport_api_v2/doc/approval_flow_backend_task_plan.md`
- 스펙 문서: `doc/stock_approval_system_spec_v4.md`, `doc/stock_approval_system_api_v4.md`
- QA 체크리스트: `doc/qa/approval_flow_uat_checklist.md` (작성 대상)

View File

@@ -3,14 +3,22 @@
## 진행 현황 스냅샷 (2025-10-19 기준)
- 단계 1~2: 공통 네트워크 인프라와 마스터 도메인 원격 저장소/테스트가 모두 반영되어 실 API 계약 기준 코드가 자리잡았다.
- 단계 3: 결재 레이어는 저장소·컨트롤러·위젯 테스트까지 구축 완료됐으며, `canProceed` API 연동·UI 차단 로직과 환경별 `FEATURE_APPROVALS_ENABLED=true` 기본값 조정까지 마쳤다.
- 단계 4: 재고 트랜잭션 컨트롤러와 submit/complete 플로우가 API 호출로 전환됐고, 고객 필터/위젯에서 사용하던 정적 카탈로그를 제거하여 전 구간이 실데이터를 사용한다. 보고서 기능은 `ReportingRepositoryRemote` 기반으로 API에 연결돼 다운로드 링크/바이너리 응답을 모두 처리하며, UI는 진행 상태·에러·다운로드 액션(열기/URL 복사)을 제공한다.
- 단계 4: 재고 트랜잭션 컨트롤러와 submit/approve/reject/cancel/complete 플로우가 API 호출로 전환됐고, 고객 필터/위젯에서 사용하던 정적 카탈로그를 제거하여 전 구간이 실데이터를 사용한다. 보고서 기능은 `ReportingRepositoryRemote` 기반으로 API에 연결돼 다운로드 링크/바이너리 응답을 모두 처리하며, UI는 진행 상태·에러·다운로드 액션(열기/URL 복사)을 제공한다.
- 단계 5: 테이블 spec 분리는 완료됐고, 권한 경로 통일·Failure 파서 고도화·실패 메시지 통합·실제 API 플로우 검증이 잔여 과제로 남아 있다.
- (2025-10-29) Approval Flow v2 대응을 위해 `ApprovalSubmissionInput` 등 도메인 입력 모델과 `/approval/submit|approve|reject|recall|resubmit|history` 호출을 Data 레이어에 도입했다. 기존 `create/update` 경로는 레거시 화면이 교체될 때까지 병행 유지한다.
## 문서 동기화 규칙
1. `superport_api_v2` 리포지터리의 `stock_approval_system_*.md` 문서를 단일 소스로 간주하고, 수정은 반드시 백엔드 리포지터리에서 먼저 수행한다.
2. 백엔드 문서 변경 후 프론트 리포지터리 루트에서 `tool/sync_stock_docs.sh`를 실행해 `doc/` 경로를 갱신한다. CI 또는 로컬 검증 시에는 `tool/sync_stock_docs.sh --check`로 차이를 확인한다.
3. 문서 차이가 감지되면 동기화 커밋을 생성하고 PR 본문에 백엔드 커밋 링크를 포함해 리뷰어가 출처를 추적할 수 있도록 한다.
## Approval Flow v2 연동 계획 (신규)
1. 백엔드 세부 작업 계획(`../superport_api_v2/doc/approval_flow_backend_task_plan.md`)과 프런트 작업 계획(`doc/approval_flow_frontend_task_plan.md`)을 기준으로 동시 진행한다.
2. 입고/출고/대여 등록 화면은 결재 단계 구성 섹션을 추가하고 제출 요청에 Approval payload를 병합한다.
3. 결재 템플릿/이력 메뉴는 `ShadTable` 기반으로 재구성하고 recall/resubmit, 감사 로그 UI를 확장한다.
4. Approval 관련 DTO/레포지터리/유즈케이스를 전면 재정비하여 신규 엔드포인트(`/approval/submit|approve|reject|recall|resubmit`, `/approval/templates`)와 계약을 맞춘다.
5. 테스트 체계는 위젯/통합 테스트에서 결재 단계 추가/삭제/회수/재상신 플로우를 검증하고, `integration_test`에 시나리오를 추가한다.
## 0. 사전 준비 및 브랜치 전략
1. 현재 백엔드 서버는 아직 기동되지 않았지만, 모든 기능은 실제 API 계약(`stock_approval_system_api_v4.md`)을 기준으로 구현한다.
2. 프론트엔드 작업용 브랜치를 `feature/api-integration` 형태로 생성하고, 단계별 작업이 끝난 뒤 스쿼시 머지한다.
@@ -40,22 +48,27 @@
## 3. 결재(Approvals) 도메인 실연동 준비
1. [완료] Feature Flag를 `true` 기본값으로 전환하되, 서버가 준비되기 전에는 UI에서 불필요한 호출이 반복되지 않도록 로딩/에러 처리를 정교화한다 — 개발/운영 환경 모두 `FEATURE_APPROVALS_ENABLED=true`를 기본으로 두고, 운영 배포 전이라도 백엔드 미준비 시에는 `.env.*`에서 수동으로 비활성화하도록 가이드를 명시했다.
2. [완료] `ApprovalRepositoryRemote`에 목록/상세 `include=steps,histories,template` 옵션과 생성/수정/삭제/복구/`canProceed` 호출을 구현한다 — `can-proceed` 엔드포인트까지 연동해 컨트롤러에서 액션 실행 전 검증하도록 구성했다.
2. [진행중] `ApprovalRepositoryRemote` 확장
- (완료) 목록/상세 `include=steps,histories,template` 옵션과 생성/수정/삭제/복구/`canProceed` 호출을 구현했다 — `can-proceed` 엔드포인트까지 연동해 컨트롤러에서 액션 실행 전 검증하도록 구성했다.
- (2025-10-29) `submit`/`approve`/`reject`/`recall`/`resubmit`/`listHistory` 메서드와 대응 DTO(`ApprovalSubmitRequestDto`, `ApprovalResubmitRequestDto`, `ApprovalDecisionRequestDto`, `ApprovalRecallRequestDto`, `ApprovalAuditListDto`)를 추가했다. 컨트롤러·유즈케이스 연결은 F2 단계에서 마이그레이션한다.
3. [완료] `ApprovalStepController.performStepAction``/api/v1/approval-steps/{id}/actions`로 요청을 보낸 뒤 응답으로 상태를 갱신하도록 구성한다.
4. [완료] Approval Templates
- 템플릿 CRUD/restore 및 스텝 편집 API 연동을 구현하고, 템플릿 적용 시 `/approvals/{id}/steps` 호출과 연계되도록 리팩터링한다.
5. [완료] 테스트
- `ApprovalController``ApprovalPage` 권한 테스트에 `canProceed` true/false 흐름을 추가했고, 기능 플래그 on/off 시나리오를 커버하는 위젯 테스트를 유지하고 있다.
6. [ ] 결재 열람 제한 연동
- 상신자/기결재자만 목록·상세 API를 조회할 수 있도록 `ApprovalRepositoryRemote`에 403 (`APPROVAL_ACCESS_DENIED`) 처리 분기를 추가하고, UI에서 권한 토스트/리다이렉트를 구현한다.
## 4. 재고 트랜잭션 (입고/출고/대여) 실데이터 전환 준비
1. [완료] Repository 작성
- `StockTransactionRepositoryRemote`, `TransactionLineRepositoryRemote`, `TransactionCustomerRepositoryRemote``/api/v1/stock-transactions` 계열 엔드포인트에 맞춰 구현한다.
- `include=lines,customers,approval` 파라미터를 지원해 상세 응답을 완성한다.
- ApiClient 모킹 기반 단위 테스트로 쿼리/경로/페이로드 구성을 검증한다.
- 신규 `status`/`include_pending` 파라미터를 지원해 초안·상신 전표는 기본 목록에서 제외하고, 대기 전용 화면에서만 렌더링한다.
2. [진행중] Controller 연동
- (완료) `InboundPage`, `OutboundPage`, `RentalPage`에서 `_mockRecords`를 제거하고 `StockTransactionRepository` 기반 실데이터를 로드하도록 전환했다.
- (완료) 데이터 페칭 로직을 전용 컨트롤러로 분리하고 페이지가 컨트롤러 상태를 구독하도록 리팩터링했다.
- (진행) 상태 전이 액션(Submit/Approve/Reject/Cancel/Complete)을 API 호출 기반으로 대체한다 — submit/complete는 컨트롤러와 위젯에 연결되어 있으나 approve/reject/cancel 버튼/토스트 연결, 생성·수정 다이얼로그에서 `StockTransaction*Input` 매핑, 신규 공통 위젯을 활용한 필드 교체가 남아있다.
- (진행) 상태 전이 액션(Submit/Approve/Reject/Cancel/Complete)을 `doc/stock_approval_system_api_v4.md` 4.7절 규격에 맞춰 API 호출 기반으로 정비한다 — submit/approve/reject/cancel/complete 모두 컨트롤러·위젯에 연결되도록 리팩터링하고, 생성·수정 다이얼로그 `StockTransaction*Input` 매핑 공통 위젯 교체를 마무리한다.
3. 상세 모달 UI
- 서버 응답 스키마에 맞춘 DTO→Domain 변환기를 작성하고, 편집/삭제 후 상태 동기화를 서버 응답으로 수행한다.
4. 테스트
@@ -102,7 +115,7 @@
1. [완료] 백엔드 서버 기동 및 점검
- Homebrew로 PostgreSQL 16을 설치해 로컬 DB를 준비한 뒤, `migration/001_initial_schema.sql``script/load_sample_data.sh --with-demo-data`로 스키마·샘플 데이터를 적재했다.
- `cargo run -p backend``nohup`으로 기동하고 `curl http://127.0.0.1:8080/health`로 헬스 체크를 확인했다.
- `script/run_api_tests.sh --base-url http://127.0.0.1:8080` 실행 결과 110개 시나리오 중 98건 통과, 12건(재고 전이 흐름 및 그룹-메뉴 권한 복구)이 실패함을 확인했다. 실패 케이스는 미구현 엔드포인트 목록과 함께 log/API_TEST_RESULT_YYYYMMDD_HHMMSS.txt에 기록해 백엔드 공유 예정.
- `script/run_api_tests.sh --base-url http://127.0.0.1:8080``stock_approval_system_api_v4.md` (2025-09-18) 스펙 반영 버전으로 재실행해 상태 전이·권한 복구 시나리오가 모두 통과하는지 확인하고, 결과 로그(log/API_TEST_RESULT_YYYYMMDD_HHMMSS.txt)를 갱신한다.
- (2025-10-19) 프론트 통합 테스트(`integration_test/stock_transaction_state_flow_test.dart`)의 환경 변수 안내 및 `.env.staging.example` 템플릿을 추가했다. 백엔드에서 재고 상태 전이/권한 복구 엔드포인트를 배포하면 스테이징 토큰·ID를 확보한 뒤 재실행한다.
2. [완료] 정적 분석 및 테스트
- `flutter analyze` → No issues found.
@@ -114,11 +127,10 @@
- `assets/.env.production` 기준 값과 README의 환경 변수 설명을 재확인했으며, `flutter build web --release` 산출물을 통해 배포 아티팩트 생성을 검증했다.
- 최종 머지 전 `notify.py` 호출 및 릴리스 노트/환경 파일 확정 프로세스는 배포 승인 시점에 수행하도록 안내를 남긴다.
- 백엔드 미구현 항목 대응 전략
- [x] 재고 상태 전이 실패(Stage 7 미구현 8건) 관련 API 스펙을 백엔드 팀과 재검토하고, `PATCH /stock-transactions/{id}/status` 확장 일정과 테스트 데이터 세트를 공유한다. (2025-10-19) `doc/backup/backend_change_requests.md` 2.4절에 상태 전이 API 요구사항과 테스트 데이터 항목을 업데이트했다.
- [x] 그룹-메뉴 권한 복구 미구현(4건)은 `/group-menu-permissions/{id}/restore` 엔드포인트 공개 후 프론트 통합 테스트에 포함시킨다. (2025-10-19) 동일 문서 2.2절에 복구 API 요구사항을 명시하고 테스트 시나리오를 정리했다.
- [x] 프론트단에서는 `ApiErrorMapper``Failure` 파서를 보강해 403/409/422 응답 메시지를 토스트·다이얼로그에 그대로 노출하고, 재시도 시 가이드 문구를 제공한다.
- [x] 백엔드 수정 전까지 승인/취소 버튼에는 기능 플래그를 적용해 운영 환경에서 잘못된 전이 요청이 발생하지 않도록 보호한다. (2025-10-19) `FEATURE_STOCK_TRANSITIONS_ENABLED` 플래그를 추가하고 입·출·대여 화면에서 버튼을 비활성화하며 안내 배지를 노출하도록 조정했다.
- 백엔드 v4 스펙 반영 체크리스트
- [ ] 재고 상태 전이 API 회귀 테스트를 `doc/stock_approval_system_api_v4.md` 4.7절 기준으로 재작성하고 submit/approve/reject/cancel/complete 호출 성공 여부를 통합 테스트에 반영한다.
- [ ] 그룹-메뉴 권한 복구 API(`POST /group-menu-permissions/{id}/restore`) 시나리오를 복구해 삭제/복구 UI가 `include_deleted=true` 응답을 사용하는지 검증한다.
- [ ] 백엔드 배포 확인 후 `FEATURE_STOCK_TRANSITIONS_ENABLED` 플래그 해제 시나리오와 운영 전환 체크리스트를 정리한다.
## 8. 재고 생성 결재 정보 수집 계획 (2024-08-XX 업데이트)
1. **신규 입력 필드 구성**

View File

@@ -3,6 +3,7 @@
## 개요
- 기준 문서: `doc/backup/backend_change_requests.md`와 최신 계약 문서(`doc/stock_approval_system_api_v4.md`)를 토대로 Flutter 프런트(`superport_v2`)와 Rust 백엔드(`superport_api_v2`) 구현을 재검증했다.
- 백엔드 팀이 전달한 최신 패치(로그인/트랜잭션, 결재 단계, 대시보드·보고서, 권한)와 `cargo test` 통과 결과를 반영해 실제 로그인 → 대시보드 → 재고/결재 → 보고서/권한 흐름을 다시 점검했다.
- Approval Flow 전면 개편 합의를 위해 백엔드 작업 계획(`../superport_api_v2/doc/approval_flow_backend_task_plan.md`)과 프런트 작업 계획(`doc/approval_flow_frontend_task_plan.md`)을 신규 작성했다.
## 주요 정합성 결과
| 구분 | 내용 | 결과 | 후속 조치 |
@@ -14,6 +15,7 @@
| 5 | 그룹-메뉴 권한 `path`·`is_deleted`·`include_deleted` | ✅ 해결 (`backend/src/domain/group_menu_permissions.rs:149`, `backend/src/adapters/repositories/group_menu_permissions.rs:227`) | DTO/필터·권한 편집 UI가 추가 필드로 회귀 없는지 테스트 |
| 6 | 대시보드 KPI `delta` 전일 대비 비율 계산 | ✅ 해결 (`backend/src/adapters/repositories/dashboard.rs:61`) | KPI 카드/차트가 백분율·부호 표시를 지원하는지 확인 |
| 7 | 사용자 요약(`created_by`, `requester`) 기본 노출 및 회귀 테스트 | ✅ 해결 (`backend/src/domain/approval_templates.rs:34`, `backend/src/adapters/repositories/approval_templates.rs:100`, `backend/src/adapters/repositories/approvals.rs:878`, `backend/src/adapters/repositories/stock_transactions.rs:1173`, `backend/src/adapters/repositories/reports.rs:256`) | 프런트 DTO가 사번(`employee_id`)·이름을 모두 반영하는지, 리스트/리포트 표시가 정상인지 검증 |
| 8 | Approval Flow v2: 트랜잭션 결재 구성 필수화 + `/approval/*` 엔드포인트 확장 | 🚧 진행중 (`backend/src/domain/stock_transactions.rs:365`, `backend/src/domain/approvals/models.rs:583`, `backend/src/api/v1/approval_flow.rs:13`) | 프런트 DTO/리포지토리 확장(`lib/features/inventory/transactions/data/dtos/`, `lib/features/approvals/data/`) 및 기능 토글 기반 UI 연동 필요 |
아래 섹션에서 영역별 관찰 내용과 프런트엔드 후속 작업을 정리했다.
@@ -31,12 +33,22 @@
- `expected_return_date`가 생성/수정/조회 전 흐름에 포함된다(`backend/src/domain/stock_transactions.rs:274`, `backend/src/adapters/repositories/stock_transactions.rs:808`). 프런트 `StockTransactionInput``RentalPage`는 이미 필드를 전송하므로, 저장 후 상세/목록에서 값이 노출되는지 UI 테스트를 추가하면 된다(`lib/features/inventory/rental/presentation/pages/rental_page.dart:1651`).
- 마이그레이션 `migration/006_add_expected_return_date_to_stock_transactions.sql`을 반드시 적용해야 하며, 로컬/스테이징 DB에 컬럼이 없으면 500 에러가 발생한다. DevOps와 일정 합의 후 `diesel migration run`을 실행하고 `.env` DB URL을 재확인한다.
- 추가 확인: 고객 정보(`customers[].customer`), 거래 라인 메모, 템플릿명 등 선택 필드가 null일 때 키가 빠지지 않는지 샘플 데이터를 확보해 양쪽 DTO 직렬화/역직렬화 테스트를 보강한다.
- 최종 승인 완료 전에는 기본 입고/출고/대여 목록에서 전표가 숨겨져야 하므로, 프런트 목록/완료 카드에 `status=draft|submitted` 필터를 추가하고 대기 전용 섹션을 제공한다.
## 결재 단계
- 목록 API가 `q`·`status_id` 필터를 처리하고 응답에 `transaction_no`를 포함한다(`backend/src/adapters/repositories/approval_steps.rs:176`). 프런트 검색 바(`lib/features/approvals/step/presentation/controllers/approval_step_controller.dart`)가 두 파라미터를 전달하는지, 리스트에서 거래번호를 표시하는지 확인한다.
- 도메인이 `status` 구조체(`{ id, name, code }`)를 반환한다(`backend/src/domain/approval_steps.rs:84`). 프런트 DTO는 `status_id` 입력과 `status` 응답을 모두 지원해야 하므로, 레거시 필드 제거와 단위 테스트(`test/features/approvals/step/domain/`) 성공 여부를 점검한다.
- 컨트롤러/위젯 테스트: 필터링, 상태 변경, 거래번호 표시 흐름을 추가해 회귀를 방지한다.
- 추가 확인: `histories[].action`에 레거시 데이터가 들어오는 경우(`id`, `name` 누락) 프런트가 안전하게 폴백 문자열을 표시하는지, 백엔드는 해당 케이스를 데이터 정제 로직으로 보완할지 정한다.
- 열람 권한은 상신자와 이미 결재한 승인자에게만 부여된다. 단계 미도달 승인자는 목록/상세 접근 시 403 처리되므로, 프런트 `ApprovalDetailPage`·`MyApprovals`에서 숨김/권한 안내 토스트를 구현하고 최종 승인 대기 상태에서도 상신자·중간 승인자만 접근 가능하도록 필터링한다.
## Approval Flow v2
- 입·출·대여 생성 요청에 `approval` 블록이 필수(`backend/src/domain/stock_transactions.rs:365`)이며, `approval.config`는 템플릿(`template_id`) 또는 직접 지정 단계(`steps[]`) 중 하나가 존재해야 한다(`backend/src/domain/stock_transactions.rs:384`). 프런트 입력모델(`lib/features/inventory/transactions/domain/entities/stock_transaction_input.dart:1`)은 `approval`을 선택이 아닌 필수 값으로 승격하고, 최소 1단계 + 최종 승인자 검증을 위젯 레벨에서 선반영해야 한다.
- 트랜잭션 목록 기본 필터는 승인 완료 건만 노출하고 `include_pending` 파라미터를 명시해야 대기/초안이 반환된다(`backend/src/domain/stock_transactions.rs:29`, `backend/src/domain/stock_transactions.rs:178`). 프런트 리스트 필터(`lib/features/inventory/transactions/domain/entities/stock_transaction_input.dart:158`)와 대시보드 카드가 새 파라미터를 전달하도록 조정하고, 결재 대기 전표 전용 섹션을 기능 토글(`feature.approval_flow_v2`)로 가드한다.
- 결재 제출·재상신 엔드포인트는 `ApprovalSubmitRequest`/`ApprovalResubmitRequest`를 사용하며 전 단계 배열을 전송해야 한다(`backend/src/domain/approvals/models.rs:583`, `backend/src/api/v1/approval_flow.rs:13`). 프런트는 `ApprovalRequestDto`·`ApprovalStepDto`·`ApprovalAuditDto` 신설 후 `ApprovalRepositoryRemote`를 통해 `/approval/submit|resubmit` 호출 시 단계 순번·승인자 ID를 직렬화한다.
- 승인/반려/회수 액션은 `actor_id`가 세션 사용자와 일치해야 하고 옵티미스틱 잠금(`expected_updated_at`, `transaction_expected_updated_at`)을 요구한다(`backend/src/domain/approvals/models.rs:624`, `backend/src/domain/approvals/models.rs:634`). 프런트 컨트롤러(`lib/features/approvals/presentation/controllers/approval_history_controller.dart`)는 서버 응답의 `approval.updated_at`을 저장해 재전송 시 파라미터로 포함해야 충돌 409를 피할 수 있다.
- 결재 상세 응답은 `current_step`, `steps[].status.is_blocking_next`, `histories[].action_code`를 포함하며 비허용 사용자에게는 `APPROVAL_ACCESS_DENIED`가 반환된다(`doc/stock_approval_system_api_v4.md:1011`, `backend/src/api/v1/approval_flow.rs:42`). DTO 파서(`lib/features/approvals/data/dtos/approval_dto.dart`)에서 새 서브 객체를 맵핑하고, 403 수신 시 접근 제한 안내를 표준 토스트로 노출한다.
- 프런트 데이터 계층에 `ApprovalSubmissionInput`/`ApprovalDecisionInput`/`ApprovalRecallInput`/`ApprovalResubmissionInput`을 추가하고, `ApprovalRepositoryRemote.submit|approve|reject|recall|resubmit|listHistory` 메서드를 신규 엔드포인트(`/approval/submit`, `/approval/approve`, `/approval/reject`, `/approval/recall`, `/approval/resubmit`, `/approval/history`)에 맞춰 구현했다. (`lib/features/approvals/domain/entities/approval.dart`, `lib/features/approvals/data/repositories/approval_repository_remote.dart`, 2025-10-29) — 기존 `create/update/assignSteps` 경로는 레거시 호환을 위해 유지하되, F2 단계에서 컨트롤러/유즈케이스를 새 흐름으로 전환할 예정이다.
## 보고서 (PDF)
- 백엔드가 PDF를 스트리밍으로 내려주고 파일명·Content-Length·ETag를 헤더에 포함한다(`backend/src/api/v1/reports.rs:94`). 프런트 `ReportingRepositoryRemote``StreamedResponse` 처리를 유지하되, 새 메타데이터(`report_name`, `generated_at`)로 다운로드 UI를 업데이트한다(`lib/features/reporting/presentation/controllers/reporting_controller.dart`).
@@ -54,14 +66,17 @@
| DB | `006_add_expected_return_date_to_stock_transactions.sql` 적용 확인 | 백엔드 | 진행 예정 | 스테이징 DB 스키마 점검 후 공유 |
| 결재 | 단계 검색(`q`, `status_id`)·거래번호 노출 통합 테스트 | 프런트/백엔드 | 준비 | 계약 데이터 샘플 확보 필요 |
| 결재 | `histories.action` 레거시 데이터 폴백 처리 협의 | 프런트/백엔드 | 준비 | 데이터 정제 vs UI 폴백 선택 |
| 결재 | 열람 권한/대기 전표 노출 제한 구현 (`draft`,`submitted` 접근 제어) | 프런트/백엔드 | 준비 | API 403/필터 명세 동기화 |
| 보고서 | Approvals/Transactions PDF 스트리밍 합동 점검 | 프런트/백엔드 | 준비 | 대용량 파일·감사 로그 확인 |
| 보고서 | 감사 로그 정책 준수 여부 재확인 | 백엔드 | 준비 | 정책 준수 결과 문서화 |
| 결재 | Approval Flow 작업 계획 상호 공유(`doc/approval_flow_frontend_task_plan.md`) | 프런트/백엔드 | 완료 | 백엔드 문서(`../superport_api_v2/doc/approval_flow_backend_task_plan.md`)와 동기화 |
| QA | `flutter analyze`, `flutter test --coverage` 회귀 실행 후 공유 | 프런트 | 준비 | DTO/테스트 수정 후 `notify.py` 발송 |
| QA | `cargo test` + 통합 시나리오 스크립트 재실행 | 백엔드 | 준비 | 보고서/결재 단계 회귀 포함 |
## 테스트 & 다음 단계
- Approval Flow 개선 과제는 `doc/approval_flow_frontend_task_plan.md`를 기준으로 우선순위를 재정정하고 백엔드 진행 상황과 주별 체크인을 맞춘다.
- 백엔드 `cargo test` 통과 보고가 공유됐지만, 프런트 QA 관점에서는 다음을 진행한다.
- 새 마이그레이션(`006_add_expected_return_date_to_stock_transactions.sql`) 적용 → 스테이징 DB 반영 상태 확인.
- 결재 단계 검색(`q`, `status_id`), 거래번호 노출, 보고서 PDF 다운로드를 프런트/백엔드 합동 점검.
- 결재 단계 검색(`q`, `status_id`), 거래번호 노출, 결재 열람 권한 제한, 보고서 PDF 다운로드를 프런트/백엔드 합동 점검.
- `flutter analyze`, `flutter test --coverage`로 DTO·테스트 변경 이후 회귀 여부 확인.
- 모든 작업을 마치면 `notify.py` 워크플로를 통해 완료 알림을 발송한다.

View File

@@ -34,6 +34,7 @@
- `404 NOT_FOUND` — 리소스 없음 또는 삭제됨.
- `409 CONFLICT` — 유니크 제약, 결재 단계 상태 충돌.
- `422 UNPROCESSABLE_ENTITY` — 비즈니스 규칙 위반(출고 고객 누락, blocking 상태 전이 등).
- `403 FORBIDDEN` — 권한 부족. 결재 열람 제한 시 `APPROVAL_ACCESS_DENIED` 코드를 사용한다.
- 에러 응답 예: `{ "error": { "code": 422, "message": "출고 트랜잭션에는 고객이 최소 1건 필요합니다.", "details": [...] } }`.
- **CORS 정책:** 서버는 `config/default.toml``[cors]` 설정을 사용해 허용 오리진을 제어한다. `allowed_origins`가 비어 있으면 모든 오리진을 허용하고, 값에 `http://localhost` 또는 `https://web.example.com:*`처럼 포트 와일드카드(`:*`)를 포함하면 동적 포트 환경에서도 `Access-Control-Allow-Origin`이 요청 오리진과 동일하게 반환된다. 허용 오리진에 일치하지 않으면 `400 BAD_REQUEST`가 응답된다.
@@ -549,10 +550,14 @@
`APP-YYYYMMDDNNNN` 패턴으로 생성한 값을 응답에서 확인한다. `approval`
블록은 결재 생성에 필요한 정보를 담으며 생략할 수 없다.
> 기본 목록(`status` 미지정, `include_pending` 미사용)은 최종 승인 완료된 전표만 노출한다. 초안·상신 단계 전표는 `status=draft,submitted` 또는 `include_pending=true`로 별도 조회하거나 Approval Flow 화면에서 확인한다.
### 4.2 목록 조회
`GET /stock-transactions?customer_id=301&include=lines,customers,approval`
- `customer_id` (optional, number): 지정한 고객이 연결된 트랜잭션만 반환한다. 다른 검색 파라미터와 조합 가능하며, `include=customers` 사용 시 선택 고객 정보가 응답에 유지된다.
- `status` (optional, string): `draft`, `submitted`, `approved`, `completed`, `rejected`, `recalled` 값을 콤마로 조합한다. 기본값은 `approved,completed`이며, 초안/상신 건을 조회하려면 `status=draft,submitted`을 명시해야 한다.
- `include_pending=true` (optional, boolean): `true`로 설정 시 기본 필터를 무시하고 모든 상태(초안·상신 포함)를 반환한다. 기본 응답은 최종 승인(`approved`,`completed`) 건만 포함한다.
```json
{
"items": [
@@ -1004,6 +1009,9 @@
### 5.2 목록 조회
`GET /approvals?include=steps,histories`
- `include` (optional, string): `steps`, `histories`, `transaction`, `requested_by`를 콤마로 조합한다.
- **열람 권한:** 상신자 또는 이미 결재를 완료한 승인자만 목록을 조회할 수 있다. 향후 단계 승인자 및 관계없는 사용자가 호출하면 `403``APPROVAL_ACCESS_DENIED` 코드를 반환하며, 응답 본문에는 `{ "error": { "code": 403, "message": "approval access denied" } }` 형식을 사용한다.
```json
{
"items": [
@@ -1104,6 +1112,7 @@
### 5.3 단건 조회
`GET /approvals/5001?include=steps,histories`
- 상신자, 이미 결재를 수행한 승인자, 시스템 감사 권한(`approval.view_all`)을 가진 사용자만 접근 가능하다. 향후 단계 승인자는 `403` (`APPROVAL_ACCESS_DENIED`) 응답을 받는다.
```json
{
"data": {
@@ -1360,6 +1369,7 @@
}
}
```
- `approval.transaction.updated_at` 필드는 전표(StockTransaction)의 최신 수정 시각(UTC)을 나타내며 회수·재상신 시 `transaction_expected_updated_at`로 전달해야 한다.
### 5.6 단계 행위
`POST /approval-steps/7001/actions`
@@ -1607,10 +1617,11 @@
주요 필터 및 확장 파라미터:
- `approval_id`, `approval_step_id`, `approver_id`, `approval_action_id`, `status_id`
- `q`(결재번호·승인자 검색), `action_from`, `action_to` (ISO8601)
- `approval_id`, `approval_step_id`, `approver_id`, `approval_action_id`(정수 ID), `status_id`
- `q`(결재번호·승인자 검색), `action_from`, `action_to` (ISO8601 UTC)
- `sort=action_at|created_at|updated_at`, `order=asc|desc`
- `include` 기본값은 `approver,approval_action,from_status,to_status`; `approval`, `step`, `status` 토큰으로 확장
- 응답은 `action` 오브젝트에 `name`/`code`를, 루트 레벨에 `action_code`를 포함하여 감사 행위 식별자를 일관되게 노출한다.
`GET /approval-histories/91001?include=approval,step`
```json
@@ -1621,9 +1632,11 @@
"approval_step_id": 7001,
"action": {
"id": 3,
"name": "보류"
"name": "보류",
"code": "comment"
},
"action_at": "2025-09-18T08:05:00Z",
"action_code": "comment",
"note": "보류 코멘트",
"approver": {
"id": 21,

View File

@@ -4,6 +4,7 @@
**버전:** 2025-09-18 16:22:30Z (UTC)
**요약:** 벤더 ↔ 창고 ↔ 고객사 간 물품 이동(입고/출고)을 관리하는 최소구성 시스템.
- 트랜잭션당 1개의 결재(1:1), **승인자 순서 기반의 순차 결재** 지원.
- 상신자는 결재 초안을 임시저장할 수 있으며, 브라우저를 닫아도 `결재 관리` 목록에서 다시 불러와 편집/상신할 수 있다.
- **다음 승인자로 넘어가면 안 되는 상태**를 `approval_statuses.is_blocking_next`로 제어.
- 모든 테이블(타입/코드 테이블 포함)에 **공통 컬럼** 적용: `is_active`, `is_deleted`, `created_at`, `updated_at`.
- **벤더는 트랜잭션 헤더에 연결하지 않음**(벤더는 제품을 통해서만 추적).
@@ -21,6 +22,8 @@
- 결재 목록 응답은 각 항목의 `id`(= `approvals.id`)를 항상 노출하여 상세 조회 트리거로 사용한다.
- 각 단계 상태가 **blocking**이면 다음 단계로 이동 불가.
- 트랜잭션에는 **여러 고객사**를 연결할 수 있음(역할 없음).
- 입고/출고/대여 트랜잭션은 최종 결재자가 승인 완료하기 전까지 기본 목록/완료 카드에 노출되지 않으며, 대기/임시 영역에서만 조회된다.
- 결재 문서는 상신자와 이미 결재를 완료한 승인자만 열람할 수 있고, 향후 단계 승인자는 자신의 순서가 도달하기 전까지 목록/상세 접근이 차단된다. (예: 상신→중간 승인 완료, 최종 승인 대기 시 상신자·중간 승인자만 열람 가능)
- 모든 로그인 사용자는 **users** 테이블 행과 매핑되며(`users.group_id`), 그룹-메뉴 권한(`group_menu_permissions`)으로 메뉴별 CRUD 가능 여부가 결정됨.
- `users.employee_id`는 영문/숫자 4~32자 정규식(`^[A-Za-z0-9]{4,32}$`)을 따라야 하며, 대소문자 구분 없이 유니크하다.
- 신규 사용자는 생성 직후 `force_password_change=true`로 저장하고, 최초 로그인에서 비밀번호를 변경하지 않으면 다른 기능을 사용할 수 없다.
@@ -408,6 +411,7 @@ zipcodes ||--o{ customers : addressed
> 번호 발급: 서버가 `TRX-YYYYMMDDNNNN` 형식으로 `transaction_no`를 생성하며 클라이언트 입력을 허용하지 않는다.
> 목록 조회는 `customer_id` 쿼리 파라미터를 지원해 특정 고객이 연결된 트랜잭션만 필터링할 수 있다. (2024-10 갱신)
> 작성자(`created_by_id`)는 로그인 세션의 사용자 ID를 사용하며, API 요청 본문에 전달된 다른 값은 무시하거나 검증 오류로 처리한다.
> 결재 최종 승인 완료 전에는 `transaction_statuses`가 `초안` 또는 `상신` 단계로 유지되며, 기본 입·출·대여 목록과 완료 카드에서는 제외한다. 대기/임시 전용 목록(필터 `status=draft|submitted`)에서만 확인 가능하다.
---
@@ -519,6 +523,8 @@ zipcodes ||--o{ customers : addressed
| updated_at | 변경일시 | timestamp | - | now() | Y | | | |
> 번호 발급: 서버가 `APP-YYYYMMDDNNNN` 형식으로 `approval_no`를 생성하며 클라이언트 입력을 허용하지 않는다.
> 상신자는 결재 초안을 저장하고 추후 재개할 수 있으며, 초안은 `결재 관리` 목록의 "임시저장" 필터로 조회한다.
> 열람 권한은 상신자와 이미 결재를 수행한 승인자에게만 부여되며, 도달하지 않은 단계의 승인자는 목록/상세/이력 API에서 403 또는 비노출로 처리한다. (예: 상신→중간 승인 완료, 최종 승인 대기 시 상신자·중간 승인자만 열람 가능)
---