SSP 匯出 Track B — 收尾 SUMMARY(2026-05-22)

§1

一句話摘要

Track B(SSP 匯出 B1~B6)全部 shipped,含 6 種格式匯出(docx/pdf/odt/json/yaml/xml)、CMMC 正式 DOCX 格式、LibreOffice 跨平台支援、中文檔名修正。


§2

Commits 清單

BE(compliance-manager-be)

Commit 說明
062782d feat: Track B B1~B4 — docx generator + MF/SSP version loaders + LibreOffice converter + API routes
25909f2 feat: B5 OSCAL JSON/XML/YAML 匯出(SSP version route)
4fde105 fix: DOCX 匯出 control_name / ao_name 空白(catalog 關聯未映射)
8df2525 feat: B6 DOCX 格式升級 — 對齊 CMMC SSP 正式樣板(本次)
8ee55f5 fix: LibreOffice binary 自動偵測(macOS soffice / Linux libreoffice)(本次)
43a9389 fix: 中文系統名稱下載檔名顯示為底線(BE — RFC 5987)(本次)

FE(compliance-manager-fe)

Commit 說明
7231b6a feat: B6 SSP 文件匯出按鈕(MF + 專案 SSP 版本,6 種格式)
c21372c fix: 下載檔名中文被替換為底線(FE — filename regex)(本次)

§3

功能說明(改動範圍)

B1~B4:核心匯出 pipeline(062782d)

  • SspDocxGenerator:docxtpl + python-docx 混合渲染
  • MfSspContentLoader / SspVersionContentLoader:從 MF 或 SSP 版本組裝 SspExportDataModel
  • SspLibreOfficeConverter:subprocess 呼叫 LibreOffice 產 PDF/ODT
  • API routes:/module-frame/<uid>/ssp-export + /ssp/<uid>/export

B5:OSCAL 格式(25909f2)

  • /ssp/<uid>/export?format=json|yaml|xml
  • 同一 route,透過 SystemSecurityPlanYamlMapper 序列化 jedi-oscal entity

B6 DOCX 格式升級(8df2525)

  • 封面:標題居中、系統名稱、metadata 表(Version/Date/Prepared by)
  • System Information:動態 loop,只顯示有值的列
  • Responsible Organization:動態 kv rows
  • Participants:合併人員表(Name / Role / Email),過濾 organization 類型
  • Assessment Objectives:bullet list(去掉 statement_id 前綴重複問題)
  • 標題、欄位名稱:全純英文,移除中英夾雜
  • 修正 docxtpl.get_docx() 回傳未渲染原件的 bug(改用 save → Document

LibreOffice 跨平台(8ee55f5)

  • 新增 _resolve_libreoffice_cmd() 自動偵測:env var → PATH libreoffice → PATH soffice → macOS app bundle
  • 解決開發機 macOS 只有 soffice 而非 libreoffice 導致 PDF/ODT 500

中文檔名(43a9389 BE + c21372c FE)

  • BE_UNSAFE_FILENAME_RE 取代原 ASCII-only 過濾;Route 加 RFC 5987 filename*=UTF-8''
  • FE:3 處 .replace(/[^a-zA-Z0-9-_]/g, '_') 改為 .replace(/[\\/:*?"<>|\x00-\x1f]/g, '_')
  • 結果:SSP_亞O航空專案_2026-05-22.docx(不再是 SSP__O____2026-05-22.docx

§4

Changelog 清單

檔案 類型
docs/changelog/2026-05-22-feat-ssp-export-b2-b3-b4-content-loader-api-converter.md feat
docs/changelog/2026-05-22-feat-ssp-export-b5-oscal-json-yaml-xml.md feat
docs/changelog/2026-05-22-feat-ssp-export-b6-fe-export-button.md feat
docs/changelog/2026-05-22-fix-ssp-docx-export-missing-control-ao-names.md fix
docs/changelog/2026-05-22-feat-ssp-docx-template-rebuild.md feat
docs/changelog/2026-05-22-fix-ssp-export-libreoffice-binary-detect.md fix
docs/changelog/2026-05-22-fix-ssp-export-unicode-filename.md fix

§5

已知 Follow-up(非阻塞)

項目 說明
_resolve_ssp_id 多版本 SSP MF 有 3 個 SSP 共用 profile_id,get_one() 隨機取一。實務沒差(3 版本都有 items),但未來若有版本差異會 flaky,應改為明確取 latest
AO 無中文翻譯 catalog 尚無 ZH 翻譯,AO section 僅顯示英文 ao_name
network_architecture / data_flow 空白 MF/SSP version loader 都回空字串,DB 尚無對應欄位
E2E 測試 Track B 無 cucumber E2E,後續可補

§6

Working Tree 狀態

pyproject.toml    M   dev-only jedi-oscal path dep — 不 commit

其餘工作樹乾淨。


§7

部署 Handover

  • BE 需要 LibreOffice 安裝(PDF/ODT)。macOS 開發機用 soffice(Homebrew),Linux production 用 libreoffice,均自動偵測。若 binary 在非標準路徑,設 LIBREOFFICE_CMD env var。
  • FE 不需重新 build(Vite dev server hot reload),production 需 re-build。
  • pyproject.toml 有 jedi-oscal path dep 待恢復 Nexus pin(待 jedi-oscal 正式發版後執行)。