| 項目 | 內容 |
|---|---|
| 緣由 | 「新增專案 422」開查 → 演成「把 FR-026 BPMN 流程引擎從死掉的舊 AP retarget 到 v2 輪次」大重構;測試中又連帶修了 GRC 專案列表/刪除(Wave 2A dark) |
| BE branch | feature/oscal-refactor(勿切 branch;發現 branch 不對停下問 user) |
| FE repo | ~/Projects/Billows/Audit-Manager/compliance-manager-fe/,同名 branch feature/oscal-refactor |
| 接手前必讀 | 本文件 §0 讀序(先讀需求 WHY 再碰 code) |
| 預估剩餘 | FE round-flow 大遷移(大,數 hr)+ Task 8b commit + 文件收尾 + stg/poc migration |
| push 狀態 | BE + FE 都有未 push commits → push 等 user 明示 |
大圖:FR-038 是把 OSCAL 從 jedi_oscal v1 整碗換成 v2(Wave 2A 已把 BE boot 切到 jedi_oscal_v2,舊 v1 全剝離)。本棒處理其中一條線:稽核流程引擎。
這條線的需求(user 對話拍板,2026-06-16):
docs/features/FR-026-2605-project-flow-engine-integrate/FINAL-SPEC-v1.0.md)。compliance.project_audit_rounds。ap_authoring stage(auditor 主責)。launch_reverify 另開 close-out 子輪 + parent_round_id),不是 FR-026 的 poam→audit 同輪迴圈。canonical 鏈(D5 拍板):planning → ap_authoring → audit → poam → End (FR-026 的 task_execution 收進 planning;review 暫不納)
stage_code → round.status 對照(與已 shipped 的 v2 輪次狀態機 1:1,零 migration): planning→planning、ap_authoring→audit_planning、audit→auditing、poam→remediation、End→closed
決策清單(design 內有完整理由): | # | 決策 | |---|------| | D1 | 流程範本綁 project_audit_round(非專案)| | D2 | big-bang 一次到位(不分階段)| | D3 | ap_authoring main_role = auditor(暫定)| | D4 | 第一輪範本在「建專案」選;後續輪在「建輪次」選 | | D5 | stage 模型 planning→ap_authoring→audit→poam;task_execution 收進 planning | | D6 | 建專案順帶建第一輪 initial + 綁範本 | | 重要實作收斂 | 無 status derivation:handler 各自寫 status(與所進入 stage 一致);poam→End(非 loop)|
完整設計:docs/features/FR-038-2606-oscal-redesign/round-flow-engine-reintegration-design.md(⚠️ §4.1b 還寫 derivation,實作改成 no-derivation,文件待收尾同步)
round-flow-engine-reintegration-design.md §1~§4(問題/決策/目標架構)round-flow-engine-implementation-plan.md(BE 11 task,已全做)+ round-flow-engine-fe-plan.md(FE,Task 1 做完、2-5 未做)app/flow_engine/service/stage_advance_service.py(已 retarget round_uid)、app/grc/service/oscal_stage_handlers.py、app/grc/service/audit_round_app_service.py(create_round 綁範本 + 狀態機)infra/grc/repository/grc_project_repo_impl.py(list_projects v2 重建)、app/grc/service/project_service.py(delete/batch_delete)冷接自檢 4 問(答不出回去讀):
| commit | 內容 |
|---|---|
1fd604cc |
Task 1 schema:project_audit_rounds.{flow_template_snapshot_uid,workflow_execution_uid} + module_frames.audit_flow_template_uid |
76252985 |
Task 2 error codes(GRC_ROUND_NO_WORKFLOW_BINDING / GRC_ROUND_PREP_TASKS_NOT_DONE) |
5df81d25 |
Task 3 ap_authoring stage_object seed + planning 收斂 |
36d022e7 |
Task 4 builtin BPMN canonical(完整稽核/自我評估 改鏈;含審核/內部自查 deactivate) |
0a132492 |
Tasks 5-10 engine core:stage_advance retarget round_uid、handlers wrap audit_round、preconditions、DI rewire、stage route round-scoped、poam→End |
67ded923 |
handler 測試回歸修正 |
| commit | 內容 |
|---|---|
b31dc79b |
修 /projects/list DI(移除 ProjectService 死接線 associations.assessment_plan_task_domain_service) |
e88e8d78 |
移除 grc 容器對 7 個 Wave 2A 已移除 oscal v1 provider 的死接線 |
c56927c4 |
重建 list_projects(v2):查 projects+extensions、軟刪排除、可見性、分頁 → 列表恢復顯示(只回未刪除) |
987575a6 |
批次刪除 API(POST /grc/projects/batch-delete) |
596d5417 |
修單筆刪除(delete_project 不再走 dark get_project) |
| commit | 內容 |
|---|---|
175ca24 |
建專案改送 resource_library_uid + flow_template_uid(修 422,FE Task 1) |
9ad582c |
專案列表批次刪除 UI(多選 + 批次刪除按鈕) |
留在 working tree,下個 session 要 commit。 因為這 4 個檔在 session 開始前就有 user in-flight 未 commit 改動,無法用 git add 乾淨切開:
api/project/serializers/project.py(加 flow_template_uid、清掉舊 EXCLUDE)api/project/routes/project_route.py(thread flow_template_uid + delete 傳 is_admin)app/project/service/project_start_app_service.py(start_project 建 round 1 = _create_first_round,回 first_round_uid)di_containers/project/project_containers.py(注入 audit_round_app_service)test/test_project_start_creates_first_round.py(新檔,2 tests pass)驗證 Task 8b 有效:DB 已驗 — 建專案 271 後 project_audit_rounds 有 round_no=1/initial/planning,flow_template_snapshot_uid + workflow_execution_uid 非空。
FE 整個還是 AP-centric(route param apUid、apList、RoundSwitcherBar、Banner 掛 :ap-uid)。round flow 在 UI 還不能跑。要做(見 round-flow-engine-fe-plan.md Task 2-5 + audit-round-fe-migration-plan.md):
apUid→roundUid(StageService.js / useStageInfo.js / FlowPhaseBanner.vue,BE 端點已是 /project/<uid>/audit-round/<round_uid>/stage/{info,advance})ap_authoring routed stage,route /round/:roundUid/ap)grc_project_repo_impl 多個 method return []/None、grc 容器 provider 接了已移除的 oscal v1 provider(lazy resolve,踩到才炸)。改 GRC 任何 read/list 前先 grep # FR-038 2A dark 標記 + 確認 grc→oscal provider 引用都有定義(for p in $(grep -oE 'oscal_container\.[a-z_]+' di_containers/grc/grc_containers.py|sort -u); do ...)。compliance.projects 的 RLS relrowsecurity=f(沒啟用);列表過濾是 app 層 GRC visibility filter(user_id/is_admin + participant)。別再往 RLS/tenant context 鑽(我繞了一大圈才發現)。data.id 在 FE 專案列表 = project UID(serializer id = obj.uid),不是整數 id。批次刪除送 data.id 即 uid。create_app() 完整 boot(jedi_issue 要 gitlab/github token + dependency_injector deepcopy quirk,pre-existing,stash 我的改動後 baseline 一樣炸)。驗 boot 要在真實環境;sandbox 只能 import smoke + 單元測試。4 個 entangled 檔 + 1 test。先跟 user 確認他 in-flight 的改動要不要一起 commit,再決定怎麼切(顯式 git add、禁 -am)。
按 round-flow-engine-fe-plan.md Task 2-5。這是讓 round flow 在 UI 能跑的關鍵。風險:Banner prop rename ripple 到所有掛 Banner 的 view;需 round-scoped routing 地基(migration plan Step 0)。開工前讀 FE CLAUDE.md(646 行,跨 repo 鐵則)。
§4.1b 改 no-derivation(目前還寫 derivation)| 項目 | 現況 | 復原依據 |
|---|---|---|
round_prep_tasks_done precondition |
lenient(一律 ok) | prep job 是專案層級(_generate_prep_jobs),「哪些算本輪 prep」scoping 未定 → 待定後補 job-completion 檢查 |
all_poam_closed / all_controls_verdict_filled precondition |
lenient | v2 POA&M/AR Banner 檢查 follow-up;close_round/finalize 自身仍強制 |
| 4 個直接轉換 route(launch-audit/start-auditing/finalize/close) | 未退役(no-derivation 下不會壞,只 bypass BPMN) | O2:跟 FE 遷移一起退,統一走 stage/advance |
| builtin「完整稽核流程(含審核)」+「內部自查流程」 | deactivate(is_active=false) | 含 review(D5 延後)/ 無 audit(不合 ap_authoring 拓撲)→ 補 review-stage / planning→end 形狀後 reactivate |
| 專案列表 AP 進度統計(completion_rate/control 數/task 進度) | 回 0/None | v1 統計子查詢移除;待 v2 輪次層接上重算 |
design §4.1b derivation 段 |
文件寫 derivation,code 是 no-derivation | 收尾時改文件對齊 code |
scripts/sql/2026-06-16-fr038-round-flow-binding.sql(round 兩欄 + module_frames 欄)scripts/sql/2026-06-16-fr038-round-stage-seed.sql(ap_authoring stage + planning 收斂)scripts/sql/2026-06-16-fr038-builtin-flow-canonical.sql(builtin BPMN)scripts/sql/2026-06-16-fr038-poam-to-end.sql(poam→End)⚠️
schema_migrations欄位是filename/note(不是version,我踩過)。套法:psql -U cmmgr -p 25432 -d <db> --single-transaction -v ON_ERROR_STOP=1 -f <檔>。
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
git branch --show-current # 應為 feature/oscal-refactor,不對停下問 user
git log --oneline -6 | cat # 對照 §1 commit 清單
git status --short | grep -vE '^\?\? docs/' # 確認 Task 8b 4 檔 + test 仍在 working tree
# 取 DB 密碼(cmmgr/cm_app 同組,查 .env DB_SECRET)
PW=$(python3 -c "import json;[print(json.loads(l.split('=',1)[1].strip().strip(chr(34))).get('rds_master_password','')) for l in open('.env') if l.startswith('DB_SECRET=')]")
# import smoke(sandbox 無法完整 boot,用這個)
set -a; source .env; set +a; export GITLAB_API_VERSION=4 GITLAB_URL=x GITLAB_PRIVATE_TOKEN=x GITHUB_PRIVATE_TOKEN=x
.venv/bin/python -m pytest test/test_oscal_stage_handlers.py test/test_create_round_flow_binding.py test/test_project_start_creates_first_round.py -q-- 建專案有建第一輪 + 綁範本(D6 + create_round 綁定)
SELECT round_no, round_type, status, flow_template_snapshot_uid IS NOT NULL AS has_flow, workflow_execution_uid IS NOT NULL AS has_wf
FROM compliance.project_audit_rounds ORDER BY id DESC LIMIT 3;
-- canonical stage 鏈
SELECT code, complete_handler_key, precondition_key, allowed_successors FROM compliance.stage_objects WHERE code IN ('planning','ap_authoring','audit','poam') ORDER BY sort;
-- 列表只回未刪除(27 筆);軟刪 175 筆
SELECT count(*) FILTER (WHERE pe.deleted_at IS NULL) non_deleted, count(*) FILTER (WHERE pe.deleted_at IS NOT NULL) soft_deleted
FROM compliance.projects p LEFT JOIN compliance.project_extensions pe ON pe.project_id=p.id;直接打 API 驗(dev turnstile 收 dummy):
POST /api/1.0/login {"username":"blsadmin","password":"<查 .env / reference_dev_login>","cf_turnstile_token":"dummy","provider":"password"}→ 取 access_token →POST /api/1.0/grc/projects/list帶Authorization: Bearer+X-Tenant-Id:102+X-Org-Unit-Id:98。
讀 docs/features/FR-038-2606-oscal-redesign/handoff/2026-06-16-round-flow-reintegration-handoff.md,
先讀「🧭 原始需求 WHY」+ §0 自檢 4 問答得出再開工。本 arc:FR-026 流程引擎已 retarget 到 v2
audit_round(BE Tasks 1-10 done + committed);GRC 列表/刪除已修。剩:①commit Task 8b(4 entangled
檔,先問 user in-flight 改動)②FE round-flow 大遷移(Banner→round + AP 填寫畫面,FE 還全是 AP-centric)。
跑 §6 pre-flight + §7 verify 確認現況,不切 branch、push 等 user。