SSP 匯入匯出 Phase 2 — 需求理解整理版

狀態:Phase 0+ — 需求理解 v5(A0.1 結構校正後) 建立日期:2026-05-18 最後更新:2026-05-19(v5:A0 後 review 發現 main 表缺、命名不一致、鉤稽雙路徑 → A0.1 結構重整補丁) 版本歷程

  • v1:草稿整理 + 11 個待釐清項
  • v2:Raymond 第一輪回覆 → Q1~Q11 resolved + 補充 OSCAL 匯出 + Excel 樣板設計
  • v3:誤判 — 主張建三張新 OSCAL mirror 表 + 廢既有通用表
  • v4:校正 — 既有表本就是 OSCAL system-implementation 多型鏡像,改走「擴充既有表」方案(→ A0 shipped)
  • v5:A0.1 結構重整 — main 表 / items rename / join 表 / 鉤稽路徑統一(詳見 design-A0.1.md + docs/analysis/2026-05-19-ssp-system-impl-restructure-rationale.md撰寫人:Claude(依 requirement.md 草稿整理) 下一步:A0.1 開工 → A1 / B1 平行

⚠️ v5 校正 — A0.1 結構重整摘要(讀 §2 前必看

A0 shipped 後 review 發現幾個結構問題:

  1. 既有 system_security_plan_system_implementations 表 = items 不是 main,缺 1:1 main 層
  2. A0 加的 information_system_id 跟既有 system_characteristics 中介路徑重疊
  3. OSCAL system-implementation 是 block(無 UUID),DB 仍應有 main 表(為 PG 規範 + block-level metadata anchor)
  4. 表名 ssp_* 前綴慣例不一致

v5 補丁(A0.1)

項目 v4(A0 shipped) v5(A0.1 校正後)
Items 表名 system_security_plan_system_implementations ssp_system_implementation_items
Main 表 ❌ 無 ssp_system_implementations(1:1 per scope)
Join 表 ❌ 無 ssp_inventory_item_components(M:N)
Items 鉤稽 information_system information_system_id 直連 tenant system_characteristic_id 走 SSP 中介
system-implementation.users[] 列「視需求才做」 不做(既有 oscal_parties cover 人員需求)

詳細 A0.1 規格見:

  • docs/features/FR-011.2-2605-ssp-import-export-phase2/design-A0.1.md
  • docs/features/FR-011.2-2605-ssp-import-export-phase2/implementation-plan-A0.1.md
  • docs/analysis/2026-05-19-ssp-system-impl-restructure-rationale.md

0. 文件用途

這份不是正式 spec,是 Claude 把 requirement.md 草稿讀完之後,把「我理解你想做的事情」用比較結構化的方式寫回來,方便:

  1. raymond 一眼看出有沒有理解錯
  2. 開始切階段、寫 design 之前先對齊認知
  3. 列出我看到「草稿沒寫清楚」或「需要你決策」的項目

確認過後再進入 brainstorm + design.md + implementation-plan.md + test-plan.md。


1. 需求背景 — 為什麼要做這件事

1.1 「合規資源庫」是什麼

module_frame 是專案的範本層 — 顧問先把客戶現有的安全控制現況、政策程序書、組織單位、參與人員、設備、系統等資訊整理進「合規資源庫」,之後客戶建專案時,這些資訊會被當成預設值帶入該專案的 SSP,省去重複輸入,也作為 OSCAL 匯出的資料來源。

1.2 目前匯入匯出能力的限制

路徑 能匯什麼 限制
Docx 匯入(已上線 v2) metadata / parties / leveraged services / 控制項實作 / AOs 來源是顧問訪談後手寫的 SSP 草稿 docx,客戶不一定有這份文件
Excel 匯入(舊版) 只匯「控制項現況說明」+「AO 現況說明」+「參考程序書」 涵蓋面很窄,缺基本資料、設備、單位、人員、系統
Excel 匯出 現況說明 Excel 樣板下載 同上,只覆蓋現況說明
SSP 文件匯出 (目前沒有;OSCAL JSON 匯出有) 客戶想要的是可讀的 docx/pdf,不是 OSCAL JSON

1.3 真正的痛點

  • 顧問端:訪談時想用 Excel 收資料(客戶熟悉 Excel),但目前 Excel 只能收一小部分,其他還是要靠 docx 或手動進系統建。
  • 客戶端:想拿到一份完整可讀的 SSP 文件(docx / pdf)作為交付物,目前系統只能匯 OSCAL 結構化資料。
  • 資料一致性:Excel 匯入後沒有跟「設備 / 單位 / 人員 / 系統」做鉤稽,匯進來的是孤立字串,沒辦法被後續流程引用。

1.4 本期目標(一句話)

讓**「合規資源庫」的所有主要資料領域**都能透過 Excel 雙向同步(匯入 / 匯出),並讓「合規資源庫」與「專案 SSP 版本」都能匯出成可讀的 SSP 文件(docx / pdf / odt)+ OSCAL 結構化格式(JSON / XML / YAML)。

1.5 Raymond 第一輪回覆補充(2026-05-18)

補充 1:SSP 匯出加 OSCAL 格式

除了 docx / pdf / odt 三種可讀格式,匯出也要提供 OSCAL 結構化格式(JSON / XML / YAML)。這部分技術上:

  • jedi-oscal 既有 yaml mapper(infra/mapper/ssp/ssp_yaml_mapper.py),可作為 base
  • 系統目前沒看到 SSP 對外的 OSCAL export endpoint(只有 OSCAL import),所以本期屬於新增功能
  • JSON / XML / YAML 三種是 OSCAL 標準格式,互轉成本低,做一個其他兩個幾乎免費

補充 2:Excel 匯入樣板的設計規範

樣板必須:

  1. 分 sheet 做不同事情 — 每個資料領域一個 sheet(metadata / parties-organizations / parties-persons / devices / information-systems / leveraged-services / controls / AOs / reference-documents),不擠在同一個 sheet
  2. 欄位顏色提示 — 必填欄位用底色標示(沿用既有 template 黃底慣例),選填用無底色或淺色
  3. 系統有的資料 → Excel 下拉選單 — 對 Excel data validation 規格做下拉選項,使用者選的時候有 dropdown,例如:
    • system_owner → 下拉選 tenant 內既有 user(顯示 nickname)
    • org_unit → 下拉選既有組織單位
    • device → 下拉選既有 public.devices
    • information_system → 下拉選既有 compliance.information_systems
    • impl_status / sensitivity_level / deployment_model 等 enum → 下拉選 enum 值
  4. 原本系統表單就是下拉的,Excel 也要下拉 — 對齊 UI 表單行為,避免使用者用 Excel 填了系統不接受的字串

💡 設計考量:Excel 下拉選單在資料量多時會卡(如 user 上千人),需要評估是用「name list 直接列舉」還是「named range + 工作表隱藏」處理。實作階段再決定。


2. 用語對齊

術語 Tenant 層實體 OSCAL Mirror 表 OSCAL 規格對應
合規資源庫 module_frame system_security_plans system-security-plan
基本資料 module_frame.metadata + 引用的 information_systems system_security_plans_system_characteristics system-characteristics
單位 org_units oscal_parties (type=organization)【既有,不動】 metadata.parties
參與人員 users oscal_parties (type=person)【既有,不動】 metadata.parties
設備(資產) public.devices system_security_plan_system_implementations (implementation_type=inventory-item)【既有,擴充】 system-implementation.inventory-items
系統(資訊系統) compliance.information_systems system_security_plan_system_implementations (implementation_type=component / subsystem)【既有,擴充】 system-implementation.components
Leveraged Services (無 tenant 層表,純文字) system_security_plan_system_implementations (implementation_type=leveraged-authorization)【既有,擴充】 system-implementation.leveraged-authorizations
控制項現況說明 module_frame_control_default.implementation_statement system_security_plan_control_implementations control-implementation.implemented-requirements
AO 現況說明 module_frame_control_objective_default.statement ssp_control_implementation_objectives implemented-requirements.statements
參考程序書 module_frame_reference_document + mapping ssp_reference_documents + ssp_reference_document_mappings【既有】 back-matter.resources + links

架構決策(v4 校正)擴充既有 system_security_plan_system_implementations,不新建三張表。既有表已是「OSCAL system-implementation 多型鏡像」的設計用意,implementation_type 已用於區分 system / subsystem / service / component / hardware / software(用 enum SystemImplementationType),且 140 筆 hardware 資料 + jedi-oscal 完整 stack 已在運作。擴充比新建更務實。

2.1 既有表現況盤點

Schema(既有):

欄位 型別 用途
id integer PK 主鍵
uid uuid UNIQUE OSCAL UUID(已 uuid4 default)
system_security_plan_id integer NOT NULL FK 只服 SSP,CASCADE FK
name varchar(255) NOT NULL 名稱
description text 說明
implementation_type varchar(50) NOT NULL system / subsystem / service / component / hardware / software(既有 enum)
responsible_party varchar(100) 負責角色或單位(純字串,沒鉤 oscal_parties.uid)
created_at / updated_at / created_user / updated_user 完整稽核欄位

程式碼 stack(既有,jedi-oscal):

  • ORM:jedi_oscal/infra/model/ssp/ssp_system_implementation.py
  • Entity / Query Entity:jedi_oscal/domain/entity/ssp/
  • Repository interface + impl:jedi_oscal/domain/repository/ssp/system_implementation_repo.py + jedi_oscal/infra/repository/ssp/
  • Mapper:jedi_oscal/infra/mapper/ssp/system_implementation_mapper.py
  • DTO:jedi_oscal/app/dto/ssp/ssp_system_implementation_dto.py
  • Enum:jedi_oscal/common/enum/code_enum.py 內的 SystemImplementationType
  • YAML mapper:jedi_oscal/infra/mapper/ssp/ssp_yaml_mapper.py(OSCAL 序列化已部分接通)

Caller(主專案):

  • app/associations/service/project_device_mapping_service.py(專案 device mapping)
  • app/oscal/service/ssp_versioning_service.py(SSP 版本服務)

資料量:140 筆 hardware(= 已用作 devices 的 OSCAL 鏡像)。

2.2 擴充內容(A0 主體工作)

欄位擴充(ADD COLUMN)

新增欄位 型別 用途 nullable
scope_type varchar(20) 'ssp''module_frame' — 標示這筆隸屬哪邊 NOT NULL(既有 140 筆 migration 設 'ssp')
scope_id integer 對應 scope_type 指向的 id(soft FK,無 DB FK constraint) NOT NULL
device_id integer soft FK → public.devices.id;鉤稽既有 device 時填 nullable
information_system_id integer soft FK → compliance.information_systems.id;鉤稽既有 system 時填 nullable
title varchar(255) OSCAL component.title(OSCAL 規格的人類可讀標題;與 name 區分) nullable
purpose text OSCAL component.purpose(用途說明) nullable
status varchar(50) OSCAL component.status(under-development / operational / disposition / other) nullable
party_uuid varchar(36) OSCAL leveraged-authorization.party-uuid(授權方);對齊既有 oscal_responsible_parties.party_uuid 型別 nullable
date_authorized date OSCAL leveraged-authorization.date-authorized nullable

既有欄位調整

欄位 變更 理由
system_security_plan_id NOT NULL → nullable;CASCADE FK 保留 scope_type='module_frame' 時不指向 SSP,必須 nullable
responsible_party 維持,不動 既有資料用,標 deprecated(後續優化由 oscal_responsible_parties 取代)

enum 擴充(v4 校正:只加 1 個值)

SystemImplementationType (jedi-oscal common/enum/code_enum.py) 只加一個新值

  • LEVERAGED_AUTHORIZATION = "leveraged-authorization"(OSCAL leveraged services 用)

既有 enum 值的延用

既有 enum 值 新功能用途
hardware devices 的鏡像(沿用既有,跟 project_device_mapping_service 一致;不另外造 inventory-item 重複概念)
component information_systems 的鏡像(沿用既有;可選用 system / subsystem 對應 OSCAL system-implementation.this-system / subsystem
software / service / system / subsystem 維持不動

為什麼不加 inventory-item

OSCAL 字面術語上 hardware 是 component.type 子分類,inventory-item 才是「具體 deployed asset」。但既有 code 已用 hardware 涵蓋同一概念、140 筆都是這樣,加 inventory-item 會讓兩個 enum 值意義重疊(dev 心智負擔 + caller 寫入分流)。OSCAL 匯出時若需要 inventory-item 結構,由 mapper 層把 hardware 翻譯成 OSCAL inventory-item JSON 即可,不必動 DB。

既有 140 筆 hardware 資料

  • 不轉換 implementation_type(維持 hardware
  • 只 migration 補 scope_type='ssp' + scope_id=system_security_plan_id(讓既有資料能被新 scope query 撈到)

Index 補充

新增 index 用途
ix_ssp_sys_impl_scope (scope_type, scope_id) 依 scope 查詢
ix_ssp_sys_impl_device_id 依 device 反查
ix_ssp_sys_impl_info_system_id 依 information_system 反查

2.3 「不做」清單(v4 校正)

不做的事 理由
新建 oscal_inventory_items 既有表已有多型 implementation_type,加 column 即可
新建 oscal_components 同上
新建 oscal_leveraged_authorizations 同上
廢棄既有 system_security_plan_system_implementations 既有表正在用,廢棄成本遠高於擴充
Migration 搬資料到新表 不新建表,沒地方搬

2.4 表名語意爭議

問題:表名是 system_security_plan_system_implementations(含 system_security_plan 前綴),但新增 scope_type='module_frame' 後也會裝 module_frame 資料,名稱語意稍偏。

處理方向(A0 brainstorm 待決):

  • 方案 1:表 rename 為 oscal_system_implementations(更通用),既有 ORM / repo 同步改名
  • 方案 2:保留表名,加 docstring + table COMMENT 解釋
  • 方案 3:保留表名,建 view oscal.system_implementations 對齊新名稱供新功能讀

此項列入剩餘 brainstorm 題目。


3. 新需求拆解(依資料領域)

下面是「Excel 匯入」要新增的範圍,依資料領域逐項展開:

3.1 基本資料(Metadata)

內容(依 docx parser v2 已建立的欄位推估):

  • 系統名稱、簡稱、版本
  • 系統概述、邊界、敏感度分類(FIPS 199)
  • 授權邊界(Authorization Boundary)
  • 網路架構、資料流概述

匯入挑戰

  • 純文字長段落,Excel 用一個 cell 還是分多個欄位?建議分多欄但長文字 cell 不限制長度。
  • 部分欄位是 enum(如 FIPS 199 機敏等級),匯入時要 validate。

3.2 設備 / 單位 / 參與人員 / 系統 — 要鉤稽

這四類有共同特性:Excel 內填的是「字串名稱」,匯入時要對到系統內既有的實體

鉤稽的兩種狀況

狀況 系統行為
Excel 填的名稱完全相符系統內既有實體 自動鉤上(跟 docx parser 的 party email-match / org-unit name-match 一致)
找不到完全相符 需要進入「預覽 / 編輯」介面,由 user 手動 (a) 從下拉選現有的 (b) 新建一筆 (c) 暫時當純文字保留

各領域細節

領域 Tenant 層比對對象 建議比對 key OSCAL Mirror 寫入目標 鉤不到時
單位 org_units organization name 完全相符 oscal_parties (type=organization) 標 unmatched → user 可選現有 / 預覽頁新建 / 純文字 OSCAL 紀錄(party_uuid 有,soft FK null)
參與人員 users email 完全相符(同 tenant) oscal_parties (type=person) 同上
設備 public.devices name 或 ip 完全相符 system_security_plan_system_implementations (implementation_type='inventory-item')【既有表擴充】 同上:(a) 鉤已有 device (b) 預覽頁新建到 public.devices (c) 純文字 OSCAL 紀錄(device_id null)
資訊系統 compliance.information_systems name 或 abbreviation 完全相符 system_security_plan_system_implementations (implementation_type='component')【既有表擴充】 同上:(a) 鉤已有 (b) 預覽頁新建 (c) 純文字 OSCAL 紀錄
Leveraged Services (無 tenant 層表) service name + authorizing party system_security_plan_system_implementations (implementation_type='leveraged-authorization')【既有表擴充】 直接建一筆,authorizing party 可選既有 oscal_parties 或同步新建

寫入路徑(confirm 階段 BE 行為):

            user 在預覽頁 confirm
                    │
                    ▼
       ┌────────────────────────┐
       │  鉤稽結果分流           │
       └────────────────────────┘
          │           │            │
   matched      inline 新建    純文字保留
          │           │            │
          ▼           ▼            ▼
   只寫鏡像表   先寫 tenant   只寫鏡像表
  (含 soft FK)  層表 → 再寫   (soft FK
                鏡像表        = null)

註:「鏡像表」= system_security_plan_system_implementations,依 implementation_type 區分 inventory-item / component / leveraged-authorization。

Q3 已 resolved:docx parser 本期不擴充到 devices / information_systems,列入「最後統整優化清單」 — 等 Phase 2 完工後再一起處理 docx parser 對齊。同樣的 OSCAL mirror 表新建後,docx parser 之後要對齊寫入這幾張表。

Q8 已 resolved:鉤不到時除了「選現有 / 純文字保留」,也支援直接在預覽頁面新建 — 例如 user 在預覽頁看到 unmatched device,可直接 inline 輸入 ip/os 等欄位,confirm 時先寫 public.devices 再寫 oscal_inventory_items(soft FK 串起來)。

3.3 控制項 / AO 現況說明

已有功能,但要對齊 docx 匯入體驗:

  • 既有 Excel 匯入是「同樣 module_frame、同樣 control_id」做精確 join 然後寫入;
  • 草稿希望改成「用編號或名稱模糊比對」的方式,並讓 user 在預覽介面檢查匹配結果。

意涵:這代表新 Excel 不再綁定某個 module_frame,使用者可以拿任意 Excel(甚至從別的 framework 來的)匯進來,由系統幫忙比對。這跟既有「先匯出某 module_frame 的樣板 → 填 → 匯回同一個」的 round-trip 模式有差異,要釐清是否兩種模式並存。

3.4 程序書(Reference Documents)

草稿沒明說,但既有 Excel template 有 參考程序書 欄位,docx parser v2 也有 SSP document pool 模式。新版要:

  • 程序書名稱填在 control / AO 列上;
  • 匯入時把程序書建到 pool(如果不存在),並建 control/AO ↔︎ document 的 mapping;
  • 同 docx 模式做 name-match 鉤稽。

4. Excel 匯入體驗 — 對齊 docx parser v2

草稿明確說「匯入模式可以參考 docx 匯入模式」。把 docx 匯入流程(v2 已上線)抓出來,對應到 Excel:

階段 docx 流程(既有) Excel 流程(本期目標)
1. 選 parser 從 framework 選 docx parser 從 framework 選 Excel parser(或統一同一個入口)
2. 上傳檔案 上傳 docx 上傳 xlsx
3. BE 解析 解析回傳 parse_uid + parsed_result(JSONB,7 天 TTL) 同 docx 模式
4. 預覽 iframe PDF + 右側 Section 編輯 panel 左右比對(左:Excel 原貌或欄位對照、右:解析後可編輯 Section)
5. 鉤稽 parties / org-unit / leveraged auto-match + 標出未匹配 同 docx 模式 + 涵蓋設備 / 系統 / 控制項 / AO
6. user 編輯 localStorage 暫存 + BE TTL 同 docx 模式
7. 確認 POST confirm → 寫入 module_frame 同 docx 模式
8. 重新上傳 棄置 parse_uid,從頭來 同 docx 模式

4.1 左右比對的可行性

Q6 已 resolved:本期不做左右比對。Excel 不像 docx 容易渲染成 PDF,純單欄式預覽 + 編輯介面即可(方案 C)。

4.2 Excel 樣板結構(依 §1.5 補充 2)

按資料領域分多 sheet,欄位顏色 + 下拉選單規格:

Sheet 內容 必填欄位(黃底) 下拉選單欄位
00_說明 樣板版本、framework、填寫指引、必填顏色圖例
01_基本資料 系統 metadata(name / abbreviation / desc / sensitivity / boundary / objectives / deployment) name / sensitivity / objectives sensitivity (enum) / objectives (enum) / deployment_model (enum) / system_owner (既有 user list) / org_unit (既有 list)
02_單位 parties type=organization name parent_org (既有 org list, optional)
03_參與人員 parties type=person + 鉤稽 user email / name role / org_unit (既有 list)
04_設備 devices(鉤稽 public.devices name / ip os (建議候選 list) / device_type (建議候選 list) / status (enum)
05_資訊系統 information_systems(鉤稽 compliance.information_systems name sensitivity / objectives / deployment_model / system_owner
06_外部利用服務 leveraged authorizations service_name / provider
07_控制項與AO 控制項實作 + AO 現況(保留既有 module_frame_import_template.xlsx 的結構 + 擴充) statement_id / control_id impl_status (enum)
08_程序書 reference document pool doc_name / doc_no doc_type (enum, 若有)

💡 已有資料下拉如果量大(如 user 上千人),實作階段用「named range + 隱藏 lookup sheet」處理。


5. SSP 文件匯出

5.1 範圍(含 OSCAL 結構化格式)

Q5 已 resolved「合規資源庫」與「專案 SSP 版本」兩邊都要提供匯出

匯出來源 × 匯出格式組合矩陣:

來源 \ 格式 docx pdf odt OSCAL JSON OSCAL XML OSCAL YAML
合規資源庫(module_frame)
專案 SSP 版本(project + ssp_version)

兩個來源的差異:合規資源庫匯出的是「範本層」資料(顧問建好的 default);專案 SSP 版本匯出的是「實際填寫的現況」(含每個 AP round 的差異)。

5.2 多格式支援的真實成本

Q4 已 resolved:odt 本期要做

格式 實作成本 技術做法
docx python-docx 手寫,跟既有 system-design DOCX 規範一致(封面 / 版本紀錄 / 目錄 / Graphviz 圖)
pdf docx 完成後用既有 /upload-file/<uid>/preview-as-pdf endpoint 或 LibreOffice headless convert
odt 用 LibreOffice headless --convert-to odt 從 docx 轉,或用 odfpy 直接產(評估後再定)
OSCAL JSON jedi-oscal 已有 yaml mapper(ssp_yaml_mapper.py)作 base,serialize 改 JSON
OSCAL XML 同 JSON,OSCAL 標準 XML schema 已定
OSCAL YAML jedi-oscal 既有 yaml mapper 已可用

5.3 範本(Template)

Q10 已 resolved先用 CMMC 通用樣板,後續如果有法規資料不同的需求再抽象化。

  • ASIA-CMMC-SSP-DRAFT-with-user-info-202604.docx 拆出章節結構、版面樣式、placeholder
  • 含封面頁、版本更新紀錄表、Word 自動目錄(依 CLAUDE.md DOCX 規範)
  • 章節結構與 OSCAL system-security-plan 對應,方便未來轉 OSCAL JSON / XML / YAML

5.4 匯出資料 API vs UI

  • API
    • 合規資源庫:POST /module-frame/<uid>/export?format=docx|pdf|odt|json|xml|yaml
    • 專案 SSP:POST /projects/<project_id>/ssp/<version_id>/export?format=...
  • UI
    • 合規資源庫頁面加「匯出 SSP」按鈕 + 格式選擇 dropdown
    • 專案規劃頁面同模式加按鈕

6. 我建議的階段切分(重新規劃)

草稿說「不要全照我的切,要的話再分更細」。下面是我的版本,跟草稿的差異會標出。

6.1 切分原則

  1. 可獨立 ship:每階段完成後系統都還能正常用,不依賴後續階段
  2. 可平行:匯入 / 匯出 兩條主線可平行進行(不同人 / 不同 session)
  3. 小批次驗收:每階段 1~2 週可完成,避免長尾
  4. 基礎先行:共用的 parser 架構 / 鉤稽框架先做

6.2 階段規劃

Phase A0:基礎設施 — 擴充既有 system_security_plan_system_implementations 表(前置必做 ✅ shipped (BE c4804d7 + jedi-oscal afe7035→dbb3d7c, 2026-05-18))

Phase 主題 範圍 依賴
A0 既有表 schema 擴充 + ORM / Entity / Repository / Mapper 同步擴充 在既有 system_security_plan_system_implementations 上加 scope_type / scope_id / device_id / information_system_id / title / purpose / status / party_uuid / date_authorized 欄位;既有 system_security_plan_id 改 nullable;enum 擴充 inventory-item / leveraged-authorization;jedi-oscal 全 stack 同步擴充

A0 包含項目

  • SQL migration(ALTER TABLE 加 9 個 column + 改 system_security_plan_id nullable + 加 3 個 index)
  • 既有 140 筆 hardware 資料 migration(只補 scope_type='ssp' + scope_id=system_security_plan_id;不轉 implementation_type,維持 hardware
  • jedi-oscal 套件擴充(dev 期走 poetry path dependency,不立即發版):
    • ORM model:ssp_system_implementation.py
    • Entity / Query Entity:jedi_oscal/domain/entity/ssp/
    • Repository interface + impl
    • Mapper:system_implementation_mapper.py + ssp_yaml_mapper.py(OSCAL 序列化)
    • DTO:ssp_system_implementation_dto.py
    • Enum:SystemImplementationType 加新值
  • 既有 caller 驗證:project_device_mapping_service + ssp_versioning_service 確保不破壞
  • 補單元測試(新欄位 CRUD + scope 篩選 + soft FK 整合)

A0 是 Track A 與 Track B OSCAL 線(B5)共同前置 — 任何 Excel 匯入 / OSCAL 匯出邏輯都要等這層基礎建好才能接。

Track A:Excel 匯入(5 階段)

Phase 主題 範圍 依賴
A1 Excel 樣板設計 + 匯出下載 設計 multi-sheet xlsx(§4.2 9 個 sheet),含必填欄位顏色標示、enum 與既有資料下拉選單;提供「下載空白樣板」+「從現有 module_frame 下載已填樣板」兩種模式 A0(樣板下拉要選 OSCAL mirror 既有資料)
A2 Excel Parser + BE 解析 API 寫 ExcelParser(對應 docx 的 DocxParser),輸出 ParsedResult JSONB;提供 upload + parse endpoint,回傳 parse_uid(沿用 docx parser 的 7 天 TTL 機制) A1
A3 鉤稽邏輯 — parties / org-units(抽共用層) 把 docx parser 既有的 party / org-unit match 邏輯抽出共用 service,Excel / docx 兩條路徑都用同一份 matcher;寫入路徑寫到 oscal_parties A2
A4 鉤稽邏輯 — devices / information_systems / leveraged + 控制項/AO 模糊比對 新增 devices / information_systems / leveraged / control / AO 的 match 邏輯;寫入路徑寫到 A0 建好的三張 OSCAL mirror 表 A0, A3
A5 預覽 UI + Confirm 寫入(含 inline 新建) 前端單欄預覽 + 編輯介面、localStorage 暫存、unmatched 項目支援「選現有 / 純文字 OSCAL 紀錄 / inline 新建 tenant 資料」三種處理;confirm 時依路徑寫入 module_frame + OSCAL mirror 表 A2~A4

跟草稿的差異:草稿把「Excel 匯入功能」當一個階段,我拆成 4 階段(A2~A5)+ A0 基礎建設,因為鉤稽邏輯是高風險區域、需要分批驗證;A3 把 docx 既有 matcher 抽出共用,避免兩套 parser 行為不一致。

Track B:SSP 匯出(6 階段,新增 OSCAL 線)

Phase 主題 範圍 依賴
B1 Docx 樣板拆解 + python-docx generator 骨架 ASIA-CMMC-SSP-DRAFT-with-user-info-202604.docx 拆出章節結構,建立 generator 骨架(章節 helper、樣式、封面、版本紀錄表、目錄)
B2 內容組裝服務 — 兩種來源 → 共用 SSP data model App service 把 module_frame 專案 SSP 版本資料組成 generator 用的 SSP data model(metadata / parties / inventory_items / components / leveraged / controls / AOs / references),共用同一個 generator A0, B1
B3 Docx Export API + 下載 POST /module-frame/<uid>/export?format=docxPOST /projects/<pid>/ssp/<ver>/export?format=docx 兩支 endpoint;回傳 docx file stream B2
B4 PDF + ODT 補上 docx 完成後接 LibreOffice headless convert(或 odfpy)補 pdf / odt 兩種格式,同一個 export endpoint 用 format 參數切換 B3
B5 OSCAL 結構化匯出(JSON / XML / YAML) 基於 jedi-oscal 既有 yaml mapper 擴充,序列化 OSCAL mirror 表(含 A0 三張新表)→ JSON / XML / YAML;同一個 export endpoint format=json|xml|yaml A0, B2(與 B3/B4 平行可進行)
B6 前端 UI + 格式選擇 合規資源庫頁 + 專案規劃頁加「匯出 SSP」按鈕 + 格式下拉(docx / pdf / odt / oscal-json / oscal-xml / oscal-yaml) B3, B4, B5

跟草稿的差異:草稿是 3 階段(樣板 / API / UI),我拆成 6 階段:

  1. 樣板拆成 B1(generator 骨架)+ B2(data model 組裝),技術重點不同
  2. 多了 B5 OSCAL 結構化匯出線(raymond 第一輪回覆補充)
  3. ODT 不能等 docx 順手就拿到,獨立做 B4
  4. UI 集中在最後 B6(含格式 dropdown)

6.3 階段相依關係

              ┌── A1 ── A2 ── A3 ── A4 ── A5  (Excel 匯入完成)
              │
A0 ───────────┤
(OSCAL mirror │
 表基礎)      │
              │   B1 ── B2 ──┬── B3 ── B4 ──┐
              └──────────────┤              ├── B6 (SSP 匯出完成)
                             └── B5 ────────┘

關鍵 dependency

  • A0 是 Track A 與 Track B(B2 起算)共同前置 — 一定要先做
  • A0 完成後,A1 / B1 可平行起手
  • A 跟 B 主線可平行;B 內部 B3 / B4 / B5 可平行(都依賴 B2 data model)

6.4 各階段的「最小可驗收」

  • A0 ship:既有表擴充 migration 跑通、jedi-oscal 擴充欄位 ORM + repository CRUD 測試通過、既有 caller (project_device_mapping_service + ssp_versioning_service) regression 測試通過、140 筆既有資料 scope_type='ssp' migration 完成
  • A1 ship:可下載空白樣板 + 已填樣板(兩個檔案,含必填顏色 + 下拉選單)
  • A2 ship:API 可解析 Excel 回傳 JSONB,postman 可測
  • A3 ship:解析結果含 matched / unmatched parties / org-units 標記,docx 路徑同時切換到共用 matcher 行為不變
  • A4 ship:解析結果擴充含 devices / information_systems / leveraged / controls / AOs match 標記,confirm 寫入 OSCAL mirror 表
  • A5 ship:完整 UI flow,含 inline 新建 device / information_system / party 能力(同步寫 tenant 表 + OSCAL mirror 表)
  • B1 ship:可產出空殼 docx(封面 / 目錄 / 章節骨架,無實際資料)
  • B2 ship:可從 module_frame 專案 SSP 版本兩種來源產出含實際資料的 docx
  • B3 ship:兩支 export endpoint 上線(docx)
  • B4 ship:pdf + odt 兩格式接上
  • B5 ship:OSCAL JSON / XML / YAML 三格式接上(讀 A0 三張新表序列化)
  • B6 ship:UI 按鈕 + 格式下拉,6 種格式都可下載

7. 待釐清項目決策結果(Q1~Q11 已全數 resolved,2026-05-18)

7.1 範圍類

# 問題 決策
Q1 「設備」對應 OSCAL 哪一項? public.devices(jedi-device 套件)→ OSCAL inventory-items(資產概念),匯入時與此表鉤稽
Q2 「系統」對應實體? compliance.information_systems(既有資訊系統表),匯入時與此表鉤稽
Q3 docx parser 是否同步擴充 devices / information_systems? 本期不擴充,列入「最後統整優化清單」,Phase 2 完工後再處理
Q4 odt 格式本期是否要做? 要做 — docx / pdf / odt 三種可讀格式 + OSCAL JSON / XML / YAML 三種結構化格式
Q5 SSP 匯出來源? 「合規資源庫」與「專案 SSP 版本」兩邊都要 — 矩陣詳見 §5.1

7.2 體驗類

# 問題 決策
Q6 Excel 預覽是否左右比對? 不做左右比對 — 單欄式預覽 + 編輯介面即可
Q7 Excel 匯入流程? 對齊 docx parser — create 模式(新建 MF)+ update 模式(補資料到既有 MF)雙模式,編輯 / TTL / 確認流程一致
Q8 控制項 / AO 等 unmatched 行為? 對齊 docx + 加 inline 新建 — 標 unmatched 後 user 可選 (a) 選現有 (b) 純文字保留 (c) 預覽頁面直接 inline 輸入新建 三種

7.3 範本類

# 問題 決策
Q9 Excel 樣板要 framework 一份還是通用? 通用結構 — 一份 multi-sheet 樣板,控制項 sheet 動態依據 module_frame 的 framework 預填
Q10 SSP 匯出 docx 樣板? 通用,先用 CMMC 當樣板 — 後續若法規資料差異大再抽象化
Q11 既有 Excel 匯入(只匯現況)是否保留? 保留,移到批次維護「現況說明」功能下;新版定位是「匯入完整資料」,跟舊版定位不同

7.4 衍生新議題(v2+v3+v4 補充)

# 議題 處理方向
N1 OSCAL JSON / XML / YAML 序列化的完整度 jedi-oscal 既有 yaml mapper 是否覆蓋 SSP 全部欄位?實作前要先盤點缺哪些 mapper
N2 Excel 下拉選單在資料量大時的效能 named range + 隱藏 lookup sheet 處理;上千筆以下可直接列舉
N3 inline 新建 device / information_system 的權限檢查 需確認匯入者是否有建立這些實體的權限(manager / auditor 角色檢查)
N4 專案 SSP 版本匯出時,要不要跨多 AP round 合併 預設匯出當前最新版本;若要跨 round 比較,列為 follow-up
N5 既有表擴充欄位細節(v4 校正) 9 個新欄位的 nullable / index / OSCAL 屬性對應 — 進 SDD 階段定(部分已在 §2.2 草擬)
N6 既有通用表後續 v4 已 obsolete:v3 主張廢棄既有表是誤判,v4 改成擴充既有表
N7 A0 在 OSCAL 寫入 race(v3) confirm 時:先寫 tenant 表(device)→ 寫鏡像表(含 soft FK)— 要在同一個 @transaction scope 內,避免半寫狀態
N8 既有 140 筆 hardware 資料 migration 策略 已 resolved:只補 scope_type='ssp' + scope_id,不轉 implementation_type;沿用 hardware 不引入 inventory-item 重複概念
N9 表名語意爭議(v4) 表名 system_security_plan_system_implementations 含 ssp 前綴但要服 module_frame — rename / 不動 / view alias 三方案 brainstorm 待決
N10 既有 responsible_party 欄位後續(v4) 既有純字串欄位有資料、不鉤 oscal_parties.uid;新功能改用 oscal_responsible_parties(polymorphic);既有 column 暫保留標 deprecated

8. 風險評估

風險 影響 緩解
鉤稽邏輯複雜度高(5 種實體、多 key match + 寫入兩層 tenant + OSCAL mirror) 開發時間翻倍、UX 設計痛苦 先把 docx parser 既有 party / org-unit match 抽成共用服務(A3),新領域複用;A0 把 mirror 表基礎打穩再做寫入
A0 既有表擴充欄位定錯(v4 校正) 後續 A4 / A5 / B5 全部要回改 A0 SDD 階段先把 OSCAL 規格欄位列清楚再下手;既有 jedi-oscal stack 都要同步擴充
A0 破壞既有 caller(v4 新增) project_device_mapping_service / ssp_versioning_service regression A0 完成後跑既有 caller 的 integration 測試;ALTER TABLE 用 ADD COLUMN 不改既有欄位語意;nullable 化既有 system_security_plan_id 要驗證所有 caller 都接受 null
140 筆既有資料 migration 出錯(v4 新增) 既有 hardware 紀錄遺失或錯標 Migration 加 transaction + 先 SELECT count 對帳;migration 完成後 SELECT COUNT(*) WHERE scope_type='ssp' 驗證仍 140 筆
Excel 結構變動成本高(樣板改一次,parser + UI 都要動) 後續維護負擔 A1 樣板定版前先跟使用者(顧問)確認 sheet 結構,避免反覆改
docx 樣板渲染品質(中英文混排、表格樣式) 客戶交付品質直接影響業務 B1 階段先做 PoC,跟既有 system-design DOCX 模式對齊
docx parser 與 Excel parser 雙系統不一致(同樣資料兩種匯入路徑可能行為不同) 維運痛苦、bug 散落 鉤稽 / 寫入邏輯抽 common 層,parser 只負責格式解析;A3 抽 matcher 共用
OSCAL UUID 引用一致性(v3 新增) implemented-requirements 引用 inventory-item UUID 對不上 既有表 uid 已有 unique constraint;寫入時用 transaction scope 確保鏡像 UUID 與 control_impl 引用同步
既有 Excel 匯入(舊版)使用者習慣 切換成本 A 系列完成前舊版繼續可用,A5 上線時提供 migration 提示
舊 system_implementations 通用表與新 mirror 表雙軌期 v4 已 obsolete — 不建新表,沒雙軌問題

9. 不在本期範圍(明確排除,避免 scope creep)

  • ❌ docx parser 擴充到 devices / information_systems(Q3 決議 → 列入「最後統整優化清單」,Phase 2 完工後處理)
  • ❌ Excel / docx 雙向同步(雙向同步是另一個議題)
  • ❌ 跨 module_frame 的 bulk import / export(一次只處理一個 MF)
  • ❌ 既有舊版 Excel 匯入功能的下線(Q11 決議:保留並移到批次維護「現況說明」下)
  • ❌ 跨 AP round 合併匯出(N4:預設只匯當前最新版本,跨 round 比較列 follow-up)

9.1「最後統整優化清單」(Phase 2 完工後處理)

項目 來源
docx parser 擴充到 devices 鉤稽(寫入鏡像表 implementation_type='hardware') Q3
docx parser 擴充到 information_systems 鉤稽(寫入鏡像表 implementation_type='component') Q3
Excel / docx parser 共用 matcher 反向同步(如果 A3 抽得不夠乾淨) A3 衍生
跨 AP round 的 SSP 匯出差異比對 N4
Framework-specific docx 樣板抽象化(如果出現 ISO 27001 / NIST 800-53 客戶) Q10
既有 responsible_party (varchar) 欄位資料遷移到 oscal_responsible_parties N10

10. 下一步

raymond 確認這份理解版本後,按 docs/claude/feature-development-workflow.md 進入:

  1. Phase 1 — Brainstorm:針對 Q1~Q11 待釐清項目逐一收斂
  2. Phase 2 — 歸檔到 features/:把這份搬到 docs/features/FR-011.2-2605-ssp-import-export-phase2/raw-requirement.md
  3. Phase 3 — design.md:依切分後的 Track A / B 分別寫 SDD(或合一份大的)
  4. Phase 4 — implementation-plan.md + test-plan.md:交給 feature-test-planner agent
  5. Phase 5 — 實作:依階段 ship

附錄:與既有 feature 的關聯

既有 feature 路徑 關聯
SSP Doc Parser v2 docs/features/FR-022-2604-ssp-doc-parser/ 鉤稽邏輯、UI flow、parse_job model 全部可複用
SSP Update Diff docs/features/FR-025-2605-ssp-update-diff/ 匯入後若要 diff 與 module_frame 既有資料差異,可對齊 update diff 的 side-by-side UI
Module Frame Template Defaults docs/features/FR-018-2604-module-frame-template-defaults/ 控制項 / AO defaults 的寫入 model 已存在,匯入直接寫這層
SSP Document Pool docs/features/FR-010-2603-ssp-document-pool/ 參考程序書 pool + mapping 機制已存在,Excel 匯入要對齊
Compliance Framework PDF Import v2 docs/features/FR-024-2605-compliance-framework-pdf-import-v2/ 框架匯入跟 SSP 匯入是不同層次(前者建框架 / 後者填內容),但 UI 模式可參考