| 項目 | 內容 |
|---|---|
| 緣由 | FR-038 v1→v2 OSCAL redesign 收尾:把舊「AP-mode」的 FE dual-mode code path 整套退役 |
| Branch | BE + FE 皆 feature/oscal-refactor(勿切 branch) |
| 範圍 | 主要 FE(compliance-manager-fe),含少量 BE(compliance-manager-be) |
| 接手前必讀 | 本文件全文 + docs/review/2026-06-18-fr038-api-inventory-dead-and-broken.md §1B/§2 |
| 預估時間 | 主要 FE 重構 ~半天(需開 FE dev/build 邊改邊驗);BE cleanup ~1h;task-setup ~30m |
| 狀態 | 安全核心已做(v1 AR/POA&M 頁刪檔);糾纏部分待本棒 |
v2 把產品模型從「專案 → AP(評估計畫)」改成「專案 → 稽核輪次(round)」:每個專案可多輪稽核,每輪有自己 round-scoped 的 SSP 快照 / AP / AR / POA&M。FR-038 之前是 v1「專案→AP」模型,頁面都是 AP-scoped(URL 帶 /ap/:apUid)。
v2 切換時 FE 兩套路由並存:round-scoped(*-round,URL 帶 /round/:roundUid)+ 舊 AP-scoped(*-ap 或 base),靠各元件的 isRoundRoute = !!route.params.roundUid 三元切換。
現在:所有 live 專案都是 round-based(新建專案 project-start 一定建 round_no=1 的 initial 輪);舊 AP-mode 專案已全部 soft-deleted(DEV 實查:199 archived + 8 pending 皆 deleted_at 已設,只剩 1 個 live 專案 round-based)。User 明確要求:舊 AP-mode 都不要了,把 ap-mode code path 全退役。
目標:FE 導航與元件純 round;移除 -ap/base 的 ap-mode 分支、-ap 路由、已退役 v1 頁;BE 移除 v1 dark-stub 路由/repo。避免使用者誤入 ap-mode 看到空/壞頁。
本棒在大圖的位置:FR-038 2B 收尾的「死碼清理」。功能性 v2 重建已完成(dashboard/覆核/任務/匯入匯出 un-500 等,見 §11 commits);本棒是拔掉並存的 v1 ap-mode 殘留。
project-auditor-overview / project-planning)不能直接刪?fetchApList → redirect -ap)功能性 v2 重建 + v1 退役都已做完並 commit(見 §11)。與本棒直接相關的:
50c1061):AuditReviewView.vue / PoamView.vue / AuditVerdictPanel.vue / PoamDetailDrawer.vue + router 的 project-audit-review / project-poam 條目移除。稽核/POA&M 全走 RoundAuditReviewView / RoundPoamView。a23f614e):grc 的 v1 AR(/ar/controls/list、/ar/control/<uid>/verdict 等 6 條)+ POA&M(/poams/list、/poam/<uid>)在 api/grc/__init__.py 已註解(標 FR-038 DEAD-V1 §1B)。a23f614e):oscal scoped import / grc control-group·control·AO list·detail / project job-execution-device / flow-engine main-process 等 / participant menu —— 全用 # [FR-038 DEAD-V1|...] 標記(grep -rn "FR-038 DEAD-V1" . 可一次撈出)。⚠️ 這些 §1B/§2 目前是註解(停用但保留),本棒要把它們真的刪掉。
核心難點:base 路由(project-auditor-overview / project-planning)是 live 的(被多個元件 push),且「進 base 會被 ProjectAuditorOverview.fetchApList redirect 到 -ap」是 ap-mode 入口還通的原因。所以不能只刪路由 —— 要把「進 base → 導 round」改通,並重接所有還指向 base/-ap 的元件。
可達性實況(grep 出來的,下個 session 直接照這改):
| 路由 name | 還被誰 push(非 router 定義/非 _archived) | 處置 |
|---|---|---|
project-auditor-overview(base) |
ProjectSettingsView:59,86;TaskSetupView:615;ProjectPlanningView:1521 | 保留,但要讓進 base 改導 round |
project-auditor-overview-ap |
PoamView(已刪);ProjectAuditorOverview:95,108(ap-branch 內部) | 收掉 ap-branch 後即無人引用 → 可移路由 |
project-planning(base) |
SspDocxImportPage:811,847 | 保留或改導 round(看 SspDocxImportPage 能否拿到 round) |
project-planning-ap |
ProjectAuditorOverview 三元(1298/1346/1487);ImportExcelPreviewPage:84 | 重接後 可移 |
project-task-setup / -ap |
0 導航 | → Part 3 |
project-ap-list |
ProjectCreateView:262;ProjectListView:291 | live,保留(這是輪次列表入口,非 ap-mode) |
具體改動(compliance-manager-fe):
src/views/project/ProjectAuditorOverview.vue:
fetchApList(~line 67-102):目前 if (isRoundRoute) {撈 audit-rounds/list; return} else {撈 assessment-plans/menu; router.replace(-ap)}。把 else 分支改成:resolve 該專案最新一輪 round → router.replace({name:'project-auditor-overview-round', params:{id, roundUid}})(讓 base 進來自動轉 round)。可用既有 /projects/<pid>/audit-rounds/list 拿最新輪 uid。onApChange(~104-110):移除 else 的 -ap 分支,一律 round。project-planning-ap,~1298/1346/1487):移除 : {name: ...-ap/...base...} fallback,一律 project-planning-round(roundUid = selectedApUid,round 模式下即 roundUid)。-ap 導航 → round(每個都要先能拿到 round uid;拿不到的,保留 base 但靠上面 fetchApList 自動轉 round):
ProjectSettingsView.vue:59,86、TaskSetupView.vue:615:push base auditor-overview → 維持 base(fetchApList 會自動轉 round)或直接帶 roundUid。ProjectPlanningView.vue:1521:三元 -ap/base → round。SspDocxImportPage.vue:811,847:push base planning → 維持 base 或帶 round。ImportExcelPreviewPage.vue:84:project-planning-ap → round(需 resolve round)。src/config/router/index.js:確認上面都改完、grep 無人引用後,移除 project-auditor-overview-ap / project-planning-ap 條目(base 保留)。node --check 驗語法。src/config/locales/i18n/{zh-tw,en}/menu.json 移除 project-auditor-overview-ap / project-planning-ap label(task-setup-ap 看 Part 3)。npm run build(或 dev server)跑過 + 手動點:專案設定→回總覽、規劃頁、docx/excel 匯入後導航,都落 round 頁、不再進 ap-mode。⚠️ 盲改風險高:這些是 live 共用元件 + 核心導航,且部分元件手上只有 projectId/apUid 沒 roundUid(要先 resolve 當前 round)。務必開 FE build 邊改邊驗,不要靜態改完就 commit。
目前是「註解停用」,本棒真刪。用 py_compile + blueprint register probe 驗(不需 FE build)。
api/grc/__init__.py:刪除 §1B(Ar*/POA&M)+ §2(control-group/control/AO、projects/menu 等)的已註解 add_resource 區塊 + 對應的 route class import。api/grc/routes/audit_route.py 的 ArControlListResource/ArControlDetailResource/ArVerdictResource/ArFindingCreateResource/ArFindingDetailResource/ArRoundListResource;api/grc/routes/poam_route.py 的 v1 PoamList/PoamDetail(先確認 FE 已無呼叫 —— §1B 已退役、round 走 /audit-round/*)。assessment_result_app_service/poam_app_service,不同物):
infra/grc/repository/grc_audit_repo_impl.py(GrcAuditRepoImpl,全 dark stub)+ DI audit_service provider(di_containers/grc/grc_containers.py)。oscal_audit_query.py(注意:oscal_audit_query 被 oscal_stage_preconditions 用,確認後再決定,可能要保留)。oscal_project_service.py / project_system_info_service.py / oscal_audit_service.py)→ 連同 test/ 內直接建構它們的單元測試一起評估刪除。grep -rn "FR-038 DEAD-V1" . 確認都清掉;.venv/bin/python -m py_compile <檔> + blueprint register probe(見 §F)。project-task-setup / project-task-setup-ap 路由 0 code 導航 → 可移 router 條目 + 刪 src/views/project/TaskSetupView.vue + menu.json label。public.ui_routes 沒掛 task-setup(側邊選單可能 DB 驅動):
PGPASSWORD='<查 .env DB_SECRET>' psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -tA \
-c "SELECT route_name, path, enable FROM public.ui_routes WHERE route_name ILIKE '%task-setup%' OR path ILIKE '%task-setup%';"grc_task_setup_repo_impl.get_task_setup_tree 這 session 已重建成 v2(commit 4880a0a0)。TaskSetupView 移除後它變孤兒,可一併清或留著(無害)。本棒會疊在 B6 + 覆核讀回上,先確認它們 runtime OK(這兩個我只做了 compile/import/SQL 驗,沒跑 runtime):
2ed83f49 的 diff)。docs/review/2026-06-18-fr038-api-inventory-dead-and-broken.md §1B/§2 — 哪些路由為何停用、FE 哪些頁取代。src/views/project/ProjectAuditorOverview.vue — ap/round dual-mode 主嫌(fetchApList / onApChange / 三元)。src/views/project/ProjectPlanningView.vue — 另一個 dual-mode 共用元件(規劃/任務指派頁,round 主路徑)。src/config/router/index.js — round/ap/base 路由定義 + breadcrumb parent 鏈。api/grc/__init__.py — BE 已註解的 §1B/§2 路由區塊(Part 2 清理對象)。feature/oscal-refactor,branch 不對停下問 user。compliance-manager-fe/CLAUDE.md(646 行,PrimeVue quirks / i18n / 元件慣例)。git add 檔名、禁用 -am。# BE
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
git branch --show-current # 應為 feature/oscal-refactor
git status --short # 確認乾淨(除 pyproject.toml/README.md/FR-039/proposal.html 等非本 arc)
# FE
cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe
git branch --show-current; git status --short
# BE blueprint register probe(改完 Part 2 驗,需 env stub 繞過 gitlab/github import)
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
export GITLAB_API_VERSION=4 GITLAB_URL=https://x.invalid GITLAB_PRIVATE_TOKEN=d GITHUB_PRIVATE_TOKEN=d ENV=DEVELOP_PREMISE
.venv/bin/python -c "
import os
[os.environ.setdefault(k.strip(), v.strip().strip(chr(34)).strip(chr(39))) for k,v in (l.split('=',1) for l in open('.env') if '=' in l and not l.startswith('#'))]
for k,v in {'GITLAB_API_VERSION':'4','GITLAB_PRIVATE_TOKEN':'d','GITHUB_PRIVATE_TOKEN':'d','GITLAB_URL':'https://x.invalid'}.items(): os.environ[k]=v
import api.grc, api.project; assert api.grc.create_module() and api.project.create_module()
print('blueprint register OK')"add_module_frame stub)、M6 ai_dashboard OscalFramework(Version)Service resolver、M7 frameworks.main_version 雙真相、L1 dead write-strategy、L2 重複 error code、L4 stage precondition、ssp-import-template/control-defaults 填值完整 v2。清單見 docs/review/2026-06-18-fr038-api-inventory-dead-and-broken.md。BE(feature/oscal-refactor):
f6163e02 專案列表狀態改顯示最新一輪 + 稽核計畫改輪次總數a23f614e 退役死 v1 路由/DI + un-500 資源庫匯入樣板(§1B/§2 註解停用)4880a0a0 重建 GRC dark-stub 為 v2(dashboard/覆核寫入/menus/AO jobs/task-setup/batch-notify)+ My Audits 漏排已刪專案修正f7a9f752 上線前審查報告 + API 死碼/壞掉盤點(docs)2ed83f49 docx AO key 統一 _obj.N(B6)+ 覆核狀態讀回控制樹(閉環)FE(feature/oscal-refactor):
c62eb4c 專案列表狀態改最新一輪 + 移除完成率欄2182ef0 稽核/POA&M 導覽全改走 round + 我的稽核移除證據就緒50c1061 刪除已退役 v1 稽核/POA&M 頁(4 檔 + router)接手 FR-038「AP-mode 最終清理」。請先讀
docs/features/FR-038-2606-oscal-redesign/handoff/2026-06-18-ap-mode-removal-handoff.md
全文,特別是「🧭 原始需求/WHY」+ 冷接自檢 4 問 —— 答得出再開工。
任務:把 v2 並存的舊 AP-mode code path 退役(現行專案全 round-based、舊 AP 專案已刪)。
建議順序 Part 2(BE 刪已停用 v1 路由/repo,py_compile+blueprint probe 驗)→ Part 3
(task-setup,先查 ui_routes)→ Part 1(FE ap-mode 導航/元件移除,**務必開 FE dev/build 邊改邊驗**,
base 路由保留但改導 round、重接 ~5 個元件、移 -ap 路由)。
先跑 handoff §C 驗「B6 + 覆核讀回」runtime OK,再疊上去。規範見 §E(勿切 branch / 不自動 push /
跨 repo 先讀 FE CLAUDE.md / 改完要驗不盲改)。§G 列了勿順手做的項目。