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

@@ -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,