--- type: concept status: stable related_pages: ["[[B01_Dashboard/B01_backend]]", "[[B02_ProjRegister/B02_backend]]", "[[B03_FileInput/B03_backend]]", "[[B04_wf1_Surface/B04_backend]]", "[[B05_wf2_Route/B05_backend]]", "[[B06_wf3_ProfileCross/B06_backend]]", "[[B07_wf4_DesignDetail/B07_frontend]]", "[[B08_wf5_Quantity/B08_frontend]]", "[[B09_wf6_Estimation/B09_frontend]]"] last_updated: 2026-07-12 source: raw/plans/plan_workflow_state_management.md (계획, 2026-07-10) + 실 코드/DB 직접 확인 (2026-07-12) --- # Workflow 상태 관리 — 구현 완료 (실 DB 확인됨) > **status: stable.** 2026-07-12 실 코드 전수 확인 + DB 직접 접속(`SHOW TABLES`/`DESCRIBE`)으로 검증. 계획서(2026-07-10)의 설계가 **B01~B06 전 단계에 이미 적용 완료**됨. 정식 검증보고서는 없지만 코드·DB 실측이 계획과 일치해 stable로 채택. 남은 잔재 1건은 아래 참고. ## SSOT: `project_workflow_stages` 테이블 (실 DB 확인) | 컬럼 | 타입 | | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | id | INT PK | | project_id | CHAR(36), FK | | stage_no | TINYINT (0~6) | | stage_key | VARCHAR(30) — FILE_INPUT/WF1_SURFACE/WF2_ROUTE/WF3_PROFILE_CROSS/WF4_DESIGN_DETAIL/WF5_QUANTITY/WF6_ESTIMATION | | state | ENUM('NOT_STARTED','IN_PROGRESS','COMPLETE','FAILED','STALE') | | progress_percent | TINYINT | | params | LONGTEXT(JSON) — 재실행 시 폼 프리필용 | | message, started_at, completed_at, updated_at | 진행/이력 | 생성 SQL: `db_management/006_workflow_state.sql`, 백필: `db_management/migrate_workflow_state.py` (기존 프로젝트 `projects.status` 해석 후 시드) ## 공통 유틸 `common_util/common_util_workflow_state.py` | 함수 | 역할 | |---|---| | `initialize_project_stages(cursor, project_id)` | 프로젝트 생성 시 7행 NOT_STARTED 시드 | | `start_stage(cursor, project_id, stage_no, params)` | IN_PROGRESS 전이 + N+1~6의 COMPLETE를 STALE로 전파 + `projects.status` 캐시 갱신 | | `complete_stage(cursor, project_id, stage_no)` | COMPLETE 전이 (stage 6 완료 시 `projects.status='DONE'`) | | `fail_stage(cursor, project_id, stage_no, message)` | FAILED 전이 | | `update_stage_progress(cursor, project_id, stage_no, progress)` | 진행률만 갱신 | | `get_workflow_state(cursor, project_id)` | 단건 조회, `current_stage` 계산 포함 | ## 실 연동 현황 (파일:줄번호) | 페이지 | 위치 | 연동 stage_no | |---|---|---| | [[B02_ProjRegister/B02_backend|B02_ProjRegister]] | `B02_ProjRegister_Repository.py:90` `initialize_project_stages` 호출 | 시드(0~6) | | [[B03_FileInput/B03_backend|B03_FileInput]] | `B03_FileInput_Router.py:175,224,256,347,570` | stage 0, 1 | | [[B04_wf1_Surface/B04_backend|B04_wf1_Surface]] | `B04_wf1_Surface_Router.py:168,209,227,233` | stage 1 | | [[B05_wf2_Route/B05_backend|B05_wf2_Route]] | `B05_wf2_Route_Router.py:51,96,112,117,122,128,152` | stage 2 | | [[B06_wf3_ProfileCross/B06_backend|B06_wf3_ProfileCross]] | `B06_wf3_ProfileCross_Router.py:68,111,127,132,137,143,187` | stage 3 | | [[B01_Dashboard/B01_backend|B01_Dashboard]] | `B01_Dashboard_Repository.py:83` `get_workflow_states_for_projects()` (배치 조회, 프로젝트 목록에 `workflow_state` 필드 포함) | 조회 전용 | ## 조회 API (실제 존재, 계획서와 경로 일치) `GET /{project_id}/workflow-state` — `B03_FileInput_Router.py:667` ```json {"status": "success", "workflow_state": {"project_id": "...", "current_stage": 2, "stages": [...]}} ``` 실제 전체 경로는 B03 라우터 prefix를 포함한 `/api/projects/{project_id}/workflow-state`이다. ## 상태 전이 (구현대로) ``` NOT_STARTED → IN_PROGRESS → COMPLETE └→ FAILED → (재실행) IN_PROGRESS COMPLETE → (하위 단계 재작업) → STALE → (재실행) IN_PROGRESS ``` stage N이 IN_PROGRESS 전이 시 N+1~6의 COMPLETE를 전부 STALE로 전파 (`start_stage` 내부 UPDATE 쿼리로 확인됨). ## projects.status 문자열 캐시 (호환용, 계획서 방침대로 유지 중) `start_stage`/`complete_stage`/`fail_stage`가 `project_workflow_stages`와 `projects.status`를 **동시에** 갱신 (`WF{n}_ANALYZING`/`WF{n}_COMPLETE`/`WF{n}_FAILED`, stage6 COMPLETE 시 `DONE`). ## B04 상태 조회 — 레거시 폴백 (당초 "잔재"로 표기했으나 정정) `get_wf1_analysis_status()`([[B04_wf1_Surface/B04_backend]], `B04_wf1_Surface_Router.py:372`)는 `project_workflow_stages`(SSOT)를 **우선** 조회하고, 행이 없을 때만(백필 미작동 대비) `projects.status` 문자열 비교로 폴백함(416 `WF1_COMPLETE`, 420 `WF1_ANALYZING`, `:412-427`). → B04 실 코드 확인 결과 **정상 경로가 아닌 방어적 폴백**. SSOT 안정화 후 제거 가능하나 현재는 안전장치로 유효. 별개로 `update_project_status()`(`:76`)는 정의만 있고 미호출(죽은 코드) → 정리 권장. ## 미해결 사항 (계획서 원문, 아직 결정 안 됨) - `projects.status` 완전 제거 여부 — 현재는 유지 중(위 확인) - STALE 하위 결과 파일: 즉시 삭제 vs 재실행 시 덮어쓰기 — 코드 레벨 확인 안 함, 별도 점검 필요