# Bugfix Session 3 SUMMARY — Excel Update Flow 覆蓋語義修補

> **時程**：2026-05-21（接續同日 session 2 SUMMARY：`2026-05-21-bugfix-session2-SUMMARY.md`）
> **跨 repo**：compliance-manager-be + compliance-manager-fe

---

## 1. 這段時間在幹嘛（一句話）

Excel re-import（update flow）時，舊資料沒有被覆蓋（append 而非 overwrite），以及基本資料 / 控制項清單沒有隨 Excel 更新，本次統一修補。

---

## 2. 修補項目與根因

| # | Bug 描述 | 根因 | 修正位置 |
|---|---------|------|---------|
| 1 | Re-import devices/info_systems/leveraged → 重複 row | `WriteStrategy.write()` 只 add，未先刪舊 row | `write_strategy/base.py` |
| 2 | 取消勾選的控制項 default 殘留 | `write_excel_control_defaults()` 只 upsert | `module_frame_write_strategy.py` |
| 3 | 移除的參與人員 link 殘留 | `write_parties()` 只 upsert，stale link 未刪 | `module_frame_write_strategy.py` |
| 4 | Template-edit 控制項清單不隨 Excel 更新 | `_confirm_update_flow` 未更新 `oscal_profile.include_controls`（頁面讀 profile，非 defaults）| `ssp_excel_import_app_service.py` |
| 5 | 基本資料（名稱/類別/描述）不隨 Excel 更新 | `_confirm_update_flow` 未呼叫 `update_module_frame()`；即使呼叫也需傳 `locale`，否則只改主表不改 `module_frame_trans`（failover query 優先翻譯表）| `ssp_excel_import_app_service.py` |
| 6 | 導回 template-edit 時參與人員顯示舊筆數 | `useModuleFrameParties` 永久 module-scope cache，import 後未 invalidate | `ImportExcelPreviewPage.vue` + `useModuleFrameParties.js` |

---

## 3. Commit 清單（本次 session 3 未 commit，待使用者確認後提交）

### BE 未 commit 的改動
- `app/oscal/service/ssp_excel_import_app_service.py` — `_confirm_update_flow` + `_resolve_include_uids_for_update`
- `domain/oscal/service/write_strategy/base.py` — delete-before-insert
- `domain/oscal/strategy/module_frame_write_strategy.py` — full overwrite + stale link cleanup
- `di_containers/oscal/oscal_containers.py` — `refdoc_mapping_domain_service` 注入

### FE 未 commit 的改動
- `src/views/module_frame/ImportExcelPreviewPage.vue` — confirm dialog + parties cache invalidate
- `src/config/locales/i18n/*/ssp-excel-import.json` — `confirm_overwrite_*` keys

### Changelog
- `docs/changelog/2026-05-21-fix-ssp-excel-import-overwrite-mode.md`（已建立）

---

## 4. 架構關鍵決策

### WriteStrategy 整份覆蓋 vs upsert
- **devices / info_systems / leveraged**：整份覆蓋（delete all + insert）— 因為 row 本身無穩定 natural key，重複 row 無法去重
- **control_defaults + objectives**：整份覆蓋（先清空 MF 全部 defaults + refdoc mappings，再只寫 in-profile 的）
- **responsible_party links**：snapshot → upsert → 刪 stale（有 party_uuid 可追蹤，不需全刪全插）
- **reference_documents（程序書）**：保持 append-only（設計明確不覆蓋）

### `module_frame_trans` locale 陷阱
- `BaseRepositoryImpl.update(entity, locale=None)` 只改主表 `module_frames`
- `GET /module-frame/{uid}` 用 failover query，優先讀 `module_frame_trans`（翻譯表）
- 解法：`update_module_frame` 必須傳 `locale`（`user_context.locale` fallback `zh_Hant_TW`）

---

## 5. Follow-up

| 項目 | 說明 |
|------|------|
| Track B（SSP 匯出）| B1–B6 全部 pending，尚未開始 |
| Design-A4.md §11.3 | 本次偏差已補入 §11.3 |
| Cucumber E2E | A5 update flow 整份覆蓋行為尚無 regression test |
