# Excel 匯入匯出對齊 Session Summary
**日期：** 2026-05-26  
**Branch：** feature/ssp-oscal-alignment  
**性質：** Excel 匯出樣板、匯入預覽、資料寫入路徑全面對齊 web UI

---

## 一、本次修改範圍總覽

### BE commits（15 個，`9379f2a6`→`1a79d6e2`）

| commit | 主題 |
|--------|------|
| `9379f2a6` | Excel 樣板 sheet 名稱對齊 web（v3.0.1）+ 補 v3.0.0 欄位 i18n |
| `cb850d11` | 資產清冊 → 資產（v3.0.2）|
| `832073b0` | MF filled export 改從 mf-default tables 讀 components/LA |
| `afbcf555` | docx import mf-default confirm 補存 props（protocol/security_auth/provider/fedramp...）|
| `7dbd3bc6` | LA/Component service `_to_dict` 扁平 + add/update 打包 props |
| `3b619471` | 受評標的 export 改讀 mf-default SC + AO lookup key 修 |
| `3d9fe47d` | 受評標的加範圍識別碼欄 + scope_description fallback to description |
| `7b5ddcee` | 欄位名稱全面對齊 web（12 欄名）|
| `27c51a60` | AO lookup 對齊 FE aoLetterKey()（description [a]→(a)）|
| `9db63df0` | inventory component refs string→list + controls preview catalog matching |
| `64be8460` | 角色對齊 OSCAL ssp_party_role + 人員/單位補欄（title/phone/address）v3.0.4 |
| `80a53a1b` | 角色中文 label + key-value 雙向對應 v3.0.5 |
| `8d09bef5` | Excel import superset/update flow 補寫 MF defaults（Step 6c）|
| `42bc09d3` | project launch：MF defaults 為 single source of truth，阻斷 template SSP clone |
| `b54ec0da` | template-copy：Phase 2 雙重寫入防護（後被 42bc09d3 取代為更根本修法）|
| `1a79d6e2` | SSP-scoped Excel 下載補 inventory items + 舊 SSP 髒資料清理 |

### FE commits（4 個）

| commit | 主題 |
|--------|------|
| `20df46e` | 移除 templateSsp gate，直接顯示系統元件/外部授權 tab |
| `51701fe` | 匯入預覽 Tab 名稱對齊 + 參與人員/單位補欄位 |
| `351edf8` | 角色下拉改用 menuStore.sspPartyRoleMenu（對齊 docx import）|
| `44436ef` | 資產清冊 DataTable 補顯示資產標籤/FQDN/主機名稱/軟體/作業系統 |

---

## 二、主要 Bug 與根本原因

### A. Excel 樣板 sheet 名稱 / 欄位名稱不對齊 web
- **原因**：v3.0.0 三個新 sheet 的 i18n key 沒補；舊 sheet 名稱未改
- **修法**：補 28 個 i18n key，4 個 sheet 改名，12 個欄位對齊 web 文案

### B. MF template-edit「系統元件/外部授權」tab 空白
- **原因**：FE tab 顯示條件 `templateSspExists && templateSspUid`，但 Bug T Phase 2 後資料存在 mf-default tables，不走 template SSP path
- **修法**：移除 templateSsp gate，直接 mount ModuleFrameComponentsLeveragedInventoryTab

### C. Excel filled 匯出 components/LA 空
- **原因**：`_populate_filled_data` 走 `_fetch_mf_items_via_ssp`（OSCAL SSP tables），但資料在 mf-default tables
- **修法**：注入 MF default DS，優先讀 mf-default tables

### D. docx import 後 props 欄位（protocol/security_auth 等）空白
- **原因**：`_run_mf_default_confirm` 存 props 時用 `comp_dict.get("props")` = None（ParsedComponent 沒有 props 欄位）
- **修法**：從 parsed dict flat fields 手動打包成 props dict

### E. LA/Component API response 欄位不對齊（provider 等空）
- **原因**：`_to_dict` 回 `props:{...}` 巢狀，FE 讀 `data.provider` 扁平
- **修法**：`_to_dict` 展開 6 個 LA 欄位到頂層；FE add/update 送扁平欄位 → BE 打包 props

### F. Excel export 受評標的空/欄位不對
- **原因**：走 OSCAL SSP path，但 SC 在 mf-default；scope_description null 但 description 有資料
- **修法**：注入 MfScDefaultDomainService；scope_description fallback to description

### G. AO 現況說明/實作狀態空
- **原因**：`existing_obj_map` key 是 `(cid, "(a)")` 但 lookup 用 `(cid, assessment.uid=UUID)`
- **修法**：從 `assessment.description "[a]..."` 提取字母 → `"(a)"`（對齊 FE aoLetterKey()）

### H. 控制項全部「未配對」
- **原因**：v2-bundle schema 的 `_run_preview_reconcile` 直接 return，不跑 catalog matching
- **修法**：加 `_preview_reconcile_controls`，用 CatalogControlReconciler 設 matched_catalog_control_id

### I. 角色下拉不對齊 web
- **原因**：Excel 用 Billows 4 角色（manager/reviewer/auditor/viewer），web 用 OSCAL ssp_party_role
- **修法**：Excel enum 改中文 OSCAL 角色；匯入時 reverse mapping 回 OSCAL key；FE 預覽改用 menuStore

### J. 啟動專案 components/LA/inventory 重複
- **原因**：Excel import 同時寫進 template SSP OSCAL tables（_run_v2_bundle_confirm）+ MF defaults（Step 6c）；啟動專案兩條 clone 路徑都執行
- **修法**：確立 MF defaults 為 single source of truth；`_setup_ssp_system_implementation` 若 MF defaults 有資料則跳過 template SSP clone

### K. SSP-scoped Excel 下載 inventory 空
- **原因**：`_populate_filled_data_for_ssp` hardcoded `bundle.inventory_items = []`（Phase 4 TODO 未完成）
- **修法**：注入 InventoryItemDomainService，讀 `ssp_inventory_items` by ssp_id

---

## 三、架構決策紀錄

### Single Source of Truth：MF defaults tables

Bug T Phase 2 建立的架構：
- `compliance.module_frame_component_defaults` — 系統元件
- `compliance.module_frame_leveraged_authorization_defaults` — 外部授權
- `compliance.module_frame_inventory_item_defaults` — 資產
- `compliance.module_frame_system_characteristic_defaults` — 受評標的

template-edit 頁面讀/寫 → MF defaults  
啟動專案 Step 7.6 `copy()` → MF defaults → project SSP OSCAL tables  
`_setup_ssp_system_implementation` Step 3-5 → 有 MF defaults 時 skip template SSP clone

template SSP OSCAL tables 現有資料為 Excel import 的副產品，不再做為 project clone source。

### Excel 角色欄位

DB `system_menus` 存 OSCAL key（無中文）  
FE `oscal-role.json` 存中文 label  
BE `OSCAL_PARTY_ROLE_ZH` / sheet_handlers `_PARTY_ROLE_ZH_TO_KEY` 雙向對應  
三者均為 source code hardcoded，OSCAL 標準角色不常變，可接受

---

## 四、DB 直接修改紀錄

| 操作 | 說明 |
|------|------|
| DELETE ssp_components WHERE id IN (528-531, 536-539) | 刪 SSP 293/294 重複 component（8→4）|
| DELETE ssp_leveraged_authorizations WHERE id IN (74,76) | 刪 SSP 293/294 重複 LA（2→1）|
| DELETE ssp_inventory_items WHERE id IN (64-73, 84-93) | 刪 SSP 293/294 重複 inventory（20→10）|
| UPDATE module_frame_component_defaults SET description=purpose WHERE description='' | 補現有 8 筆 description 空的紀錄 |

---

## 五、Template 版本歷程（本 session）

| 版本 | 改動 |
|------|------|
| v3.0.1 | sheet 名稱對齊 web + 補 28 個 i18n key |
| v3.0.2 | 資產清冊 → 資產 |
| v3.0.3 | 受評標的加範圍識別碼欄 |
| v3.0.4 | 角色對齊 OSCAL ssp_party_role + 單位加角色欄 |
| v3.0.5 | 角色改中文 label（key-value 雙向對應）|

---

## 六、已知 follow-up

| 項目 | 說明 |
|------|------|
| 匯入 Phase 2 legacy alias | v3.0.0 舊樣板（單位/元件清冊/利用授權/控制項與AO）上傳會 SHEET_MISSING，需補 sheet_handlers `_LEGACY_SHEET_NAME_ALIASES` |
| template SSP OSCAL tables 清理 | 現有 template SSP 仍有 components/LA/inventory 資料（非 project SSP）；功能上無影響但有冗餘資料；未來可評估是否清除 |
| MF 受評標的狀態預設值 | `status=null` 匯出/匯入均空白；若需預設 active 可在 `_build_sc_from_mf_default` 補 fallback |
| 系統元件 OSCAL type enum 中文化 | Excel 下拉仍顯示英文（service/hardware/etc.）；FE 顯示有中文 label，Excel 可考慮同步 |
