本卡屬 FR-162(母卡見「母卡」欄),批 3,等 1b。顧問維護對照的工作台,後端部分。只改 BE repo。
顧問跟公司討論後要能調整對照:這條其實是等價不是部分重疊、這兩個評估目標該配在一起、官方這條在我們情境不適用。還要能把對照匯出成 Excel 離線整理再匯回,官方更新時匯新版。這張卡做這些動作的 API、開權限、登記側選單;畫面在 2b。
~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/features/FR-162-2610-cross-framework-control-mapping/design.md(決策表 D1~D11、詳細設計含 DDL、拆分表);盤點與官方資料分析:~/Projects/Billows/Audit-Manager/compliance-manager-be/docs/analysis/2026-10-24-cross-framework-control-mapping.md。本卡已帶足開工所需細節,不必先讀完。① 能力點與選單 migration(主線 phase=active,檔名 scripts/sql/2026-10-xx-fr162-control-mapping-capabilities.sql,照 2026-10-23-fr161-pre-engagement-capabilities.sql 寫法):capabilities 加 oscal.control-mapping.read(看)、oscal.control-mapping.manage(改、匯入、重建),module='oscal'、license_module='module-frame'、assignable_scopes='{{tenant,org_unit}}'、home_route_name='control-mapping';ui_routes 加 control-mapping(掛 group-compliance-audit 群組、url='/control-mapping'、排在資源庫之後);route_capabilities 綁 read;持 oscal.resource-library.update 的系統角色預設授 manage(照 FR-161 回補寫法)。⚠️ ui_routes.name 必須與 FE 路由 name 一字不差。
② app service app/oscal/service/control_mapping_app_service.py(每個 public method @transaction;守門用 common.authz 的 capability 軸,不另寫):
list_mappings() -> 所有 mapping(含兩端框架版本名、是否參考框架、entries 數)
get_matrix(mapping_id, origin=None, status=None, q=None)
-> 控制項層列(來源代號+標題、目標代號+標題、relationship、confidence、origin、status、entry_id、
被誰覆寫/覆寫誰)+ 每列底下 objective 層子列;標題從 catalog 查(參考框架無標題回 None)
override_entry(entry_id, relationship, confidence, remarks)
-> 原列 status='disabled';新列 origin='curated'、overrides_entry_id=原 id(D5)
disable_entry(entry_id, remarks) -> status='disabled'(不新列)
add_entry(mapping_id, source..., target..., relationship, confidence, remarks) -> origin='curated'
history(entry_id) -> 沿 overrides_entry_id 往回走的列
export(mapping_id, fmt='xlsx'|'oscal', effective_only=True, with_origin=False)
import_(mapping_id, file, fmt) -> 走套件匯入(更新語意),回 {added, updated, skipped, errors[]}
rebuild(mapping_id, file, fmt, confirm: bool) -> confirm 不為 True 回 412;否則刪該 mapping 全部 entries 再匯入
blank_template() -> xlsx bytes
③ route api/oscal/routes/control_mapping_route.py,在 api/oscal/__init__.py add_resource:GET /oscal/control-mappings、GET /oscal/control-mappings/<id>/matrix、POST .../entries、PUT .../entries/<eid>/override、POST .../entries/<eid>/disable、GET .../entries/<eid>/history、GET .../export?fmt=、POST .../import(multipart)、POST .../rebuild、GET /oscal/control-mappings/template。list/matrix/history/export/template 用 @require_capability('oscal.control-mapping.read'),其餘 manage。分頁照 docs/claude/api-patterns.md。
④ error code(flow_control_error_code.py,序號先 grep 現有最大):GRC_CONTROL_MAPPING_IMPORT_INVALID(400,msg 帶錯行)、GRC_CONTROL_MAPPING_NOT_FOUND(404)、GRC_CONTROL_MAPPING_PAIR_EXISTS(409)、GRC_CONTROL_MAPPING_REBUILD_NOT_CONFIRMED(412)。回寫列出四碼給 2b 補 FE i18n。
phase=active migration 1 支(能力點與選單),回寫時明講出貨基線待重產。pyproject.toml 第 139 行取消註解、第 85 行 pin jedi-oscal-v2==2.8.0 先註解,poetry update jedi-oscal-v2。path 改動不 commit(commit 前 git diff pyproject.toml poetry.lock 要空或還原)。@transaction;repo/讀模型繼承 BaseRepositoryImpl 或 @property session;需要新 domain service 就在 __init__ 加參數並在 di_containers/ wiring。改 __init__ 簽章必同步 DI,驗收要實打端點(DI 簽章漂移只在端點被打時才炸)。