# Phase 2 A1 — T6 final（A1 task arc 完整收口）

> **日期**：2026-05-19
> **本檔角色**：A1 task arc 第三份 summary，承接 [SUMMARY-be-partial-ship.md](SUMMARY-be-partial-ship.md)（T4+T5+partial T7 BE），涵蓋 T6 BE+FE+3 輪 UX polish = **A1 整體 BE+FE shipped**
> **狀態**：**A1 BE+FE shipped ✅**（T0-T6 完成；T7 cucumber E2E pending follow-up）
> **剩下**：T7 完整 E2E（cucumber + 完整 BE smoke 需 user 端配齊 GitLab env）

---

## 一句話總結

承接 BE partial ship (T0-T5)，T6 收口本 session 完成 **7 個 commits**（BE 7 + FE 2，扣除 1 個 tracker doc commit）：BE framework-version-scoped 新 endpoint + FE 兩個下載點 + 3 輪 UX polish（hidden cols / VLOOKUP autofill / required body fill / 黃底 border + 範圍限縮 / role enum 對齊 ParticipantRole + cross-domain finding 紀錄）。BE 106 unit test 全綠。A1 整體 shipped，剩 T7 cucumber E2E。

---

## 本 session 完成的事

### T6 BE — Framework-version-scoped endpoint（commit `3171116`）

新 endpoint：
```
GET /api/1.0/ssp-import-template?framework_version_uid=<uid>&mode=blank&locale=
```

S1 場景：顧問訪談前下載「framework_version 全 catalog controls 樣板」（superset）。跟既有 MF-scoped endpoint（profile-scoped subset）互補。

範圍：
- `TemplateDataBundle.mf_uid` / `mf_name` 改 Optional
- App service `generate_by_framework_version()` + 3 helper
- DI wire 4 新 dep
- Route 加 `SspImportTemplateByFrameworkVersionResource`
- Error code 加 `GRC_FRAMEWORK_VERSION_NOT_FOUND` + `GRC_TEMPLATE_FRAMEWORK_VERSION_REQUIRED`
- design-A1.md §3.3 / §6.2.1 / §15.1 補
- +11 unit test

### T6 FE — 兩個下載點 + Dialog（commit `e0ff8f1` + `00b6662`）

| 場景 | UI 入口 | 對應 BE endpoint |
|------|---------|----------------|
| S1 訪談前 | 列表頁右上「新增合規資源庫」menu → 新「下載 SSP 匯入樣板」項 → Dialog 選 framework + version | FW-version-scoped |
| S3 MF 已存在後 | MF template-edit 頁批次維護 menu 加 2 項（空白 / 已填） | MF-scoped |

範圍：
- 新元件 `DownloadSspBlankTemplateDialog.vue`（兩層 picker，後續 fix-1 改 vertical stack）
- `ModuleFrameTemplateService` 加 2 個 method
- `api.js` 加 2 個 constant
- `ModuleFrame.vue` createMenuItems 加項
- `ModuleFrameTemplateEditView.vue` batchMenuItems 加 2 項
- i18n zh-tw + en 9 個 key
- 新 changelog

### Tracker update（commit `66d0d13`）

A1 status `BE partial shipped` → `BE+FE shipped`，commit chain 完整紀錄。

### UX polish round 1（commit `fbcf9f2`）— 5 個問題

使用者下載樣板實際驗證後反饋：

| # | 問題 | 修補機制 |
|---|------|---------|
| 1 | FE Dialog 框架名跑版 | 兩 dropdown 改 vertical stack (`00b6662`) |
| 2 | UID 欄位 user 看到困惑 | `ColumnDef.hidden=True` + openpyxl `column_dimensions[X].hidden`（01 framework_version_uid/profile_uid + 07 statement_id）|
| 3 | 訪談時要手 key email/name | `ColumnDef.autofill_from` + `lookups_helpers` + INDEX/MATCH 公式 — 03/04/05 sheet user 選 matched_* 後對應欄位自動帶入 |
| 4 | 07 控制項看不出哪要填 | `impl_status` + `statement` 改 required（header 自動黃底）|
| 5 | 08 程序書 doc_no/doc_type/version | 系統 schema 無 → 移除欄位 |

- TEMPLATE_VERSION bump v1.0.0 → v1.1.0
- +15 unit test

### UX polish round 2（commit `690f25c`）— 3 個追加

| # | 問題 | 修補 |
|---|------|------|
| 1 | 黃底只 header（user 期待整欄 body 也黃）| `_apply_required_body_fill` 對 required column body 套黃底 |
| 2 | VLOOKUP 不自動算 | `Workbook.calculation.fullCalcOnLoad = True` 強制 Excel 開檔重算 |
| 3 | 03 role 應 required + 對齊系統四角色 | enum 改 `manager/reviewer/auditor/viewer` + required=True |

- +5 unit test

### UX polish round 3（commit `faade8d` + `2b1e93c`）— 黃底細節

- `faade8d`：黃底蓋掉 Excel gridlines → `CELL_THIN_BORDER` 加深灰 thin border 到 header + required body
- `2b1e93c`：空 sheet 黃底延伸 200 row 視覺糟 → 範圍限縮到 `min(1 + len(filled_rows), MAX_DATA_ROW)`，blank mode 不套 body（只 header）

### Cross-domain role 不一致紀錄（commit `b6b4870`）

T6 fix2-C 把 SHEET_PERSONS role 改 ParticipantRole 後 audit 既有 docx 匯入流程發現：

- OSCAL `oscal_responsible_parties.role_id` 跟 GRC `project_participants.role` (ParticipantRole) **兩條獨立資料流，沒 mapping**
- 既有 docx parser line 303 `role_id=parsed.role or ""` 無 validation
- dev DB 可能累積雜亂字串

處理：
- `design-A1.md §15.3` 紀錄完整 finding + A2 parser contract
- `docs/issues/pending/2026-05-19-person-role-cross-domain-inconsistency.md` 含 4 個修補計劃（A2 必做 / docx normalize / DB audit / 雙寫設計）
- T6 不動既有 docx parser；A2 開工時實作修補 A

---

## 完整 commit 鏈（A1 整 task arc）

### BE — 16 commits 未 push（feature/ssp-import-export-phase2）

```
2b1e93c  tweak(ssp-import-template): T6 fix4-A 黃底範圍限縮到實際 filled rows
b6b4870  docs(ssp-import-template): T6 fix2-C 跨域 role 不一致 — design.md §15.3 + issue
faade8d  tweak(ssp-import-template): T6 fix3-A — 黃底 cell 加 thin border 補回視覺分隔
690f25c  feat(ssp-import-template): T6 fix2 round 2 — required body fill + recalc + role enum
fbcf9f2  feat(ssp-import-template): T6 fix UX polish — hidden cols + VLOOKUP + ref_docs schema
66d0d13  docs(ssp-import-export-phase2): A1 T6 FE shipped — update tracker README
3171116  feat(ssp-import-template): A1 T6 BE — framework-version-scoped endpoint (superset)
c653f05  docs(ssp-import-export-phase2): A1 BE partial ship task arc 收口 — SUMMARY + handoff prompt
46b8999  docs(ssp-import-export-phase2): A1 partial T7 — BE smoke + changelog + tracker
419907d  feat(ssp-import-template): A1 T5 07_控制項與AO sheet — profile-scoped 父子 row + MF defaults
c3de9fa  feat(ssp-import-template): A1 T4 filled mode 非控制項 sheet — 6 領域預填 + DI
f14a942  docs(ssp-import-export-phase2): A1 partial summary — T0-T3 收口 + 換 session 交接
ffd5d63  feat(ssp-import-template): A1 T3 blank mode — generator 主邏輯 + lookup wiring
f68525f  feat(ssp-import-template): A1 T2 generator base — sheet defs + styles + lookup + DV helpers
d9d54c2  feat(ssp-import-template): A1 T1 skeleton — route + app service + DI 接通
f59c4ff  docs(ssp-import-export-phase2): A1 T0 verify 結果回填 design.md (4 處)
b18db55  docs(ssp-import-export-phase2): A1 phase docs — design + implementation plan
```

外加最終收尾 commit（含 round 3 changelog + 本 SUMMARY）尚未 commit。

### FE — 2 commits 未 push（feature/ssp-import-export-phase2）

```
00b6662  tweak(ssp-import-template): T6 fix-1 Dialog 框架名跑版 — 兩 dropdown 改 vertical stack
e0ff8f1  feat(ssp-import-template): A1 T6 FE — Excel 匯入樣板兩個下載點
```

---

## A1 整體規範文件齊全度

### Changelog（6 份，含本次收尾 round 3）

| 檔案 | 主題 | Commit |
|------|------|--------|
| `2026-05-19-feat-mf-ssp-import-template-download.md` | A1 T0-T5 + partial T7 BE base | b18db55 → 419907d |
| `2026-05-19-feat-mf-ssp-import-template-by-framework-version.md` | T6 BE FW-version-scoped endpoint | 3171116 |
| `2026-05-19-feat-mf-ssp-import-template-download-fe.md` (FE) | T6 FE 兩個下載點 + dialog | e0ff8f1 |
| `2026-05-19-feat-ssp-import-template-ux-polish.md` | UX round 1 (5 fix) | fbcf9f2 |
| `2026-05-19-feat-ssp-import-template-ux-polish-round2.md` | UX round 2 (3 fix) | 690f25c |
| `2026-05-19-tweak-ssp-import-template-yellow-fill-polish.md` | UX round 3 (border + range) | faade8d + 2b1e93c |

### Issue（1 份）

`docs/issues/pending/2026-05-19-person-role-cross-domain-inconsistency.md` — Person role 跨 OSCAL/GRC domain 不一致，4 個修補計劃（A2 phase 開工必看）

### Design

`docs/features/FR-011.2-2605-ssp-import-export-phase2/design-A1.md` v1.2，含：
- §3.1 主下載 endpoint（既有）
- §3.2 權限檢查
- §3.3 framework-version-scoped endpoint（T6 新增）
- §6.2.1 framework-version-scoped 資料組裝（T6 新增）
- §11 Acceptance Criteria（含 T6 新項）
- §14 樣板演進 SemVer SOP
- §15.1 T6 新 endpoint reconciliation
- §15.2 T6 fix UX polish 5 項
- §15.3 跨域 role 不一致 finding（必看）

### Tracker

`docs/features/FR-011.2-2605-ssp-import-export-phase2/README.md` A1 row 標 `BE+FE shipped ✅`

---

## 測試結果

```
$ pytest tests/test_excel_template_*.py tests/test_ssp_import_template_app_service.py
106 passed (Unit test 全綠)
```

範圍：
- `test_excel_template_base.py` — 26（含 ColumnDef invariant + lookup_builder + DV builder + helpers）
- `test_excel_template_generator_blank.py` — 25（含 structure / styling / DV / hidden cols / autofill / border / required body fill / role enum）
- `test_excel_template_generator_filled.py` — 20（filled mode 各 sheet）
- `test_ssp_import_template_app_service.py` — 35（app service helpers + T6 framework_version + helpers）

**累計**：106 全綠（A1 partial ship 時 71 + T6 改動 +35 = 106）

---

## 已知 follow-up / 未完項

| # | 項目 | 嚴重度 | 處理時機 |
|---|------|--------|---------|
| 1 | T7 cucumber E2E + 完整 BE smoke | 預期未完 | 後續 session — 跨 compliance-manager-test repo |
| 2 | VLOOKUP autofill Excel 開檔可能不自動算 | UX | user 暫 skip；可按 Ctrl+Alt+F9 強制重算；或後續改用其他機制（INDIRECT / Data Validation macro）|
| 3 | Person role 跨 OSCAL/GRC domain 不一致 | Medium | issue 已開；A2 phase 開工時實作修補 A（Excel parser enum validation 必做）|
| 4 | 既有 docx parser role normalize / dev DB 髒資料 audit | Medium | A2 phase 後考慮（issue 內含修補計劃）|
| 5 | OSCAL party ↔ project_participant 雙寫設計 | 大議題 | 不在 A1/A2 範圍，未來 OSCAL 匯出規劃時考慮 |
| 6 | 02_單位 OSCAL role 欄位（系統未 expose UI）| 預期 | 保留 optional 不動；未來 OSCAL 匯出時用 |
| 7 | BE boot 撞 jedi-issue GitLab env | 環境 | A0.1 既有 follow-up；user 端配齊後可跑完整 smoke |
| 8 | `test_write_parties_refreshes_existing_party_in_place` pre-existing fail | low | 非 A1/T6 引入 |
| 9 | jedi-oscal 仍 path-dep | 例行 | Phase 2 整體完工再一次性 bump Nexus |
| 10 | `pyproject.toml` path-dep 改動還原 pin Nexus | 例行 | Phase 2 收口時做 |

---

## 部署 handover

### 對 dev DB

無需 migration — A1 純粹是新 endpoint + 新 generator，不動 schema。

### 對 staging / production

- A1 完整 ship 後（含 T7 E2E + 完整 BE smoke）才考慮 deploy
- BE boot 需配齊 GitLab / GitHub env vars（A0.1 既有 follow-up）
- jedi-oscal 仍 path-dep — Phase 2 整體完工再一次性 bump Nexus

### BE 重啟（user 端配齊 env 後）

```bash
lsof -ti:8000 | xargs kill -9
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
set -a; source .env; set +a
nohup poetry run python main_app.py > /dev/null 2>&1 &
```

### 完整 BE smoke（T7 完整版範本）

```bash
TOKEN="..."  # from dev login
MF_UID="..." # dev DB existing MF uid
FW_VERSION_UID="..."  # dev DB existing framework_version uid

# MF-scoped blank
curl -H "Authorization: Bearer $TOKEN" -H "X-Tenant-ID: 102" \
     "http://localhost:8000/api/1.0/module-frame/$MF_UID/ssp-import-template?mode=blank" \
     -o /tmp/template_mf_blank.xlsx

# MF-scoped filled
curl -H "Authorization: Bearer $TOKEN" \
     "http://localhost:8000/api/1.0/module-frame/$MF_UID/ssp-import-template?mode=filled" \
     -o /tmp/template_mf_filled.xlsx

# FW-version-scoped blank (T6 新增)
curl -H "Authorization: Bearer $TOKEN" \
     "http://localhost:8000/api/1.0/ssp-import-template?framework_version_uid=$FW_VERSION_UID&mode=blank" \
     -o /tmp/template_fw_blank.xlsx

# Verify via openpyxl
poetry run python3 -c "
from openpyxl import load_workbook
for fn in ['/tmp/template_mf_blank.xlsx', '/tmp/template_mf_filled.xlsx', '/tmp/template_fw_blank.xlsx']:
    wb = load_workbook(fn)
    visible = [s for s in wb.sheetnames if not s.startswith('_lookup_')]
    print(f'{fn}: total={len(wb.sheetnames)}, visible={len(visible)}')"
```

### FE 重啟

FE 有 hot reload，dev server 自動更新；但建議 hard refresh 瀏覽器（避免 cache）。Dialog 元件 + i18n 改動需重新 build production 才會生效。

### Manual 驗證 UI

| 場景 | 驗證步驟 | 預期 |
|------|---------|------|
| S1 訪談前 | 列表頁右上「新增合規資源庫」→ 點「下載 SSP 匯入樣板」→ 選 framework + version → 下載 | 下載 xlsx，filename `ssp_template_<fw>_<version>_blank_<date>.xlsx` |
| S3 MF 已存在 | 進 MF template-edit 頁 → 批次維護 → 選「下載 SSP 匯入樣板（空白）/（已填）」 | 下載對應 xlsx |
| 黃底 + border | 開 xlsx 看 03_參與人員 sheet | A 欄 / B 欄 / F 欄 header 黃底 + thin border |
| 黃底範圍 | 同上看 row 2-50 | blank：body 無黃底；filled：實際 row 黃底 |
| UID 隱藏 | 開 xlsx 看 01_基本資料 | E/F 欄 (framework_version_uid / profile_uid) 應隱藏 |
| Role enum | F 欄下拉 | `manager / reviewer / auditor / viewer` |
| 程序書欄位 | 08_程序書 sheet | 只有 doc_name + description 兩欄 |
| VLOOKUP（嘗試）| D 欄選 matched_user → 看 A/B/C 欄 | 預期自動帶入；若沒動按 Ctrl+Alt+F9 強制重算 |

---

## 規範遵守清單

- [x] 顯式 `git add <file>`，禁 `-am` / `-A` — 全 7 個 T6 commits（BE 5 個 + FE 2 個）+ doc commits 都遵守
- [x] 所有 commits 含 `Co-Authored-By: Claude Opus 4.7 (1M context)` footer
- [x] jedi-oscal 沒動，仍 path-dep
- [x] `pyproject.toml` dev-only path-dep 改動沒被 commit
- [x] DDD 嚴格分層（Route 不碰 DB，App Service `@transaction`，Generator 純函式）
- [x] @transaction 寫對位置
- [x] BE 重啟提醒（每次 BE service 改動都告知 user 要重啟）
- [x] T6 fix 流程：每輪 user 反饋 → 修補 → test → commit
- [x] 跨 repo 切換時提醒（BE / FE 不同 repo，commit 分開）
- [x] 跨域 role 不一致紀錄 issue（不擠在 changelog）
- [x] design.md §15 reconciliation 段補 T6 變動

---

## 下一階段建議

A1 已 BE+FE shipped。Phase 2 next stop：

### A2 — Excel Parser + 解析 API（中型）

依賴 A1 已 ship。涵蓋：
- Excel 上傳 + 解析 + parse_uid TTL
- 03 role 強制 enum validation（issue 修補 A 必做）
- A2 預覽 UI + Confirm 寫入（A5 範圍）
- 區分 superset upload（建新 MF）vs MF update upload（更新既有 MF）兩條 import flow

### B1 — Docx 樣板 + generator 骨架（中型）

可平行 A2；依賴 A0.1。涵蓋：
- SSP docx 匯出樣板 + jedi-docx 整合
- 對齊 OSCAL responsible_party / system_implementation_item / control_implementation

### T7 — A1 E2E（小型補完）

跨 compliance-manager-test repo：
- cucumber feature 兩 scenario（MF-scoped + FW-version-scoped 下載）
- Playwright step + page object
- openpyxl 驗 sheet 結構 / 黃底 / hidden cols
- BE 完整 smoke 需 user 端配齊 GitLab env

---

## 結語

A1 task arc 跨 3 session 完工：
- session 1 (T0-T3)：design + plan + skeleton + generator base + blank mode
- session 2 (T4-T5 + partial T7)：filled mode + 控制項與AO + BE smoke
- session 3 (T6 + 3 輪 UX polish)：FW-version-scoped endpoint + FE 兩個下載點 + UX 反饋細節整修

`feature/ssp-import-export-phase2` branch 累計 17 commits（含本份 SUMMARY 收尾 commit）。BE 106 unit test 全綠。

A1 整體 BE+FE shipped。剩 T7 E2E 跨 test repo 留 follow-up。
