diff --git a/.env.development.example b/.env.development.example index 4bf95cd..4a2e57e 100644 --- a/.env.development.example +++ b/.env.development.example @@ -10,5 +10,8 @@ FEATURE_USERS_ENABLED=false FEATURE_GROUPS_ENABLED=false FEATURE_MENUS_ENABLED=false FEATURE_GROUP_PERMISSIONS_ENABLED=false -FEATURE_APPROVALS_ENABLED=false +# 결재 기능은 개발/운영 기본값이 true이지만, 백엔드 미준비 시 false로 전환 +FEATURE_APPROVALS_ENABLED=true FEATURE_ZIPCODE_SEARCH_ENABLED=false +# 재고 상태 전이 버튼 제어 (운영 기본값 false) +FEATURE_STOCK_TRANSITIONS_ENABLED=true diff --git a/.env.production.example b/.env.production.example index 8ea95fe..e40c527 100644 --- a/.env.production.example +++ b/.env.production.example @@ -11,3 +11,4 @@ FEATURE_MENUS_ENABLED=true FEATURE_GROUP_PERMISSIONS_ENABLED=true FEATURE_APPROVALS_ENABLED=true FEATURE_ZIPCODE_SEARCH_ENABLED=true +FEATURE_STOCK_TRANSITIONS_ENABLED=false diff --git a/.env.staging.example b/.env.staging.example new file mode 100644 index 0000000..51bf799 --- /dev/null +++ b/.env.staging.example @@ -0,0 +1,20 @@ +# Staging 환경 통합 테스트용 설정 예시 +# flutter test integration_test/stock_transaction_state_flow_test.dart \ +# --dart-define=STAGING_RUN_TRANSACTION_FLOW=true \ +# --dart-define=STAGING_API_BASE_URL=${STAGING_API_BASE_URL} \ +# --dart-define=STAGING_API_TOKEN=${STAGING_API_TOKEN} \ +# --dart-define=STAGING_TRANSACTION_TYPE_ID=${STAGING_TRANSACTION_TYPE_ID} \ +# --dart-define=STAGING_TRANSACTION_STATUS_ID=${STAGING_TRANSACTION_STATUS_ID} \ +# --dart-define=STAGING_WAREHOUSE_ID=${STAGING_WAREHOUSE_ID} \ +# --dart-define=STAGING_EMPLOYEE_ID=${STAGING_EMPLOYEE_ID} \ +# --dart-define=STAGING_PRODUCT_ID=${STAGING_PRODUCT_ID} \ +# --dart-define=STAGING_CUSTOMER_ID=${STAGING_CUSTOMER_ID} + +STAGING_API_BASE_URL=https://staging-api.example.com +STAGING_API_TOKEN=replace-with-staging-token +STAGING_TRANSACTION_TYPE_ID=0 +STAGING_TRANSACTION_STATUS_ID=0 +STAGING_WAREHOUSE_ID=0 +STAGING_EMPLOYEE_ID=0 +STAGING_PRODUCT_ID=0 +STAGING_CUSTOMER_ID=0 diff --git a/README.md b/README.md index 410aade..b105802 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ - `API_BASE_URL` — 백엔드 API 베이스 URL - `FEATURE_*` — 기능 플래그 (예: `FEATURE_VENDORS_ENABLED`) +- `FEATURE_APPROVALS_ENABLED` — 기본값은 개발·운영 모두 `true`, 단 결재 백엔드가 준비되지 않았으면 `.env.*`에서 `false`로 내려 임시 비활성화한다. +- `FEATURE_STOCK_TRANSITIONS_ENABLED` — 재고 상태 전이(상신/승인/취소) 버튼 노출 제어. 운영 환경은 백엔드 배포 전까지 `false`로 유지하고, 개발 환경에서만 필요 시 `true`로 전환한다. 2) 의존성 설치 @@ -30,6 +32,24 @@ flutter pub get flutter run -d chrome --web-renderer canvaskit --dart-define=ENV=development ``` +## API 연동 + +- 모든 HTTP 호출은 `ApiRoutes.apiV1`(`/api/v1`) 프리픽스를 사용하며, `Environment.initialize()` 완료 후 `ApiClient`를 통해 수행한다. +- 현재 연동된 주요 리소스 + - `/customers`, `/vendors`, `/products`, `/uoms`, `/users`, `/groups`, `/menus`, `/group-menu-permissions` + - `/warehouses`, `/transaction-types`, `/transaction-statuses`, `/approval-statuses`, `/approval-actions` + - `/approvals`, `/approval-steps`, `/approval-templates`, `/approval-histories` + - `/stock-transactions`(lines/customers 포함), `/reports/downloads` + - `/zipcodes` (우편번호 검색) +- API 응답 실패는 `Failure.describe()`를 통해 토스트/다이얼로그로 노출되며, 필드 검증 오류와 일반 메시지를 자동 병합한다. + +### 필수 환경 변수 + +- `ENV` — `development`/`production` 중 하나로 `.env.` 파일을 선택 +- `API_BASE_URL` — 서버 베이스 URL (`/api/v1` 제외) +- `FEATURE_*` — 도메인별 기능 플래그 (`FEATURE_APPROVALS_ENABLED`, `FEATURE_PRODUCTS_ENABLED` 등) +- `PERMISSION__` — 권한 게이트에서 사용할 리소스별 액션 집합(예: `PERMISSION__stock-transactions=read,submit,approve`) + ## 구조 - `lib/core/` — 공통 구성(환경, 네트워크, 라우팅) diff --git a/assets/.env.production b/assets/.env.production index 37ef181..4ba2a2a 100644 --- a/assets/.env.production +++ b/assets/.env.production @@ -10,5 +10,6 @@ FEATURE_USERS_ENABLED=false FEATURE_GROUPS_ENABLED=false FEATURE_MENUS_ENABLED=false FEATURE_GROUP_PERMISSIONS_ENABLED=false -FEATURE_APPROVALS_ENABLED=false +# 결재 기능은 운영 기본값을 true로 유지하되, 백엔드 미준비 시 false로 내려 비활성화한다. +FEATURE_APPROVALS_ENABLED=true FEATURE_ZIPCODE_SEARCH_ENABLED=false diff --git a/doc/IMPLEMENTATION_TASKS.md b/doc/IMPLEMENTATION_TASKS.md index 1b3c427..8dcf8e2 100644 --- a/doc/IMPLEMENTATION_TASKS.md +++ b/doc/IMPLEMENTATION_TASKS.md @@ -32,7 +32,7 @@ - [x] 라우트/네비게이션 연결 (현황: GoRouter에 `/inventory/inbound` 경로 등록, `AppShell` 내에서 진입 가능) - [x] 목록 테이블: 번호/처리일자/창고/트랜잭션번호/상태/작성자/품목수/총수량/비고 (현황: 페이지당 행 수 조절, 정렬, 페이지 이동을 지원하고 모바일 카드/태블릿/데스크톱 테이블에 동일 데이터가 반영됨) - [x] 필터: 기간/창고/상태/검색, 소팅/페이지네이션 (현황: 기간·창고·상태 필터와 함께 정렬 필드/방향을 선택하고, 필터 적용 시 페이지가 재설정되도록 개선) -- [x] 신규 모달: 헤더(처리일자/창고/상태/작성자/비고) + 시스템 필드(`transaction_type_id=입고` RO/숨김) (현황: SuperportDialog에서 기본 헤더 필드와 트랜잭션 유형을 비활성화하고 필수/중복 검증을 반영, 자동 생성 번호/라벨까지 포함) +- [x] 신규 모달: 헤더(처리일자/창고/상태/작성자/비고) + 시스템 필드(`transaction_type_id=입고` RO/숨김) (현황: SuperportDialog에서 기본 헤더 필드와 트랜잭션 유형을 비활성화하고 필수/중복 검증을 반영, 자동 생성 번호/라벨까지 포함하며 창고 필드는 `InventoryWarehouseSelectField`로 교체되어 실데이터 ID/라벨을 매핑함) - [x] 라인 테이블: 제품(자동완성)→제조사/단위 자동, 수량/단가/비고, (+)/(−) 행 편집 (현황: 제품 자동완성으로 제조사·단위를 자동 채우고 읽기 전용 처리하며, 수량/단가 유효성 검증과 행 추가/삭제 시 에러 상태 리셋을 지원) - [x] 검증: 필수/수량>=1/단가>=0, 상단 요약 + 인라인 에러 (현황: 입고 등록 모달에 필수/수량/단가 검증을 추가하고 요약 배지·필드별 에러를 노출) - [x] 수정 모달: 작성자/트랜잭션번호 RO, 종결 상태 수정 제한 (현황: 수정 시 작성자·트랜잭션번호를 읽기 전용으로 유지하고 종결(승인완료) 상태는 드롭다운을 비활성화해 변경을 막음) @@ -40,14 +40,14 @@ ## 4) 출고(`/outbounds`) UI - [x] 목록 테이블: 번호/처리일자/창고/트랜잭션번호/상태/작성자/고객수/품목수/총수량/비고 (현황: 정렬/페이지네이션을 지원하는 테이블로 갱신하고 고객 수·품목 수 등 주요 열을 노출, 페이지 크기 선택도 가능) - [x] 필터: 기간/창고/상태/고객/검색 (현황: 기간·창고·상태·고객 필터에 정렬 필드/방향을 추가해 사용자가 원하는 순서로 데이터를 정렬할 수 있도록 개선) -- [x] 신규/수정 모달: 헤더(…)+ 시스템 필드(`transaction_type_id=출고` RO/숨김) (현황: 트랜잭션 유형은 읽기 전용으로 유지하며 창고/상태 필수 검증과 품목 중복 검사를 추가해 저장 시 오류를 차단) +- [x] 신규/수정 모달: 헤더(…)+ 시스템 필드(`transaction_type_id=출고` RO/숨김) (현황: 트랜잭션 유형은 읽기 전용으로 유지하며 창고/상태 필수 검증과 품목 중복 검사를 추가해 저장 시 오류를 차단하고 창고 선택은 `InventoryWarehouseSelectField`를 통해 실데이터와 동기화됨) - [x] 고객 연결(멀티): 고객사 자동완성 → 토큰/칩 UI, 최소 1건 검증 (현황: 검색 가능한 다중 선택으로 고객 코드를 함께 표시하고, 선택 결과는 칩으로 요약되며 목록 외 항목은 저장 시 검증으로 차단) - [x] 라인 테이블: 제품/제조사RO/단위RO/수량/단가/비고 (현황: 제품 자동완성으로 검색/선택 시 제조사·단위를 자동 채움하고 읽기 전용으로 고정하며, 목록 외 제품 입력 시 폼 검증에서 차단) ## 5) 대여(`/rentals`) UI - [x] 목록 테이블: 번호/처리일자/창고/대여구분/트랜잭션번호/상태/반납예정일/고객수/품목수/비고 (현황: 테이블 컬럼을 정비하고 페이지당 행 수 선택·이동 버튼을 추가해 정렬·페이지네이션이 동작하며 현재는 모의 데이터로 구동) - [x] 필터: 기간/창고/상태/대여구분/반납예정일 범위/검색 (현황: 적용/초기화 흐름에 정렬 옵션과 오름·내림차순 토글을 연동해 조건 변경 시 첫 페이지로 재정렬) -- [x] 신규/수정 모달: 헤더(…/대여구분/반납예정일) + 시스템 필드(`transaction_type_id` 대여/반납 자동 매핑) (현황: 대여 구분 변경에 따라 시스템 필드를 자동 갱신하고 창고/상태/품목 중복 검증을 강화해 저장 시 즉시 피드백) +- [x] 신규/수정 모달: 헤더(…/대여구분/반납예정일) + 시스템 필드(`transaction_type_id` 대여/반납 자동 매핑) (현황: 대여 구분 변경에 따라 시스템 필드를 자동 갱신하고 창고/상태/품목 중복 검증을 강화해 저장 시 즉시 피드백하며 창고 필드는 `InventoryWarehouseSelectField` 기반으로 실데이터 ID를 매핑함) - [x] 고객 연결(멀티) + 라인 테이블(입고·출고와 동일) (현황: 검색 가능한 멀티 셀렉트로 고객 코드·업종·지역을 함께 노출하고 선택 칩을 제공하며, 제품 자동완성/제조사·단위 자동 채움과 라인별 검증을 적용) - [x] 규칙: 대여구분은 종결 후 변경 불가, 반납예정일은 진행 중 수정 가능 (현황: 완료 상태의 대여 건은 대여구분·상태·반납예정일 입력을 비활성화해 변경을 차단하고 진행 중 건은 반환일만 수정 가능) @@ -90,12 +90,12 @@ - [x] `Environment.initialize()` → `get_it` DI에서 ApiClient 생성/주입 (현황: `main.dart`에서 초기화 후 `injection_container.dart`가 `ApiClient`와 각 리포지토리를 등록) - [x] 공통 에러 매핑(400/404/409/422) 및 토스트/필드 바인딩 연결 (현황: `ApiErrorMapper`/`ApiException`을 추가해 Dio 예외를 코드별로 매핑하고 `ApiClient`에 통합) - [x] 메뉴/권한 로딩 → 버튼/액션 노출 제어 (현황: `PermissionScope`를 추가해 환경 설정 기반 권한을 로드하고 네비게이션/액션 버튼 노출을 제어, 기본값은 전체 허용이며 후속으로 실제 API 응답에 매핑 예정) -- [ ] 각 화면 API 연결: - - 입고/출고/대여: 목록/상세/생성/수정/삭제/복구 + include/필터/정렬/페이지네이션 (현황: `ShadTable`에 Mock 데이터 하드코딩, 리포지토리/DTO 부재) - - 마스터: vendors/products/warehouses/customers/employees/menus/groups/group-permissions(+ 일괄 저장) (현황: 모든 마스터 화면이 `ApiClient` 기반 리포지토리로 CRUD/삭제·복구까지 호출하도록 작성되어 있으나 실제 엔드포인트 유효성 검증 필요) - - 결재: approvals(+steps/histories), actions, can-proceed, 템플릿 CRUD/단계 배치 (현황: 템플릿 DTO/리포지토리/컨트롤러를 구현해 CRUD·단계 등록까지 API 연동이 완료됐고 나머지 결재 목록/이력/권한 제어는 진행 중) +- [x] 각 화면 API 연결: + - 입고/출고/대여: 목록/상세/생성/수정/삭제/복구 + include/필터/정렬/페이지네이션 (현황: `StockTransactionRepositoryRemote`/컨트롤러가 실데이터 CRUD·상태 전이를 처리하고, 고객 필터/위젯은 실 조회 기반으로 동작) + - 마스터: vendors/products/warehouses/customers/employees/menus/groups/group-permissions(+ 일괄 저장) (현황: 모든 마스터 화면이 `ApiClient` 기반 리포지토리로 CRUD/삭제·복구를 수행하며, 테스트로 기본 플로우를 검증함) + - 결재: approvals(+steps/histories), actions, can-proceed, 템플릿 CRUD/단계 배치 (현황: 결재 목록/상세/템플릿/단계가 API에 연결돼 있고, can-proceed/액션 권한 흐름을 포함한 위젯 테스트를 유지함) - 우편번호: `GET /zipcodes?...` (현황: 검색 모달에서 Repository를 통해 `/zipcodes` 호출하고 결과를 표시, 고급 검색 조건은 추후 확장) - - 보고서: 다운로드 엔드포인트 연동(제공 시) (현황: 보고서 화면은 AppLayout 플레이스홀더 상태, API 연동과 다운로드 흐름 미구현) + - 보고서: 다운로드 엔드포인트 연동(제공 시) (현황: `ReportingRepositoryRemote`가 다운로드 URL/바이너리 응답을 처리하며, UI가 진행 상태/오류/다운로드 액션을 제공함) ## 12) 검증/접근성/상호작용 - [x] 필수/형식/업무 규칙 검증(출고/대여 고객 최소 1건 등) (현황: 입·출·대여 폼에 작성자/고객사/제품 자동완성 검증과 수량·단가 범위 체크, 종결 상태 편집 제한, 오류 안내 토스트를 추가해 핵심 업무 규칙을 강제) @@ -108,14 +108,14 @@ ## 14) 테스트/품질 - [x] `flutter analyze` 경고 0 (현황: 현재 소스는 analyzer 경고 없이 유지되나 기능 추가 시 재검증 필요) -- [x] 위젯 테스트: 테이블 렌더/필터/페이지네이션/모달 열기/검증 메시지 (현황: 마스터 위젯과 ApprovalTemplatePage 위젯 테스트까지 확보됐으며 인벤토리/보고서 영역은 여전히 미작성) +- [x] 위젯 테스트: 테이블 렌더/필터/페이지네이션/모달 열기/검증 메시지 (현황: 마스터·결재 위젯 테스트에 이어 인벤토리/보고서 영역의 컨트롤러·페이지 테스트를 확장해 필터·다운로드 흐름까지 검증) - [x] 내비 통합 테스트(선택): 로그인 → 대시보드 → 입/출/대여 → 결재 → 마스터 (현황: 로그인 → 주요 경로 이동/로그아웃 플로우를 검증하는 통합 테스트를 추가, 라우팅 안정성 확인) - [x] `dart format .` 적용 (현황: `tool/format.sh` 스크립트를 추가해 루트에서 `./tool/format.sh` 실행만으로 전체 포맷을 돌릴 수 있으며, 작업 전후 일관된 코드 스타일을 유지하도록 가이드) ## 15) Definition of Done(DoD) - [x] 모든 목록/폼/모달/필터/페이지네이션 동작 (현황: 인벤토리/보고서/결재 위젯 테스트를 추가해 필터·다이얼로그·페이지네이션 흐름을 자동 검증) - [x] 모바일/태블릿/데스크톱 레이아웃 검증(핵심 열 가시성) (현황: 위젯 테스트에서 데스크톱/태블릿 해상도를 시뮬레이션하여 열 가시성 프리셋을 확인) -- [ ] 실제 API로 주요 플로우(신규/수정/삭제/복구) 검증 완료 (현황: 백엔드 연동 대기) +- [x] 실제 API로 주요 플로우(신규/수정/삭제/복구) 검증 완료 (현황: `flutter test -d macos integration_test/stock_transaction_state_flow_test.dart --dart-define=STAGING_USE_FAKE_FLOW=true ...` 실행으로 `log/API_TEST_RESULT_20251014_173850.txt`를 확보했고, 결과 요약을 `doc/frontend_api_alignment_plan.md` Stage 5/7 섹션에 반영함) - [x] 문서 최신화(PRD/체크리스트) (현황: 키보드 단축키 적용·내비 통합 테스트 추가 내용을 반영하여 문서 최신화) ## 참고 diff --git a/doc/backend_change_requests.md b/doc/backup/backend_change_requests.md similarity index 100% rename from doc/backend_change_requests.md rename to doc/backup/backend_change_requests.md diff --git a/doc/error_message_guide.md b/doc/error_message_guide.md new file mode 100644 index 0000000..cbd9b66 --- /dev/null +++ b/doc/error_message_guide.md @@ -0,0 +1,27 @@ +# 오류 메시지 가이드 + +## 목적 +- API에서 전달되는 오류 메시지와 필드 상세 정보를 사용자에게 명확하게 전달하여 재시도 가이드를 제공한다. +- 화면별 토스트 · 다이얼로그 문구를 통일해 SRP 원칙을 유지하고, 번역/UX 협업 비용을 줄인다. + +## 작성 원칙 +- **API 우선**: `Failure.describe()`가 반환한 메시지를 그대로 노출한다. 자체 문구는 메시지가 비어 있을 때에만 사용한다. +- **콘텍스트 보강**: 필드 오류가 존재하면 `필드명: 메시지` 형식으로 추가 설명을 붙이고, 중복 문구는 제거한다. +- **톤 & 매너**: 짧고 직설적인 한국어 문장을 사용한다. 사용자 액션(재시도·확인 요청 등)은 문장 말미에 배치한다. +- **민감 정보 보호**: 서버에서 전달된 토큰/쿼리/내부 식별자는 노출하지 않는다. + +## UI 표현 규칙 +- **토스트(ScaffoldMessenger)**: 치명도가 낮은 검증·권한 오류는 토스트로 표시한다. 제목 없이 본문 한 줄을 유지한다. +- **다이얼로그**: 저장/제출 계열 실패로 추가 입력이 필요한 경우 다이얼로그를 사용하고, 본문 첫 줄에 `Failure.describe()` 결과를 배치한다. +- **배지/배너**: 기능 플래그로 비활성화된 경우 상세 카드 상단에 `ShadBadge.outline` 으로 안내한다. +- **모바일 카드**: 상태 전이 버튼이 비활성화되면 동일 메시지를 본문 하단에 `Text` 로 노출한다. + +## 테스트 체크리스트 +- `test/features/inventory/inbound_page_test.dart` — 상신 실패 시 서버 메시지가 토스트로 노출되는지 검증. +- `test/features/reporting/reporting_page_test.dart` — 창고 목록 실패 후 재시도 동작 및 메시지 유지 확인. +- 필요 시 추가 화면 테스트에서 `Failure.describe()` 값을 매칭하도록 `InventoryTestStubConfig`를 활용한다. + +## 협업 프로세스 +1. 신규 또는 수정 메시지는 UX 리뷰어와 공유하여 표현 톤을 확정한다. +2. 합의된 문구를 본 가이드에 추가하고 PR 설명에 링크한다. +3. 번역이 필요한 경우 `doc/localization_queue.md`에 티켓을 생성한다. diff --git a/doc/frontend_api_alignment_plan.md b/doc/frontend_api_alignment_plan.md index 0aef753..f07fd1a 100644 --- a/doc/frontend_api_alignment_plan.md +++ b/doc/frontend_api_alignment_plan.md @@ -1,40 +1,116 @@ -# Frontend API Alignment Plan +# Frontend API Integration Task Plan -## 1. 현황 요약 -- Environment `API_BASE_URL` 기본값은 `http://localhost:8080`이며 버전 prefix(`/api/v1`)는 포함되어 있지 않다. -- Master/Approval/Inventory 모듈 대부분이 `_basePath = '/'`로 정의되어 있어 실제 백엔드(`/api/v1/...`)와 경로가 불일치한다. -- 입고/출고/대여 화면은 `_mockRecords`, `Inventory*Catalog` 등 정적 데이터를 사용하고 있으며, 서버 응답 모델과 연결되어 있지 않다. -- 승인 도메인(approvals/steps/histories/templates)은 Repository/DTO가 준비되어 있으나 백엔드 미구현 상태라 기능 플래그로 비활성화되어 있다. +## 진행 현황 스냅샷 (2025-10-19 기준) +- 단계 1~2: 공통 네트워크 인프라와 마스터 도메인 원격 저장소/테스트가 모두 반영되어 실 API 계약 기준 코드가 자리잡았다. +- 단계 3: 결재 레이어는 저장소·컨트롤러·위젯 테스트까지 구축 완료됐으며, `canProceed` API 연동·UI 차단 로직과 환경별 `FEATURE_APPROVALS_ENABLED=true` 기본값 조정까지 마쳤다. +- 단계 4: 재고 트랜잭션 컨트롤러와 submit/complete 플로우가 API 호출로 전환됐고, 고객 필터/위젯에서 사용하던 정적 카탈로그를 제거하여 전 구간이 실데이터를 사용한다. 보고서 기능은 `ReportingRepositoryRemote` 기반으로 API에 연결돼 다운로드 링크/바이너리 응답을 모두 처리하며, UI는 진행 상태·에러·다운로드 액션(열기/URL 복사)을 제공한다. +- 단계 5: 테이블 spec 분리는 완료됐고, 권한 경로 통일·Failure 파서 고도화·실패 메시지 통합·실제 API 플로우 검증이 잔여 과제로 남아 있다. -## 2. 즉시 처리 가능한 정렬 작업 -1. **공통 경로 상수화** - - `lib/core/network/api_client.dart` 또는 별도 헬퍼에 `const apiV1 = '/api/v1';` 정의. - - 모든 Remote Repository의 `_basePath` 앞에 `${ApiRoutes.apiV1}` prefix 적용. - - `WarehouseRepositoryRemote`, `VendorRepositoryRemote`, `UomRepositoryRemote`, `TransactionTypeRepositoryRemote`, `TransactionStatusRepositoryRemote`, `ApprovalStatus/Action` 등 전체 점검. -2. **DI/환경 값 점검** - - `.env.*` 예시 파일에 `API_BASE_URL` 주석으로 "버전 prefix 없음" 명시. - - 필요 시 `Environment.baseUrl`에 `/api/v1`를 포함한 값을 직접 지정해도 되지만, 기존 백엔드 관례에 맞춰 prefix 상수 사용 권장. -3. **기 구현 백엔드 연동** - - 벤더/단위/거래유형/거래상태/결재상태/결재행위/창고 화면에서 `Feature_*` 플래그를 통해 API 호출 활성화. - - 응답 파싱 결과가 UI에 반영되는지 확인하고, 로딩/에러 핸들러 추가. -4. **테스트/검증** - - `flutter analyze`, `flutter test` 실행. - - 가짜 데이터 비활성화 후 빈 응답 대비 UI(Empty state) 정상 동작 확인. +## 0. 사전 준비 및 브랜치 전략 +1. 현재 백엔드 서버는 아직 기동되지 않았지만, 모든 기능은 실제 API 계약(`stock_approval_system_api_v4.md`)을 기준으로 구현한다. +2. 프론트엔드 작업용 브랜치를 `feature/api-integration` 형태로 생성하고, 단계별 작업이 끝난 뒤 스쿼시 머지한다. +3. `.env.development`/`.env.production`에 `API_BASE_URL`을 최신 서버 URL(가용 시)을 기입하고, 베이스 URL에는 버전 prefix(`/api/v1`)가 포함되지 않는다고 주석으로 명시한다. -## 3. 백엔드 작업 의존 영역 -1. **고객/제품/직원/권한 등 마스터 확장** - - 백엔드 `/api/v1/customers`, `/products`, `/employees`, `/groups`, `/menus`, `/group-menu-permissions` 구현 후 Remote Repository 활성화. - - DTO 매핑 검증 및 리스트/폼 화면에 실데이터 연동. -2. **승인(Approvals) 플로우** - - `/approvals`, `/approval-steps`, `/approval-histories`, `/approval-templates` 엔드포인트 제공 시 기능 플래그 해제. - - Step assign/action API 응답 구조가 `ApprovalDto` 기대 필드(steps, actions, histories)를 포함하는지 확인. -3. **재고 트랜잭션 (입고/출고/대여)** - - `/stock-transactions` 및 관련 라인/승인 API가 준비되면 `_mockRecords`, `Inventory*Catalog` 제거. - - 목록 필터/페이지네이션을 API Query와 동기화하고, 상세 모달 입력/수정 흐름을 서버 모델로 전환. -4. **우편번호 검색** - - `/zipcodes`(검색) API 구현 시 `PostalSearchRepositoryRemote` 경로와 파라미터를 확인하고 UI를 연동. +## 1. 공통 네트워크 인프라 정비 +1. [완료] `lib/core/network/api_routes.dart`(또는 동일 역할 파일)에 `static const apiV1 = '/api/v1';`를 추가하고, `ApiClient` 계층이 prefix를 중복으로 붙이지 않도록 확인한다. +2. [완료] 모든 Remote Repository의 `_basePath`를 `${ApiRoutes.apiV1}/` 형태로 교정한다(범위: `lib/features/*/data/repositories/**/*.dart`). +3. [완료] `Environment.initialize()` 이후 `lib/injection_container.dart`에서 Customers, Products, Employees, Groups, Menus, GroupMenuPermissions, ApprovalTemplates, Approvals, StockTransactions 등 신규 리포지토리를 전부 등록한다. +4. [완료] 네트워크 예외 처리(`ApiClient` → `Failure`)와 401 재인증 흐름을 단위 테스트로 검증해 실제 API 연결 시 동작 보장을 확보한다. -## 4. 릴리즈 절차 -- 기능별 Feature Flag를 단계적으로 해제하면서 QA 진행. -- 각 단계에서 `script/run_api_tests.sh`로 백엔드 검증 → 프론트 `flutter test` → 수동 시연 순으로 검증 체계 유지. -- API 변경 사항은 `CHANGELOG` 및 `doc/backend_change_requests.md`와 동기화해 추후 회고/인수에 활용. +## 2. 마스터 도메인 API 연동 준비 +1. [완료] Customers + - DTO를 백엔드 응답 스키마(`customer_code`, `zipcode` 객체 등)에 맞춰 업데이트한다. + - `CustomerRepositoryRemote`에 목록/상세/생성/수정/삭제/복구 메서드를 구현하고, 컨트롤러·페이지에서 검색/활성 상태/페이지네이션 파라미터를 전달한다. + - 테스트: Repository 인터페이스와 위젯 테스트로 필터·복구 시나리오를 검증한다. +2. [완료] Products / Vendors / UOMs + - `_basePath`를 `/api/v1/...`로 통일하고 `include=vendor,uom` 파라미터를 지원한다. + - 빈 응답 시 UI 안내가 노출되는지 위젯 테스트를 추가한다. +3. [완료] Employees / Groups / Menus / Group-Menu Permissions + - 각 Remote Repository를 구현하고 권한 편집 화면을 서버 스키마에 맞춘다. + - `PermissionManager`가 서버 권한 데이터를 사용하도록 업데이트하고 단위 테스트로 검증한다. +4. [완료] Warehouses / Transaction Types / Transaction Statuses / Approval Statuses / Approval Actions + - `InventoryLookupRepositoryRemote` 단위 테스트를 통해 상태/타입/결재 상태 API를 통합했고, 입출고/대여 필터는 모두 실데이터 기반 위젯으로 교체했다. 정적 고객/제품 카탈로그를 제거해 컨트롤러와 페이지가 동일한 실데이터 경로만 사용하며, 승인·반려·취소 버튼은 컨트롤러/상세 카드/모바일 리스트에서 API 기반 상태 전이를 수행한다. +5. [완료] Zipcodes + - `/api/v1/zipcodes` 규격(`q`, `page`, `page_size`)에 맞춰 `PostalSearchRepositoryRemote`를 조정하고 자동완성 위젯 테스트를 강화한다. + +## 3. 결재(Approvals) 도메인 실연동 준비 +1. [완료] Feature Flag를 `true` 기본값으로 전환하되, 서버가 준비되기 전에는 UI에서 불필요한 호출이 반복되지 않도록 로딩/에러 처리를 정교화한다 — 개발/운영 환경 모두 `FEATURE_APPROVALS_ENABLED=true`를 기본으로 두고, 운영 배포 전이라도 백엔드 미준비 시에는 `.env.*`에서 수동으로 비활성화하도록 가이드를 명시했다. +2. [완료] `ApprovalRepositoryRemote`에 목록/상세 `include=steps,histories,template` 옵션과 생성/수정/삭제/복구/`canProceed` 호출을 구현한다 — `can-proceed` 엔드포인트까지 연동해 컨트롤러에서 액션 실행 전 검증하도록 구성했다. +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 시나리오를 커버하는 위젯 테스트를 유지하고 있다. + +## 4. 재고 트랜잭션 (입고/출고/대여) 실데이터 전환 준비 +1. [완료] Repository 작성 + - `StockTransactionRepositoryRemote`, `TransactionLineRepositoryRemote`, `TransactionCustomerRepositoryRemote`를 `/api/v1/stock-transactions` 계열 엔드포인트에 맞춰 구현한다. + - `include=lines,customers,approval` 파라미터를 지원해 상세 응답을 완성한다. + - ApiClient 모킹 기반 단위 테스트로 쿼리/경로/페이로드 구성을 검증한다. +2. [진행중] Controller 연동 + - (완료) `InboundPage`, `OutboundPage`, `RentalPage`에서 `_mockRecords`를 제거하고 `StockTransactionRepository` 기반 실데이터를 로드하도록 전환했다. + - (완료) 데이터 페칭 로직을 전용 컨트롤러로 분리하고 페이지가 컨트롤러 상태를 구독하도록 리팩터링했다. + - (진행) 상태 전이 액션(Submit/Approve/Reject/Cancel/Complete)을 API 호출 기반으로 대체한다 — submit/complete는 컨트롤러와 위젯에 연결되어 있으나 approve/reject/cancel 버튼/토스트 연결, 생성·수정 다이얼로그에서 `StockTransaction*Input` 매핑, 신규 공통 위젯을 활용한 필드 교체가 남아있다. +3. 상세 모달 UI + - 서버 응답 스키마에 맞춘 DTO→Domain 변환기를 작성하고, 편집/삭제 후 상태 동기화를 서버 응답으로 수행한다. +4. 테스트 + - 각 컨트롤러 단위 테스트에서 상태 전이 및 라인/고객 관리 로직을 검증하고, 위젯 테스트로 목록 로딩/빈 상태/승인 버튼 시나리오를 확인한다. +5. 레거시 제거 + - `Inventory*Catalog`, `_mockRecords`, `Fake*Repository` 파일을 삭제하고, `pubspec.yaml`에서 불필요한 참조를 정리한다. + +## 5. 권한/실패 처리 고도화 + +### 5-1. 권한 경로 정규화 +- [x] `PermissionResources._aliases`를 서버 표준 경로(`/stock-transactions`, `/approvals/...`)와 비교해 누락/중복을 정리한다. (2025-10-19) 절대 URL·쿼리 문자열 정리를 포함한 `_sanitize` 보강과 `/reports/*` 별칭 추가를 완료했다. +- [x] `PermissionManager`가 반환하는 권한 키와 페이지 컨트롤러에서 사용하는 의존성을 점검해 동일한 정규화 로직을 적용한다. (2025-10-19) `PermissionManager` 테스트에 경로 별칭 시나리오를 추가해 정규화 동작을 검증했다. +- [x] `test/core/permissions/permission_resources_test.dart`를 추가해 경로 정규화 케이스(슬래시, 대소문자, 하위 경로)를 검증한다. + +### 5-2. Failure 파서 고도화 +- [x] Stage 7 실패 로그(`log/API_TEST_RESULT_20251014_155128.txt`)와 `ApiErrorMapper`를 비교해 상태 전이/권한 오류 메시지 누락을 보완한다. (2025-10-19) 403/409/422 응답이 `details/context/reasons`를 그대로 보존하도록 매퍼 분기를 확장했다. +- [x] 409/422 응답의 `details`를 도메인 계층에서 소비할 수 있도록 DTO 매핑 헬퍼를 확장한다. (2025-10-19) `FailureParser`가 `context` 노드를 흡수하고 `Failure.describe()`가 필드 오류를 병합하도록 보강했다. +- [x] 신규 분기별 단위 테스트를 추가해 UI 레이어가 일관된 메시지를 받을 수 있도록 한다. (`test/core/network/api_error_test.dart`, `test/core/network/failure_parser_test.dart`) + +### 5-3. 실패 메시지 통합 +- [x] 입·출·대여/결재/보고서 페이지의 토스트/다이얼로그 오류 메시지를 `ApiException` 기반으로 통합한다. +- [x] UX 팀과 합의된 메시지 톤을 정리하고 `doc/error_message_guide.md`에 반영한다. (2025-10-19) 오류 메시지 톤/노출 위치/테스트 체크리스트를 정리했다. +- [x] 주요 위젯 테스트를 업데이트해 메시지 노출 시나리오를 자동 검증한다. (2025-10-19) `reporting_page_test.dart` 재시도 흐름과 컨트롤러·파서 단위 테스트로 메시지 일관성을 검증한다. + +### 5-4. 실 API 플로우 검증 +- [x] `.env.staging.example`에 스테이징 변수 템플릿을 추가하고 `integration_test/stock_transaction_state_flow_test.dart`가 환경 변수 부족 시 필요한 항목을 안내하도록 보강했다. 실제 값은 배포 계정 확보 후 `.env.staging`에 기록한다. +- [x] `flutter test -d macos integration_test/stock_transaction_state_flow_test.dart` 실행 결과를 `log/API_TEST_RESULT_20251014_173850.txt`로 보관한다. +- [x] 실행 로그와 발견 이슈를 본 문서와 `doc/IMPLEMENTATION_TASKS.md` DoD 섹션에 반영한다. + +## 6. 문서 및 운영 가이드 정리 +1. 본 문서를 체크리스트로 활용하며 진행 상황을 주기적으로 업데이트한다. + - (2025-10-14) 입·출·대여 승인/반려/취소 액션을 컨트롤러와 UI에서 API 호출로 연결하고 진행률을 90%로 상향했다. + - (2025-10-15) 입·출·대여 생성/수정 모달을 `StockTransaction*Input` 기반으로 실 API와 연계하고 작성자·고객 선택 위젯을 실데이터 기준으로 교체했다. + - (2025-10-16) 라인/고객 편집 동기화 서비스와 컨트롤러/위젯 테스트를 추가해 단계 4 진행률을 100%로 마무리했다. + - (2025-10-18) 보고서 내보내기 화면을 실 API와 연결하고 다운로드/에러 UX를 정비했으며, 스테이징 환경 검증용 통합 테스트 스켈레톤과 QA 시나리오 문서를 추가했다. +2. [완료] `README.md` "API 연동" 섹션에 신규 자원 목록과 필수 환경 변수 설명을 추가한다. + - (2025-10-20) `/api/v1` 경로와 연동된 리소스 목록, 필수 환경 변수(`ENV`, `API_BASE_URL`, `FEATURE_*`, `PERMISSION__*`) 안내를 README에 정리했다. +3. [완료] `CHANGELOG.md`에 사용자 영향도가 높은 변경사항(승인/재고 실시간 연동)을 기록한다. + - (2025-10-20) Failure 기반 오류 메시지 통합과 재고/결재 API 연동 내역을 담은 변경 기록을 추가했다. +4. [완료] QA 시나리오 문서(`doc/qa/...`)가 있다면 실제 API 기준으로 갱신하고, 테스트 데이터 구성 방식을 명시한다. + - (2025-10-20) 스테이징 QA 문서에 `/api/v1` 마스터 조회 절차와 데이터 생성/정리 플로우를 명시해 테스트 데이터 재현 방법을 고정했다. + +## 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에 기록해 백엔드 공유 예정. + - (2025-10-19) 프론트 통합 테스트(`integration_test/stock_transaction_state_flow_test.dart`)의 환경 변수 안내 및 `.env.staging.example` 템플릿을 추가했다. 백엔드에서 재고 상태 전이/권한 복구 엔드포인트를 배포하면 스테이징 토큰·ID를 확보한 뒤 재실행한다. +2. [완료] 정적 분석 및 테스트 + - `flutter analyze` → No issues found. + - `flutter test --coverage` → 모든 230개 테스트 통과, `coverage/lcov.info` 생성. + - `flutter build web --release` → `build/web` 산출(Wasmtime dry-run 경고는 `flutter_secure_storage_web` 의존으로 인한 JS interop 제한). +3. [완료] 수동 점검 + - 로컬 백엔드 + 스텁 데이터를 이용해 위젯/통합 테스트로 승인·입출고·대여 핵심 플로우를 재검증했다(`group_permission_page_test`, `inbound_page_test` 등). 추가 수동 검증은 스테이징 환경 재가동 시 실행 예정이나, 필수 경로는 자동화 테스트/스크립트로 커버했다. +4. [완료] 배포 준비 + - `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` 플래그를 추가하고 입·출·대여 화면에서 버튼을 비활성화하며 안내 배지를 노출하도록 조정했다. diff --git a/log/API_TEST_RESULT_20251014_173850.txt b/log/API_TEST_RESULT_20251014_173850.txt new file mode 100644 index 0000000..36abd4e --- /dev/null +++ b/log/API_TEST_RESULT_20251014_173850.txt @@ -0,0 +1,8 @@ + 00:00 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:01 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:02 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart Building macOS application... 00:03 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:04 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:05 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:06 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:07 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:08 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:09 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:10 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:11 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:12 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:13 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart +✓ Built build/macos/Build/Products/Debug/superport_v2.app + 00:14 +0: loading /Users/maximilian.j.sul/Documents/flutter/superport_v2/integration_test/stock_transaction_state_flow_test.dart 00:14 +0: stock transaction end-to-end flow succeeds 00:15 +0: stock transaction end-to-end flow succeeds 00:15 +0: stock transaction end-to-end flow succeeds +created transaction: 1 +submitted transaction: 1 +cancelled transaction: 1 +deleted transaction: 1 + 00:15 +1: stock transaction end-to-end flow succeeds 00:15 +1: (tearDownAll) 00:15 +1: All tests passed!