Files
superport_v2/doc/approval_flow_alignment_review.md
JiWoong Sul d76f765814 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
2025-10-31 01:05:39 +09:00

80 lines
9.2 KiB
Markdown

# 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 체크리스트에 반영 상황을 기록한다.