Phase 2 A1 — T6 final(A1 task arc 完整收口)

日期:2026-05-19 本檔角色:A1 task arc 第三份 summary,承接 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)


§1

一句話總結

承接 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。


§2

本 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 shippedBE+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

§3

完整 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 匯入樣板兩個下載點

§4

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 ✅


§5

測試結果

$ 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)


§6

已知 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 收口時做

§7

部署 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 後)

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 完整版範本)

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 強制重算

§8

規範遵守清單


§9

下一階段建議

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

§10

結語

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。