本卡屬 FR-162(母卡見「母卡」欄),批 3,等 1b。顧問維護對照的工作台,後端部分。只改 BE repo。

這張卡做什麼(白話)

顧問跟公司討論後要能調整對照:這條其實是等價不是部分重疊、這兩個評估目標該配在一起、官方這條在我們情境不適用。還要能把對照匯出成 Excel 離線整理再匯回,官方更新時匯新版。這張卡做這些動作的 API、開權限、登記側選單;畫面在 2b。

怎麼做

① 能力點與選單 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。

手測(DEV,Swagger 或 curl 帶 JWT)

紀律