# A5 Task Arc Final SUMMARY — 預覽 UI + Confirm 寫入

> **時程**：2026-05-20 (Session A docs) → 2026-05-21 (Session B BE + Session C FE)
> **狀態**：BE + FE shipped ✅；manual smoke checklist 待 user 跑
> **跨 repo**：compliance-manager-be + compliance-manager-fe（jedi-* 不動）

---

## 1. 整段在幹嘛（一句話）

把 A4 ship 後的「parser 解析 + 自動配對 → 寫入 SSP」這條 BE pipeline，補上「user 預覽頁拍板 → 套到 confirm」這條 user-facing path — Track A Excel 匯入端到端完整可用。

---

## 2. 三個 Session 範圍

| Session | 時間 | 範圍 | 主要 commit |
|---------|------|------|-------------|
| **A** (docs) | 2026-05-20 | design-A5.md + implementation-plan-A5.md + T0 6 verify | 5d979bf (BE) |
| **B** (BE) | 2026-05-21 上午 | T1-T8：schema 結構化 + inline_creates + decisions + content_overrides + confirm 整合 + 54 個 pytest | 535b931 → 6f926e0 + c61ef02 (BE) |
| **C** (FE) | 2026-05-21 下午 | T9-T14：service + store + router + 上傳頁 + 5 sheet preview + RowActionMenu + InlineCreateDialog + Confirm Dialog + i18n + smoke checklist | c95d02a → 332b393 (FE) |

---

## 3. Commit 清單

### BE repo (feature/ssp-import-export-phase2)

```
c091824 docs(ssp-import-export-phase2): A5 Session B 收尾 - changelog + tracker + handoff B→C
6f926e0 test(oscal): A5 T7 unit + integration tests (54 個 a5 test)
7ed9363 feat(oscal): A5 T4 confirm_import 整合 + atomicity 保證
56edd30 feat(oscal): A5 T3 _apply_decisions + _apply_content_overrides
5852cca feat(oscal): A5 T2 inline_creates handling + 4 domain service DI
535b931 feat(oscal): A5 T1 confirm request schema 定稿
c61ef02 docs(ssp-import-export-phase2): A5 T14 manual smoke checklist
+ A5 SUMMARY commit（本檔）
```

6+ 個 BE commits (Session B T1-T7 + T8 收尾 + T14 smoke checklist + SUMMARY)。

### FE repo (feature/ssp-import-export-phase2)

```
332b393 feat(fe): A5 T13 confirm Dialog + decision summary
0cf3058 feat(fe): A5 T12 RowActionMenu + InlineCreateDialog + EntityPickerDialog
2412e74 feat(fe): A5 T11 5 個 sheet preview + MatchStatusCell
24622ee feat(fe): A5 T10 ImportExcelPage + ImportExcelPreviewPage shell
c95d02a feat(fe): A5 T9 SspExcelImportService + Pinia store + 3 routes
+ A5 FE changelog commit（隨本 SUMMARY 一起 ship）
```

5+ 個 FE commits (T9-T13 + changelog)。

### 跨 repo 改動範圍

| Repo | 新檔 | 修改檔 | 行數 |
|------|------|--------|------|
| BE | 0 程式碼新檔 + 1 docs（smoke checklist）| 5 程式碼檔（serializers / app service / DI container / error code）+ 4 test 檔（54 test）+ 2 docs（design / changelog）| ~1300+ |
| FE | 11 新檔（service / store + 2 page + 6 component + 2 i18n JSON）+ 1 changelog | 5 修改檔（router / api.js / menu.json × 2 / locales index.js）| ~1500+ |

---

## 4. 行為差異（user-facing）

### 4.1 ship 前（A4 ship 後 state）

- Excel 匯入流程：BE 可解析、可寫 SSP，但無 user-facing UI
- Confirm payload：BE 接 `decisions = List[Dict]` / `overrides = Dict` 彈性 schema，user decision 無路徑
- 路由 `/module-frame/import-excel` 不存在

### 4.2 ship 後

| 功能 | 行為 |
|------|------|
| **路由** | `/module-frame/import-excel` (create) + `/module-frame/:uid/import-excel` (update) + `/module-frame/import-excel/preview/:parseUid` (preview) 三條路由活了 |
| **上傳頁** | create mode：framework + version Dropdown picker。update mode：直接 file upload。POST parse → 自動 redirect preview |
| **預覽頁** | 5 sheet TabView（devices / info_systems / leveraged / parties / controls）+ badge（unmatched 紅 / fuzzy 橘） |
| **Sheet DataTable** | devices / info_systems 全功能（matched / fuzzy / unmatched 標示 + 操作 menu）；controls row expansion 顯示 objectives；parties union org+person；leveraged status-only（無 inline action）|
| **Unmatched 三路徑** | RowActionMenu popup：選現有 (EntityPickerDialog) / 新建 (InlineCreateDialog 4 entity form) / 純文字保留 / 重置 |
| **編輯持久** | localStorage `ssp-excel-import:<parse_uid>` 暫存 decisions + inlineCreates + contentOverrides；TTL 7 天對齊 BE parse job；reload 自動恢復 |
| **Confirm Dialog** | 顯示 decisionSummary 4 計數（自動配對 / 已改選 / 新建 / 純文字保留）+ inlineCreatesCount hint；點確定 → POST confirm → 成功 redirect MF 詳細頁 + clear localStorage |
| **i18n** | zh-tw + en 補 80+ 個 key；切語言所有 label / Dialog / Tag 都翻譯 |
| **BE schema 結構化** | `decisions = List[Nested(DecisionSchema)]` + `inline_creates = List[Nested(InlineCreateSchema)]` + `content_overrides = Dict`；舊 caller 傳 `{}` / `{"decisions": [], "overrides": {}}` 仍合法（defensive `.get(...)` 模式）|
| **Inline create 4 entity** | confirm `@transaction` 內依序套：content_overrides → inline_creates（device / info_system / org_unit / user）→ decisions → A4 8-step write；失敗整段 rollback |
| **import_summary** | A4 既有 + 加 `inline_created_devices` / `_info_systems` / `_org_units` / `_users` / `decision_applied_count` / `skipped_as_text_count` |

---

## 5. 規範文件清單

### BE repo

| 文件 | 路徑 |
|------|------|
| Design + Plan | `docs/features/FR-011.2-2605-ssp-import-export-phase2/design-A5.md` (含 §10.1-10.4 共 12 條偏差) + `implementation-plan-A5.md` |
| Changelog | `docs/changelog/2026-05-21-feat-ssp-excel-import-phase2-a5-be.md` (type=feat) |
| Smoke checklist | `docs/features/FR-011.2-2605-ssp-import-export-phase2/handoff/2026-05-21-a5-smoke-checklist.md` (8 段 user 自跑 checklist) |
| 本 SUMMARY | `docs/features/FR-011.2-2605-ssp-import-export-phase2/handoff/2026-05-21-a5-SUMMARY.md` |
| 對話歷史 | 待 user 匯出原始對話 dump 到 `docs/conversation-history/2026-05-21/ssp-import-export-phase2-A5/` (兩層目錄，原始 dump only) |
| Tracker README | `docs/features/FR-011.2-2605-ssp-import-export-phase2/README.md` A5 row 改 BE+FE shipped ✅ |

### FE repo

| 文件 | 路徑 |
|------|------|
| Changelog | `docs/changelog/2026-05-21-feat-ssp-excel-import-phase2-a5-fe.md` |

---

## 6. 15 條偏差紀錄（design-A5 §10.1-10.3 詳細）

### §10.1 T0 pre-flight verify 偏差 (6 條，Session B 開工前)

1. **10.1.1** — Domain service `.add()` 方法名 3/4 不一致（device → add_device / info_sys → add ✓ / org_unit → add_org_unit / user → add_user）→ `_apply_inline_creates` 用 entity_type → method-name dispatch
2. **10.1.2** — `UserDomainService.add_user` 無 `send_invite` 機制 → 不發邀請信，user 帳號由 admin 後續手動處理
3. **10.1.3** — DELETE endpoint + `discard_parse` 已 ship (A2 階段) → T5 縮 scope ~3 個 pytest 併入 T7
4. **10.1.4** — content_overrides 命名沿 docx pattern（`implementation` + `objectives[<key>]`）
5. **10.1.5** — Error code 起始序號 400=071 / 409=031 / 412=027
6. **10.1.6** — Tests 跳過 schema 驗證 → app service 用 defensive `.get(...) or []` 讀

### §10.2 BE 實作偏差 (1 條)

7. **10.2.1** — Decisions 對 write-time FK 不直接 propagate（known limitation）：A5 `_apply_decisions` 蓋 parsed_result 的 `matched_*_id`，但 `_write_all_data` Step 7 by-key 對齊時被 orchestrator 結果覆寫。Inline creates 跟 stats 正確，但 user 改 ID 不一定反映 DB。Follow-up `F-A5-decision-write-propagation` — 需動 A4 base.py reconciler 加 `_already_resolved_by_decision()` hook，跨 §2.3 邊界，待 Session C smoke 後評估 priority

### §10.3 FE 實作偏差 (8 條，Session C)

8. **10.3.1** — FE 檔案結構照 FE 慣例（service 平鋪 / stores 複數 / config/router/index.js / i18n JSON）— design §3.2 路徑寫得太早未驗 FE repo
9. **10.3.2** — 5 sheet 而非 9 sheet（BE DecisionSchema OneOf 限制；其他 4 sheet 走 content_overrides 留 T14 polish）
10. **10.3.3** — Upload + Preview 拆 2 個 route（跟 docx pattern 不同；換 reload 恢復 + share link）
11. **10.3.4** — RowActionMenu(menu) + InlineCreateDialog + EntityPickerDialog 三檔代替原 plan UnmatchedRow + FuzzyBadge；MatchStatusCell 已含 fuzzy 顯示
12. **10.3.5** — Leveraged sheet RowActionMenu 不接（BE InlineCreateSchema OneOf 不含 leveraged + 無 party menu API）
13. **10.3.6** — localStorage shape 跟 §4.3 example 不一致（store 用 nested dict + Map<localId> 而非 flat array；trade-off：避免 splice shift；buildConfirmPayload 才 enumerate 成 BE schema array）
14. **10.3.7** — T14 manual smoke 拋給 user 跑（agent 無 browser interactive；agent 完成的是 build:DEV verify；checklist 在 handoff/2026-05-21-a5-smoke-checklist.md）
15. **10.3.8** — T11 從 7 個獨立 sheet preview 變 5 sheet + MatchStatusCell 共用元件（實際 9 個 .vue 檔：5 sheet preview + 3 共用元件 + 1 cell；比 plan 7 個多但拆共用元件好維護）

---

## 7. 已知 follow-up

| ID | 描述 | Priority | 觸發條件 |
|----|------|----------|----------|
| `F-A5-decision-write-propagation` | A5 decisions 設的 `matched_*_id` 在 write-time 被 orchestrator 覆寫 | medium-high | Session C smoke 後評估 user 是否真的踩到 |
| `F-A5-leveraged-action` | Leveraged sheet action column 為 `─`（無 party menu API + BE 不支援 leveraged inline） | medium | 後續評估 |
| `F-A5-content-overrides-ui` | SheetPreviewBasic (01_基本資料) + SheetPreviewRefDocs (08_程序書) 未實作 | medium | T14 polish 或下個 phase |
| `F-A5-cucumber` | cucumber regression 沿 F-A4-cucumber pattern | low | env 配齊那天一次性補 A1-A5 共 5 phase |
| `F-A5-user-invite-on-inline-create` | inline-create user 不發邀請信（add_user 無 send_invite） | low | 若客戶有需求再加 |

---

## 8. 部署 Handover

### 8.1 部署 dependency

- **jedi-* 套件**：不動（沒 bump version；feature 全完工才一次性 bump）
- **DB migration**：A5 無 schema 異動，無 SQL migration 需執行
- **Config**：無新環境變數

### 8.2 部署順序

1. **BE deploy** （`feature/ssp-import-export-phase2` → merge → main）
2. **FE deploy** （`feature/ssp-import-export-phase2` → merge → main + `npm run build:DEV/STG/PRD`）
3. **Smoke test**：照 `docs/features/FR-011.2-2605-ssp-import-export-phase2/handoff/2026-05-21-a5-smoke-checklist.md` 8 段
4. 若踩到 Follow-up 7.1 (`F-A5-decision-write-propagation`) → 視 user 重要度補 hotfix；否則暫留 follow-up

### 8.3 Manual smoke 重點

- ✅ Build verified（`npm run build:DEV` 通；ImportExcelPreviewPage 30 kB 進 dist）
- ✅ BE pytest 273 全綠（0 regression）
- ⏳ 待 user 跑 8 段 smoke：路由 / 預覽 / RowActionMenu / localStorage / Confirm / Discard / i18n / 已知限制觀察

---

## 9. 下一步建議

A5 ship 後 Track A Excel 匯入完整可用。Phase 2 後續：

- **Track A Excel 匯入** ✅ 完工（A1 樣板 + A2 parser + A3 matcher + A4 寫入 + A5 預覽 confirm）
- **Track B SSP 匯出** （B1-B6 6 phase 待開）— 預估 1-2 週

短期 follow-up 優先序：
1. **F-A5-decision-write-propagation** — 跑 manual smoke 後評估，若 user 真踩到就 hotfix
2. **F-A5-content-overrides-ui** — SheetPreviewBasic + SheetPreviewRefDocs；user 可在預覽頁編輯 metadata + 程序書連結文字
3. **Track B 開工** — 評估與 A5 ship 後資料模型是否一致

---

## 10. 致謝

A5 task arc 跨 3 session、2 repo、6 commits BE + 5 commits FE。Session A 拍板 3 個關鍵決策（confirm 階段 inline create / fuzzy auto-accept / FE 獨立路由）。Session B 把 BE schema 結構化並寫齊 54 個 pytest。Session C FE 用既有 docx import pattern 1:1 mirror，避免重造輪子。

12 條偏差紀錄全寫進 design-A5 §10.1-10.4 — 給未來讀者一個完整的「為什麼這樣做、不那樣做」回顧。

— End of A5 Final SUMMARY —
