建立日期:2026-05-14 撰寫:raymond(透過 Claude Opus 4.7 session 2) 接手對象:M10 FE 新 session 的開發者 / Claude 執行策略:subagent-driven-development(M10 一個 implementer + 1 spec reviewer + 1 code reviewer)
review 階段 + 範本方向性驗證 + 全 stage 共用留言feature/project-flow-engine-reviewdocs/features/FR-026-2605-project-flow-engine-integrate/04-review-stage-and-flow-validation/design.md v1.3implementation-plan.md v1.1DB schema + ORM mapping + BpmnTopologyValidator + builtin BPMN patch + POST /flow-engine/flow-templates/validate endpoint。
| M | 內容 | Commit |
|---|---|---|
| M7 | StageAdvanceRequestSchema 加 decision/comment + ReviewDecisionHandler + DI register | faa21d5 |
| M8 | StageAdvanceService 接 decision/comment + 業務驗證 + JobComment(UUID fix) + Route 傳參 + design.md §16.2 reconciliation + log enrichment | dfc526d + 83a7eb6 + 47b99d5 |
| M9 | 5 條 service-level mock test + 1 條 validate HTTP smoke + 1 條 skip(deferred) + BPMN fail-case fixture + autouse→opt-in hygiene | bf69977 + fcbaa53 |
@validates_schema 訊息被 jedi-common 吞掉 → 業務驗證放 service 層:FE 從 /stage/advance 拿到 400 時 msg 是 generic「請求參數錯誤」,真實 error code 在 error_code 欄位(GRC_400061 / GRC_400062)。FE 顯示錯誤訊息時必須走 i18n by error_code,不要直接顯示 msg。詳見 design.md §16.2。
ReviewDecisionHandler silent default approve 已被 service 層先擋住:M9 test 已驗證 decision=null → GRC_400062;FE 送 advance 時若 stage 是 review 必須帶 decision,否則一定 400。
JobComment 寫入失敗不擋推進(M8 log enrichment fix):BE 在 BPMN 推進成功後寫 JobComment 是 best-effort;如果寫失敗只 log warning + 帶 ap_uid / project_uid / user_id / template_job_id context,FE 在 success response 後不要假設 comment 一定寫進 DB。M11 manual smoke 需驗證 comment 列表確實顯示退回原因。
HTTP /validate endpoint 路徑:POST /api/1.0/flow-engine/flow-templates/validate(注意 /api/1.0 prefix;M9 test 已驗)。
Repo:~/Projects/Billows/Audit-Manager/compliance-manager-fe
切換指令:
cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe
git fetch
git checkout feature/project-flow-engine-review 2>/dev/null || git checkout -b feature/project-flow-engine-review⚠️ FE 檔名跟 plan 描述不完全一致,實際路徑(已驗):
| Plan 寫的路徑 | 實際存在路徑 |
|---|---|
src/components/grc/FlowPhaseBanner.vue |
✅ 同名 src/components/grc/FlowPhaseBanner.vue |
src/views/flow-template/FlowTemplateEditView.vue |
⚠️ 實際是 src/views/flow-template/FlowTemplateEditorView.vue(多 or) |
src/service/FlowPhaseService.js |
❌ 不存在;實際是 src/service/FlowTemplateService.js(M10.3 需找 stage advance 的 service,可能在別處 — implementer 必先 grep advanceStage|stage/advance) |
src/views/flow-template/components/BpmnPaletteProvider.js |
⚠️ palette 實際在 src/views/flow-template/bpmn/ 或 src/views/flow-template/components/ — implementer 必先 ls 確認 |
M10 sub-tasks:
M10.1 i18n keys — src/locales/zh-TW.json + en.json 加 flowEngine.validator.* + flowEngine.banner.review.*(design §10.4 / plan §M10.1)
M10.2 FlowPhaseBanner.vue review 階段加雙按鈕 + Dialog comment textarea
rejectMode flag 切 placeholder + confirm-button disabled 條件{ decision: 'approve'|'reject', comment: '...' }M10.3 Service / API client — advanceStage(projectUid, apUid, payload) 支援 decision/comment
POST /project/<uid>/ap/<ap_uid>/stage/advanceM10.4 BPMN editor inline warning — FlowTemplateEditorView.vue 拖 sequenceFlow 時 debounce 500ms 呼叫 /flow-engine/flow-templates/validate
debouncedata.violations 取/validate endpoint 一律回 200(valid + violations),不會 throw 400;FE 不需 catch error 走 fallbackflowEngine.validator.*)+ context interpolate.djs-element.violation-marker .djs-visual > * { stroke: var(--danger-color, #dc3545) !important; }M10.5 Palette 加 review UserTask 預設 stencil
{ stage_object_code: 'review', main_role: 'reviewer' }M10.6 FE smoke 3 項(要實際開瀏覽器 + BE 起來 + DB 有 spec 4 seed)
M10.7 Commit FE
-A / -am)Commit msg 範本:見 plan §M10.7(line 2292)
三 repo 都要動:
docs/changelog/2026-05-14-feat-review-stage-flow-validator.md~/Projects/Billows/Audit-Manager/compliance-manager-test 新 BDD scenario features/flow-engine-review/review-stage.featureM11.1 Manual smoke 6 步(design §12.2)— 需 user 操作瀏覽器,subagent 做不到:
M11.2 BDD scenario(compliance-manager-test repo)
features/flow-engine-review/review-stage.featurenpm run test:bdd -- --tags @flow-engine-reviewM11.3 Changelog(BE + FE 各一份;test repo 不需 changelog)
type: feat, breaking: false, modules: [flow-engine, grc]M11.4 最終 summary(CLAUDE.md「做 summary」流程)
docs/conversation-history/2026-05-13-review-stage-and-flow-validation/part-NN-of-NN-*.md(按 phase 拆 part)subagent-driven-development SOP:
每個 implementer prompt 必含:
CLAUDE.md 規範必貼(兩 repo 都要遵守):
-A / -am(CLAUDE.md 反覆強調;BE working tree 有 2 個未追蹤 SQL 不該掃進)Request body(M7 + M8 加的欄位):
{
"force": false,
"decision": "approve" | "reject" | null,
"comment": "...string..." | null,
"ctx": {}
}Response(success / failure 都用既有 envelope):
{ "status": true, "data": { "advanced": true, "handler_result": {...}, "current_stage_info": {...} } }{ "status": false, "error_code": "GRC_400061" | "GRC_400062", "msg": "..." }(msg 是 generic「請求參數錯誤」,FE 必須用 error_code 走 i18n)Error code 對照(FE 必加 i18n):
| error_code | 中文 | 觸發條件 |
|---|---|---|
GRC_400060 |
範本流程結構不合法 | template create/update 時 topology violation |
GRC_400061 |
退回審核必須附留言 | stage=review + decision=reject + comment 空/whitespace |
GRC_400062 |
decision 值必須為 approve 或 reject | stage=review + decision 缺值 |
非 review stage 送 decision → BE 不擋,靜默 ignore + log warning(不影響 FE)。
純驗證 endpoint,一律回 200:
Request:
{ "bpmn_xml": "<bpmn:definitions>...</bpmn:definitions>" }Response:
{
"status": true,
"data": {
"valid": true | false,
"violations": [
{
"rule": "successor_not_allowed" | "start_stage_not_allowed" | "end_stage_not_allowed" | "unknown_stage_code" | "gateway_missing_condition" | "unreachable_node" | "no_end_path",
"reason_i18n_key": "flowEngine.validator.successor_not_allowed",
"context": {
"sequence_flow_id": "Flow_xxx", // 部分 rule 帶
"source_stage": "audit", // successor_not_allowed
"target_stage": "poam",
"stage": "poam", // start_/end_stage_not_allowed
"code": "xxx", // unknown_stage_code
"gateway_id": "Gateway_xxx", // gateway_missing_condition
"node_id": "Flow_xxx" // unreachable_node
}
}
]
}
}/validate 不會 throw 400/500(除非 BPMN 完全無法 parse);FE 不需 catch error 走 fallback path,只要看 data.valid 與 data.violations 即可。
加上 topology 守門員。違規回 400 with error_code = GRC_400060,但 violations 細節不在 response(design §16.1 reconciliation:err.context 被 jedi-common 吞掉)。
FE 設計建議:存檔前先呼叫 /validate 拿 violations,UI 顯示;user 確認 OK 才送 create/update。若 BE 仍回 400(race condition / direct API call),FE 把 GRC_400060 對應到 generic「流程結構不合法,請開啟編輯器查看詳情」訊息。
| 項目 | 影響 | 後續處理 |
|---|---|---|
| jedi-common ValidationError + ClientError 訊息被吞 | FE 只能拿到 error_code,msg 是 generic | FE i18n by error_code,不靠 msg。design.md §16.1 + §16.2 已紀錄 |
| FE 檔名跟 plan 不完全一致 | plan §M10 寫 FlowPhaseService.js / FlowTemplateEditView.vue 不存在 |
implementer 必先 grep / ls 找實際路徑(handoff §三表格列了校正) |
| dev DB Spec 4 stage_objects 已 seed | M9 HTTP validate 測試 pass-case skipped(因 dev DB 還沒跑某 seed?實際 M1 已跑) | M11 manual smoke 必須先確認 psql ... -c "SELECT code FROM compliance.stage_objects ORDER BY sort_order" 5 列含 review;若缺,跑 scripts/sql/2026-05-14-spec4-stage-objects-rules-and-review.sql |
| 自訂範本 backfill scan 結果為 0(dev DB) | M4 backfill update 0 列;user 環境若有 duplicated builtin-full-audit 範本含未 patch reverse 仍需重跑 | M11 smoke step 4(launch_new_round 切回無 review 範本)若行為異常,先 SELECT 對 duplicated 範本檢查 |
BE log 位置 log/app.log |
跨 BE / FE smoke 時若出現 500,先 grep BE log | 不要靠 lsof 找 stdout,CLAUDE.md 已寫 |
| BE port 8002 不是 8000 | env config 決定;FE 預設 axios baseURL 必須對齊 | FE config 看 src/config/api/ 是否有 dev 對 8002 設定 |
compliance-manager-be/
├── api/flow_engine/
│ ├── serializers/flow_template.py ← M6 加 validate schemas
│ ├── serializers/stage_advance.py ← M7 加 decision/comment
│ ├── routes/flow_template_route.py ← M6 加 validate endpoint
│ └── routes/stage_advance_route.py ← M8 加 decision/comment kwargs
├── app/flow_engine/
│ ├── service/flow_template_app_service.py ← M5 validator integration
│ ├── service/stage_advance_service.py ← M7+M8 加 decision/comment + JobComment
│ └── util/bpmn_topology_validator.py ← M3 純 function
├── app/grc/service/oscal_stage_handlers.py ← M7 加 ReviewDecisionHandler
├── di_containers/
│ ├── flow_engine/flow_template_containers.py ← M5 wired stage_object_domain_service
│ └── grc/grc_containers.py ← M7+M8 wire review_decision_handler + job_comment_service
├── domain/flow_engine/entity/stage_object_entity.py ← M2 4 欄
├── infra/flow_engine/
│ ├── models/stage_object.py ← M2 4 欄
│ └── mapper/stage_object_mapper.py ← M2 4 欄 mapping
├── common/code/grc_error_code.py ← M5 加 GRC_400060/061/062
├── scripts/sql/
│ ├── 2026-05-14-spec4-stage-objects-rules-and-review.sql ← M1 migration
│ ├── 2026-05-14-spec4-builtin-flow-templates.sql ← M4 migration
│ └── seeds/bpmn/
│ ├── builtin-full-audit.bpmn ← M4 patched
│ └── builtin-full-audit-with-review.bpmn ← M4 new
├── tests/test_bpmn_topology_validator.py ← M3 22 條
├── tests/test_stage_advance_service_v4.py ← M9 5 條 service-level mock
├── tests/test_flow_template_validate_endpoint.py ← M9 HTTP smoke
└── tests/fixtures/bpmn/invalid_start_to_poam.bpmn ← M9 fail-case fixture
compliance-manager-fe/
├── src/locales/
│ ├── zh-TW.json ← M10.1 加 flowEngine.validator.* + banner.review.*
│ └── en.json ← M10.1 對應
├── src/components/grc/FlowPhaseBanner.vue ← M10.2 雙按鈕 + Dialog comment
├── src/views/flow-template/
│ ├── FlowTemplateEditorView.vue ← M10.4 debounced /validate + violation outline
│ └── (palette 位置 implementer ls 確認) ← M10.5 review UserTask stencil
└── src/service/? ← M10.3 advanceStage(decision/comment)
(路徑 implementer grep `advanceStage|stage/advance` 確認)
compliance-manager-test/
└── features/flow-engine-review/
├── review-stage.feature ← M11.2 BDD scenario
└── (對應 step definition + page object)
回報 user 並建議:
FlowPhaseBanner.vue 其他 stage 怎麼處理,mirror 模式{ status, error_code, msg, data })FlowTemplateEditorView.vue 既有 commandStack 監聽,沿用既有 modeler 物件| 版本 | 日期 | 變更 |
|---|---|---|
| v1 | 2026-05-14 | M0–M6 完成、M7 起手交接 |
| v2 | 2026-05-14 | M7–M9 完成、M10 起手交接(FE + 收尾) |