FR-139 · 設計定案 · 2026-10-14

顧問在資源庫訪談、存版、送審,專案只看不改

缺失與修改建議欄、建議附件、訪談表累積匯入、資源庫版本、資源庫與專案一對一、送審鎖版

顧問在合規資源庫把客戶的訪談結果寫完整——實施狀態、現況、備註、缺失、缺失修改建議,需要時在建議下面附一份可直接給客戶用的範本(建議附件)。訪談表可以反覆匯入、一次一次累積;每整理一輪就存一版,可看舊版、可比對、可整份還原。啟動專案時專案直接看資源庫那一份 SSP,規劃頁除任務設定外唯讀;顧問按「送審」那一刻存一版並凍結給稽核輪,之後資源庫就不能改,只有輪次在「規劃中」才可編輯。本文件寫定案規則、為什麼這樣定、踩到會怎樣。

D1~D21 全部定案(2026-10-14) 三個子需求、十一張卡,待開卡 動一支套件 jedi-oscal-v2(props 逐鍵合併) 陷阱:範本 SSP 同時是專案 SSP,守門要兩類入口一起改 上版前查 STG/POC 有無一資源庫多專案

狀態:設計定案(2026-10-14),待開卡|討論稿:discussion.md|雛形:prototype/index.html(四頁:控制項填寫、版本歷史、版本比對、專案規劃頁唯讀)

雛形是假資料畫面,欄位與選項以本文件為準(實施狀態選項以 §6.6 的六值為準)。檔案路徑與行號以 2026-10-14 為準,查不到時以函式名重新定位。路徑慣例:BE 路徑相對 compliance-manager-be/;pkg/ 代表 ~/Projects/Jedicogy/module/jedi-python-package/;FE 路徑相對 compliance-manager-fe/。

名詞:資源庫=合規資源庫(compliance.module_frames);範本 SSP=資源庫底下那份 SSP(module_frames.template_ssp_id),也就是工作副本;AO=評估目標(assessment objective),控制項底下的檢查項目;IR=控制項實施紀錄(oscal.ssp_implemented_requirements);props=OSCAL 物件上的「名稱+值」擴充屬性陣列;新模式專案=living_ssp_id 等於某資源庫 template_ssp_id 的專案;舊模式專案=啟動時複製了一份 SSP 的既有專案。

§1

變更紀錄

日期 變更 對應
2026-10-14 v1:D1~D21 設計定案;資料模型、版本操作、權限分流、匯入兩路徑、畫面甲案;三個子需求十一張卡拆分與端到端驗收 —
2026-10-18 D19 改判:資源庫只在綁定專案最新一輪 planning 時可改,送審後到結案(含改善中、已結案)一律鎖 CM-2888
2026-10-14 開卡前補定七條:資源庫終身只綁一個專案(不分進行中/結案/封存);匯入前自動存備份版、匯入後不另存;鎖寫區間含 pending_reverify、remediation 與 closed 解鎖;版本不提供刪除;看版本用 oscal.resource-library.read;實施狀態 system_menus seed 併入卡 1;雛形兩處與決策不符不修、以本文件為準 母卡 CM-2745、子需求 CM-2746~2748、子任務 CM-2749~2759(T-1~T-10、T-2b;守門分流從卡 1 併入 T-9)

§2

需求背景與端到端流程

合規資源庫是顧問替客戶導入法規框架的第一個入口。顧問到客戶現場訪談,手上拿的訪談表就是系統可下載的「現況資料 Excel」;回來把訪談表匯入,同一份表隨訪談次數反覆匯入。之後逐條整理控制項與 AO 的實施狀態、現況說明、備註。

整理到「部分實作」這類條目,顧問要寫出缺了什麼與怎麼補,手上若有可直接給客戶用的範本就附上——這一步就是正式稽核前的事前稽核。以 CRA 的漏洞通報條為例:

欄位 顧問寫的內容
實施狀態 部分實作
現況說明 只有提供 E-Mail 收信接收通報
備註 連 email 都未開通
缺失 無通報平台、也沒有公告、也沒有通報手冊
缺失修改建議 提供通報平台網址、官網公告通報方式、提供手冊下載
建議附件 通報流程手冊範本.pdf(說明:照這份補上收件、分級、修補、回覆四段)

缺失若沒有自己的欄位,就只能塞進現況說明:一個欄位同時講「現在是什麼」和「少了什麼」,產缺失報告得人工再拆一次(FR-138 自家 CRA 自評就是這樣)。同一份訪談表重新匯入,還可能把上次填好的欄位清掉(§6.5)。

流程由顧問主導:

  1. 顧問在資源庫訪談、匯入、整理,完成客戶的 SSP。
  2. 啟動專案。專案直接看資源庫那份 SSP;客戶的專案管理者只指派工作與上傳證據,不編 SSP。
  3. 顧問持續訪談、匯入、整理,專案即時看到。
  4. 顧問判斷可以請外部稽核了,按「送審」(就是「啟動稽核」):存一版、凍結一份給稽核輪、資源庫鎖寫。覆核送審走同一套。
  5. 稽核流程本身照舊。送審之後到結案,資源庫都鎖住;只有覆核子輪回到規劃中時可以再整理,新年度走「複製資源庫」。
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
    actor C as 顧問
    participant RL as 合規資源庫<br/>(範本 SSP=工作副本)
    participant V as 版本索引
    participant P as 專案
    participant A as 稽核輪
    C->>RL: 下載訪談表、到客戶現場訪談
    C->>RL: 匯入訪談表(只蓋檔案有填的欄)
    RL->>V: 匯入前自動存一版當備份(source=import-backup)
    loop 整理現況、缺失、建議、附範本
        C->>RL: 暫存(不開版)
        C->>RL: 儲存成新版本
        RL->>V: 存一版(source=manual)
    end
    C->>P: 啟動專案(不複製,直接指向範本 SSP)
    P-->>RL: 規劃頁唯讀讀取同一份
    loop 持續訪談
        C->>RL: 再匯入、再整理、再存版
        RL-->>P: 專案即時看到
    end
    C->>A: 送審(=啟動稽核)
    A->>V: 存一版(source=submit,記 audit_round_id)
    A->>A: 凍結快照給稽核輪
    Note over RL: 送審後到結案資源庫鎖寫
    C->>A: 覆核送審(同一套:存版、凍結、鎖寫)
圖 1 — 顧問訪談到稽核

§3

分工概述(30 秒版)

整案一句話:顧問在合規資源庫裡把訪談結果寫完整(現況、備註、缺失、修改建議、附範本),每整理一輪就存一版;顧問覺得可以了就送審,送審那刻鎖一版給外部稽核用。專案只看資源庫那一份,不能改。

子需求 做什麼 產出 完成怎麼判定(決策者親手做什麼、看到什麼)
一、訪談欄位與匯入(卡 1、2、2b、3、4) 控制項與 AO 加「缺失」「缺失修改建議」;建議下方加「建議附件」;訪談表兩條路徑加三欄;重複匯入只蓋檔案有填的欄 props 新鍵、共用讀寫 helper、整條控制項批次存 API、建議附件表與 API、FE 欄位、Excel 三欄、實施狀態選項進 system_menus、jedi-oscal-v2 合併規則 在資源庫 460 某條控制項填缺失與建議、在建議附件掛一份範本並寫說明,存檔重開還在,且程序書區與程序書文件池看不到它;下載訪談表看到三個新欄,只填缺失欄重新匯入,其他欄沒被清掉
二、資源庫版本(卡 5、6、7) 暫存、儲存成新版本、匯入自動存版、版本歷史、唯讀看舊版、比對、整份還原 版本索引表、存版/暫存/列表/比對/還原 API、版本歷史頁、比對頁 改兩條控制項、存兩版;開第 1 版是唯讀;比對第 1、2 版只標出那兩條的差異;還原到第 1 版,確認框列出會改動的筆數與「目前工作副本會自動存成新版」,確定後歷史多一列,再還原回去內容一字不差
三、一對一與唯讀(卡 8、9、10) 啟動專案指向範本 SSP;一個資源庫終身只綁一個專案;複製資源庫;專案規劃頁唯讀(任務設定照舊可編);每次送審鎖版;送審後鎖寫、只有規劃中可改 啟動流程改寫(先盤點複製鏈)、複製資源庫、守門分流、規劃頁唯讀、送審存版 用資源庫啟動專案後,在資源庫改一條現況,專案規劃頁立刻看到;規劃頁控制項與 AO 欄位全灰、任務指派與到期日仍可改;送審後資源庫存檔鈕不能按、版本歷史多一列「送審」並標對應稽核輪;輪次進整改、結案後仍不能存檔

依賴:子需求一、二可平行;子需求三的送審鎖版用到子需求二的存版。畫面最先出的是資源庫控制項欄位(卡 2)與建議附件(卡 2b)。


§4

決策 D1~D21

項 定案 理由 被排除
D1 缺失與修改建議存哪 OSCAL props 兩個新鍵 gap、recommendation(ns 見 D14),控制項 IR 與 AO statement 兩層都有 與「實施狀態」「現況說明」走同一條路;啟動、凍結、存版都是整列複製,props 自動帶走;OSCAL 允許自訂 props 套件加實體欄(OSCAL 標準沒有這欄,要動 schema);主專案側表(每條複製路徑都要手動補,程序書池就曾因此漏帶);直接寫評估結果或 POA&M(啟動稽核才生成,資源庫階段沒有容器)
D2 備註 就是兩表既有的 remarks,不新增欄位 欄位本來就在;專案規劃頁控制項存檔沒送 remarks(ProjectPlanningView.vue:1443)的漏洞,規劃頁唯讀後自然消失 —
D3 建議附件 獨立一張表 compliance.ssp_control_attachments,掛 IR 或 AO statement;不進程序書池、程序書池不加種類欄、jedi-compliance-audit 不改;存版、還原、複製資源庫時跟著複製,稽核凍結不帶;畫面放在「缺失修改建議」正下方、與「程序書」區塊分開;AO props 舊的 reference-documents JSON 不碰 程序書是客戶自己的 SOP、用來證明現況,要進稽核凍結;建議附件是建議的一部分,客戶照做完就沒用,不該混進稽核基準。同池靠種類欄過濾,稽核側每個讀程序書的地方都要多一個條件,漏一處建議範本就跑進稽核 程序書池加「文件種類」欄(稽核側讀取處逐一加過濾、要改套件);用檔名或描述欄約定(查不了、篩不了)
D4 訪談表欄位 路徑 A(完整匯入)與路徑 B(控制項現況九欄)都加「備註」「缺失」「缺失修改建議」三欄,匯出同步帶出;docx 匯入不動 訪談表就是現況資料 Excel,顧問在現場直接填;兩條路徑共用欄名定義,只改一處兩份表欄位就不一致 docx 一併加(docx 不在顧問訪談流程內)
D5 匯入四個坑全收 ① 套件 update 模式 props 逐鍵合併:檔案有的鍵才蓋;② 資源庫完整匯入用合併語意、不清空重建;③ 實施狀態值域收進 system_menus 當唯一來源(D20);④ props 讀寫 helper 收成一支共用,匯出、差異比對、合併決策同步認得新鍵 不修①②,第二次匯入只填缺失欄,上次的現況說明就被清掉;不修③,下拉、匯入、匯出各說各話;不修④,新鍵要改六處,漏一處就是某條路徑看不到缺失 —
D6 誰能編範本 SSP 具備資源庫編輯權即可(D18),拿掉「只有帳號層超級管理員」的守門(common/authz/ssp.py:215);「顧問」角色之後再定義。這條守門目前走不到(雙模式解析器沒接上),實作是在範本 SSP 的所有寫入入口要求資源庫編輯權 顧問是主要編輯者,現行守門是開發期暫時做法 先建「顧問」角色再開權限(角色定義牽涉授權模型,會卡住整案)
D7 專案規劃頁 資源庫帶來的資料除任務設定外全部唯讀:控制項與 AO 實施層欄位、程序書、建議附件、其他 SSP 頁籤;任務設定(指派、到期日、說明)照舊可編。FE 可編判斷與 BE 專案側 SSP 寫入守門一起改 客戶專案管理者只指派工作與上傳證據;SSP 是顧問的成果,兩邊都能改就互相覆蓋 只在畫面做唯讀(共用端點擋不住,見 §6.4)
D8 資源庫與專案 一對一。啟動專案時 living_ssp_id=template_ssp_id,不複製三件組;啟動時擋「這個資源庫已綁定過任何專案」(不分進行中、結案、封存;新年度一律走複製資源庫);資源庫有專案綁著不能刪;新年度走「複製資源庫」(D17);資源庫沒有公版——公版是框架層概念,module_frames.scope 欄留著、預設不開放、畫面不出現公版資源庫。卡 8 動手前必須先盤點啟動專案的複製鏈並回報 顧問啟動後仍持續訪談,只有指向同一份專案才能即時看到;複製一份就得設計同步,那是兩份真相 維持複製另做同步(雙向衝突與同步時機);一個資源庫多專案共用一份 SSP(不同客戶的現況互相覆蓋);資源庫層加公版旗標(與框架層重複)
D9 送審 送審=啟動稽核。依序「存版(source='submit'、audit_round_id)→ 凍結快照給稽核輪 → 資源庫鎖寫」;覆核輪(close_out)送審走同一套;稽核流程本身不改 外部稽核看的是送審那一刻的內容,顧問要能回頭看送審時寫了什麼;主稽核與覆核各對應哪一版,要能從兩頭查到 稽核中仍允許改工作副本(規劃頁直接指向工作副本,客戶會看到與稽核中內容不一致);覆核另做一套
D10 版本放哪 版號與修訂史寫 OSCAL 原生 metadata.version、metadata.revisions(revision 的 links 帶 rel=predecessor-version);舊版內容用套件 snapshot_ssp 整份複製成獨立 SSP;只多一張索引表 compliance.ssp_versions,設計成「SSP 的版本」(owner_type+owner_id),第一版只有資源庫用;OSCAL 各表不加版本欄 匯出的 SSP 自帶版本資訊;整份 SSP 快照讓看舊版、比對、還原都直接用既有編輯器與 diff 只寫 metadata(做不到回顧、比對、還原);存 JSON 文件快照(還原要走匯入路徑,看舊版與比對要多一層轉換);SSP 主表加 group_id/version_no(FR-019 早期做法,v2 已移除)
D11 版本操作範圍 快照是整份 SSP(主表、12 子表、程序書掛載、建議附件、風險);暫存不開版、儲存成新版本先暫存再快照、匯入前自動存一版當備份(匯入後不另存);唯讀開舊版;版本不提供刪除;看版本歷史與舊版要 oscal.resource-library.read;比對接既有 diff 的「SSP 對 SSP」入口,只比控制項與 AO 實施層(狀態、現況、備註、缺失、建議、程序書掛載、建議附件);還原=整份換回去,先列會改動筆數給顧問確認,確定後把目前工作副本存成一版(pre_restore)再換,永遠可逆;稽核凍結快照不進索引表 顧問在乎控制項層的內容變化,比對先做這一層避免範圍膨脹;逐項還原會讓工作副本變成哪一版都不是 逐項還原;比對擴到其他頁籤
D12 控制項填寫畫面 甲案:控制項與 AO 表單各加兩個文字框,建議下方加建議附件區塊,其他七個頁籤不動;BE 照樣做「整條控制項連 AO 批次存」API 給暫存用 先讓資料有地方放,畫面改版等顧問實際用過再決定 這次重新設計填寫區
D13 範本 460 FR-138 塞在「現況說明」的缺失,新欄位上線後由小卡(卡 4)拆到「缺失」欄 460 是第一個真實案例,拆完正好驗證新欄位 —
D14 props ns 與 name ns=https://guidant.ai/ns/oscal,name=gap、recommendation;全產品之後的自訂 props 用同一個 ns OSCAL 規定自訂 props 帶自家 ns 避免與標準名稱撞 —
D15 建議附件分類 不分類,只有檔案加一行說明,不進 system_menus 與程序書已分表,「放哪張表」就是分類,沒有讀取端要用種類 建議附件分種類
D16 兩張新表的 schema compliance.ssp_versions、compliance.ssp_control_attachments;判準是 model 寫在哪個套件就放哪個 schema,兩張 model 都在主專案;跨 schema FK 指 oscal.system_security_plans 是正常的(先例 project_audit_rounds),FK 寫完整 schema 名 放 oscal 會讓人以為是 jedi-oscal-v2 的表 放 oscal
D17 複製資源庫 把啟動專案現有的複製邏輯(套件 clone_resource_library 三件組+程序書池、表單設定、ssp_risks)搬成「複製資源庫」,再補帶建議附件;版本歷史不帶;啟動專案不再用它 複製路徑與現行啟動專案幾乎相同,搬過來等於重用 匯出 Excel 再匯入(帶不走程序書檔、依賴匯入坑修完);資源庫加公版旗標
D18 資源庫編輯權 =oscal.resource-library.update,不另立能力點。範本 SSP 的所有寫入入口都要求它,含 SSP 共用端點:依「此 SSP 是否為某資源庫的 template_ssp_id」分流,是就走資源庫守門(能力點+稽核中鎖寫),不是才走專案守門 只守資源庫自己的端點,客戶專案管理者仍能從共用端點改到顧問的 SSP 另立新能力點
D19 何時可改 只有綁定專案最新一輪是「規劃中」(planning,任務規劃與任務執行階段)可改;送審後到結案(含 remediation、closed)一律鎖。覆核子輪回到 planning 時可改,子輪送審後再鎖。判斷用白名單(只放行 planning),新增輪次狀態時預設是鎖 專案看到的 SSP 就是這一份,專案一開始稽核,客戶與稽核方看到的內容就不能再被改;新年度要改走複製資源庫 進整改就解鎖(顧問邊整改邊訪談)——結案後資源庫仍可任意改,專案那份 SSP 跟著變;等結案才解鎖
D20 實施狀態值域 六值 implemented/partial/planned/alternative/not_applicable/unknown(=還沒訪談),key 保留底線拼法;進 system_menus group ssp_implementation_status;FE 下拉、Excel 匯入驗證、BE 驗證三處讀同一份;匯出 OSCAL 時才轉標準拼法 not-applicable DEV 現存 implemented 70,914、unknown 2,133、partial 47、not_applicable 13、alternative 2、planned 2;底線拼法散在讀取端與七萬多筆資料,硬改風險大、使用者無感;unknown 是顧問需要的真實狀態 key 對齊 OSCAL 連字號並 migration 既有資料
D21 既有資料 舊模式專案不遷移,維持各自獨立的 SSP 副本、照舊在專案側可寫;一對一檢查只算新模式專案;STG/POC 上線前查有無一資源庫多專案,列進上版檢查項 DEV 資源庫 460 綁 3 個專案、427 綁 1 個,全是舊模式;遷移要決定哪個專案接手範本 SSP,對既有稽核輪沒有收益 遷移既有專案

§5

現況接入點

元件 現況 本案動作
實施狀態、現況說明 props implementation-status、implementation-description;控制項在 ssp_implemented_requirements.props、AO 在 ssp_statements.props(app/oscal/service/ssp_control_implementation_service.py;資源庫側 app/module_frame/service/module_frame_control_default_service.py、module_frame_control_objective_default_service.py) 欄位不動;值域收進 menu(D20)
備註 兩表 remarks 就是「備註」(D2)
AO 識別 statement_id 格式 <control>_obj.N 沿用
同一控制項多筆 IR _ir_for_control(ssp_control_implementation_service.py:888-900)挑「已有說明」那筆 新欄位讀寫、批次存、比對走同一挑選
props 讀寫 helper 六份複製:ssp_control_implementation_service.py:960-989、資源庫兩支 default service、export/ssp_v2_content_loader.py:203、ssp_resources_context_service.py:197、import_diff/snapshot_views.py:43 收成一支(D5④)
程序書池 oscal.ssp_reference_documents+掛載表 ssp_reference_document_mappings(control_implementation→IR.id、objective→statement.id),model 在 jedi-compliance-audit;凍結時 ssp_document_pool_service.py:91 clone_pool_for_snapshot 補複製 不動;存版、還原、複製資源庫複用 clone_pool_for_snapshot
訪談表路徑 A app/oscal/service/ssp_excel_import_app_service.py;欄位 app/module_frame/excel_template/sheet_definitions.py:452-494、中文欄名 header_i18n.py:127-136;寫入 import_adapter/excel_to_oscal_ssp.py:62-110;資源庫模式 mode="replace" 清空重建(:448-510) 加三欄;資源庫模式用合併語意
訪談表路徑 B app/oscal/service/ssp_control_impl_import_service.py,端點 /ssp/<ssp_uid>/control-implementations/import;逐列 update、_setp 逐鍵合併;欄名與資源庫共用 module_frame_template_import_service.py:92;模板版本檢查 excel_parser/version_check.py 加三欄
套件 update 模式 pkg/jedi-oscal-v2/.../oscal_io_service.py:1308 IR/statement 的 props 整份覆寫;None 跳過、清空要傳 "" 逐鍵合併(D5①)
實施狀態值域 三處不一致:FE 下拉寫死在 ModuleFrameTemplateEditView.vue:348-368;Excel 匯入 module_frame_template_import_service.py:79-86;SQL 註解 scripts/sql/2026-06-02-erd-chinese-comments.sql:720 三處讀 menu(D20)
範本 SSP 寫入守門 common/authz/ssp.py:215 _require_admin_for_template 只准超級管理員,但雙模式解析器沒接上(di_containers/oscal/oscal_containers.py:345),實際走不到;資源庫寫入靠 route 能力點+service 直接拿 ssp_id 寫 兩類入口都要求 oscal.resource-library.update(D18)
專案 SSP 寫入守門 common/authz/ssp.py:99-103,187-211 專案管理者+可寫判斷;可寫判斷 domain/oscal/service/ssp_project_resolver.py:111-133(凍結一律鎖;living 在無輪次或當前輪 planning 可寫) 新模式專案改走資源庫守門
SSP 歸屬判斷 生效的是 ssp_project_resolver.py:97-108:先查 projects.living_ssp_id、再查 project_audit_rounds.ssp_id 範本判斷以 template_ssp_id 直比(§6.4)
資源庫編輯頁 src/views/module_frame/ModuleFrameTemplateEditView.vue(2,246 行、八頁籤),路由 /module-frame/:uid/template-edit 只掛新子元件
專案規劃頁 src/views/project/ProjectPlanningView.vue(2,609 行),canEditSsp = apStatus === 'planning'(:158) 唯讀旗標與提示子元件
啟動專案 app/project/service/project_start_app_service.py:347 呼叫套件 clone_resource_library 複製三件組;:378 寫 living_ssp_id;:385-389 _init_ssp_control_implementations 補建控制項;程序書池與 ssp_risks 手動補複製(:231-299, :392-409) 不再複製、直接指向;複製鏈先盤點(卡 8)
讀 living_ssp_id 的地方 11 支(flow_control/project_service.py、cloud_integration/project_tree_loader.py、task_alert/*、oscal/ssp_*_app_service.py、export/ssp_v2_content_loader.py 等) 照常讀;逐支確認不寫
複製資源庫 不存在:FE i18n 有 from_sample: "複製資源庫" 但無畫面使用,BE 無端點 新功能,搬啟動專案的複製邏輯(D17)
稽核凍結 套件 AuditRoundAppService.launch_audit(pkg/jedi-compliance-audit/.../audit_round_app_service.py:402)snapshot_ssp 複製 living SSP 到 project_audit_rounds.ssp_id 並補程序書池;主專案由 app/flow_control/service/oscal_stage_handlers.py 的 planning 階段推進呼叫;輪次狀態 planning → audit_planning → auditing → remediation → pending_reverify → closed;覆核由 launch_reverify 另開 close-out 子輪 送審多存一版(卡 10)
整份複製 pkg/jedi-oscal-v2/.../snapshot/oscal_snapshot_service.py:52 snapshot_ssp(SSP+12 子表+一份 metadata,status=frozen)、:105 clone_resource_library、:188 deep_clone_ssp 存版用 snapshot_ssp
差異比對 app/oscal/service/import_diff/ssp_diff_service.py(四態 unchanged/changed/added/gone、七區;:725 annotate_against_snapshot)、decision_merge.py:107 merge_by_decisions 加「SSP 對 SSP」入口
SSP 主表與 metadata v2 主表只有 id/uuid/metadata_id/status/import_profile_id;oscal.metadata 有 version、revisions JSONB,主專案沒用 開始寫(D10)

§6

詳細設計

6.1 資料模型

① props 新鍵(IR 與 AO statement 都有):

name ns 值 說明
gap https://guidant.ai/ns/oscal 純文字 缺失:少了什麼
recommendation https://guidant.ai/ns/oscal 純文字 缺失修改建議:怎麼補

規則:空字串=刪掉該鍵(與 _setp 一致);讀取時沒有該鍵視為空;全部欄位空時 props 回 None(與 _map_to_props 一致)。匯出 docx/Excel、差異比對、合併決策都認得這兩鍵,由共用 helper 一次處理。

② 表 compliance.ssp_control_attachments(建議附件;主線 migration,GRANT cm_app 含 sequence,RLS 依租戶):

欄 型別 用途
id/uid/tenant_id/org_unit_id 標準欄 RLS 依租戶
context_type varchar(32) NOT NULL control_implementation(掛 IR)或 objective(掛 AO statement)
context_id bigint NOT NULL IR.id 或 statement.id
file_id bigint NOT NULL 指向 upload_files
description text 一行說明
created_user/created_at/updated_user/updated_at 審計欄 API 回傳補 *_user_name

③ 表 compliance.ssp_versions(版本索引;主線 migration,GRANT cm_app 含 sequence,RLS 依租戶):

欄 型別 用途
id/uid/tenant_id/org_unit_id 標準欄
owner_type varchar(32) NOT NULL 擁有者種類,第一版只有 module_frame
owner_id bigint NOT NULL 資源庫 id
ssp_id bigint NOT NULL 這一版的整份快照 SSP(snapshot_ssp 產出,status=frozen);FK → oscal.system_security_plans
version_no int NOT NULL 同一擁有者遞增 1、2、3…
version_label varchar(64) 顯示版號,同步寫 metadata.version
source varchar(32) NOT NULL manual(手動存版)/import(匯入觸發)/submit(送審鎖版)/pre_restore(還原前自動存版)
note text 存版說明
audit_round_id bigint 可空 送審版對應的稽核輪(project_audit_rounds.id);其他來源為空
created_user/created_at 審計欄 API 回傳補 created_user_name

唯一鍵 UNIQUE (owner_type, owner_id, version_no)。

④ OSCAL 原生版本欄(不加欄,只開始寫):每存一版,該版快照與工作副本的 metadata.version 寫版號字串(與 version_label 同步);metadata.revisions 追加一筆 {version, last-modified, title, remarks, links:[{rel: "predecessor-version", href: "#<前一版 SSP uuid>"}]}。

⑤ public.system_menus 實施狀態 seed(主線 phase=seed,ON CONFLICT DO NOTHING,先例 scripts/sql/2026-05-22-seed-oscal-ssp-roles.sql):

group key 顯示(zh-tw)
ssp_implementation_status implemented 已實作
ssp_implementation_status partial 部分實作
ssp_implementation_status planned 規劃中
ssp_implementation_status alternative 替代措施
ssp_implementation_status not_applicable 不適用
ssp_implementation_status unknown 未評估

FE 走 API.SYSTEM_MENU,i18n 走 lang.ssp_implementation_status.<key>;Excel 匯入合法值與 BE 驗證讀同一份;匯出 OSCAL 時 not_applicable 轉 not-applicable。

6.2 三層關係

層 是什麼 誰改 誰看
工作副本 資源庫的範本 SSP,永遠是最新 顧問(稽核中鎖寫) 顧問;新模式專案規劃頁即時唯讀
版本歷史 某時點的整份快照(ssp_versions 每列一份),建立後不再改 沒人 顧問回顧、比對、還原來源
稽核輪凍結快照 每次送審凍結給該輪的那份(project_audit_rounds.ssp_id) 沒人 稽核輪

送審時存的版(source='submit')與稽核凍結是兩份不同的快照,靠 audit_round_id 互指:前者給顧問回顧比對、帶建議附件;後者給稽核輪當基準、不帶建議附件。稽核凍結快照不進索引表。

6.3 版本操作

操作 做什麼 開版嗎
暫存 全頁未存的控制項與 AO 一次存進工作副本(整條控制項連 AO 批次存 API) 否
儲存成新版本 先暫存;再 snapshot_ssp 複製工作副本、依 IR/statement 新舊 id 對照補程序書池掛載、建議附件與 ssp_risks;索引表加一列;寫 metadata.version 與 revision 是(manual)
匯入前備份 匯入確認前自動存一版,匯入後不另存 是(import-backup)
看舊版 開版本快照,既有編輯器帶唯讀旗標;版本索引裡的 SSP 與 status='frozen' 一律不可寫 —
比對 兩版之間或某版對工作副本;只列有差異的控制項與 AO,四態著色;比對欄位:狀態、現況、備註、缺失、建議、程序書掛載、建議附件 —
還原到某版 先算出各頁籤會改動的筆數給確認框(「會改動:控制項 N 條、負責單位 M 筆……」);確定後把目前工作副本存成一版(pre_restore),再把目標版整份複製成新工作副本,module_frames.template_ssp_id 與一對一專案的 living_ssp_id 同時換過去 是(pre_restore)
送審 見 §6.4 是(submit)

存版、還原都是寫入,受資源庫編輯權與稽核中鎖寫管(§6.4)。

6.4 權限分流與鎖寫

範本 SSP 的寫入入口有兩類,規則要在兩類都成立:

入口 現況 本案
資源庫自己的端點(api/module_frame/__init__.py) route 能力點 oscal.resource-library.*,service 直接拿 ssp_id 寫 沿用能力點;寫入前加稽核中鎖寫判斷
SSP 共用端點(系統特性、元件、外部服務、責任人員、控制項現況等,經 SspPermissionChecker) 一律走專案分支 先判「此 SSP 是否為某資源庫的 template_ssp_id」(直接比對,不靠 profile 反查):是→資源庫守門(oscal.resource-library.update+稽核中鎖寫);否→專案守門照舊

送審後鎖寫:範本 SSP 綁定的新模式專案,其當前輪次不是 planning 時(audit_planning、auditing、remediation、pending_reverify、closed),範本 SSP 的所有寫入回 412(D19);覆核子輪回到 planning 時可改、送審時再鎖。

唯讀的 SSP:版本索引裡的 SSP 與 status='frozen' 的 SSP 一律唯讀;讀取入口要認得版本快照(目前它既不是 living_ssp_id 也不是稽核輪 ssp_id,走共用端點會「找不到」)。

專案側:新模式專案的規劃頁,SSP 資料一律唯讀(D7);專案管理者帳號直接打寫入 API,因範本 SSP 走資源庫守門而被擋。舊模式專案維持專案守門與既有可寫判斷(D21)。

6.5 匯入兩路徑

路徑 A:完整匯入 路徑 B:控制項現況
入口 ssp_excel_import_app_service.py ssp_control_impl_import_service.py,/ssp/<ssp_uid>/control-implementations/import
新欄 分頁「適用控制項」加「備註」「缺失」「缺失修改建議」(sheet_definitions.py、header_i18n.py、excel_to_oscal_ssp.py) 九欄加三欄(欄名與資源庫共用 module_frame_template_import_service.py)
模板版本 欄位變動要升模板版本,excel_parser/version_check.py 認得新版 同左
合併規則 資源庫模式不清空重建;套件 update 模式 props 逐鍵合併——檔案有填的欄才蓋,空白欄保留現值 既有 _setp 逐鍵合併,新欄比照
實施狀態驗證 讀 ssp_implementation_status menu 同左
匯出 帶出三個新欄 同左

新模式專案指向範本 SSP,匯入一律從資源庫做;舊模式專案的專案側 mode="update" 照舊(D21)。docx 匯入不動。

6.6 畫面(甲案)

雛形:prototype/index.html(控制項填寫、版本歷史、版本比對、專案規劃頁唯讀)。

資源庫「適用控制項」頁籤:

  • 控制項表單與 AO 表單各在「備註」之後加「缺失」「缺失修改建議」兩個多行文字框。
  • 「缺失修改建議」正下方加「建議附件」區塊:上傳只選檔、寫一行說明,可改說明、可刪除。
  • 既有「程序書」區塊放在建議附件下方,維持現狀、分開呈現。
  • 實施狀態下拉讀 ssp_implementation_status 六值。
  • 頁首加「暫存」「儲存成新版本」(填說明)兩顆鈕與「版本歷史」入口;稽核中兩顆鈕停用並提示原因。
  • 其他七個頁籤不動。ModuleFrameTemplateEditView.vue 已超標,新欄位、建議附件區塊、頁首鈕一律做成新子元件,原檔只加一行掛載。

版本歷史頁:列版號、來源(手動存版/匯入自動存版/送審鎖版/還原前自動存版)、說明、誰、何時;送審版標對應稽核輪(主稽核或覆核)並顯示鎖頭;每列可檢視(唯讀)、比對、還原。還原確認框列出會改動的筆數,並說明目前工作副本會先存成新版。

版本比對頁:選兩版(或某版對工作副本),只列有差異的控制項與 AO,四態著色。

專案規劃頁(新模式專案):控制項與 AO 實施層欄位、程序書、建議附件、其他 SSP 頁籤全部唯讀;頁首一行「內容即時同步自合規資源庫」,有資源庫編輯權的人多一個「前往合規資源庫」連結;任務設定照舊可編。ProjectPlanningView.vue 已超標,唯讀旗標與提示做成子元件。


§7

拆分

依「決策者何時看得到畫面」排序。e2e 屬母卡收口,不在單卡做。只動一支套件 jedi-oscal-v2(卡 3),開發期走 path dependency,發版等決策者明示。

卡 做什麼 主要檔案 依賴 驗收條件(決策者親手做什麼、看到什麼) 會踩的鐵則
卡 1 BE 新欄+共用 helper+批次存 API props gap/recommendation 讀寫;六份 helper 收一支(保留空字串刪鍵、全空回 None);整條控制項連 AO 批次存端點;範本 SSP 兩類寫入入口要求 oscal.resource-library.update(依 template_ssp_id 分流) ssp_control_implementation_service.py、資源庫兩支 default service、export loader、snapshot_views.py、ssp_resources_context_service.py、decision_merge.py、common/authz/ssp.py — 與卡 2 一起驗 先查再寫(helper 收斂不另寫第七份);common/authz/ 當次跑 reviewer;守衛測試
卡 2 FE 控制項欄位+暫存鈕 甲案兩層表單各加兩框;頁首暫存鈕接批次存;實施狀態下拉讀 menu(seed 在卡 3,卡 2 先接 API) ModuleFrameTemplateEditView.vue 只掛新子元件 卡 1 API 介面先定 在範本 460 填一條控制項與其 AO 的缺失、建議,按暫存後重新整理,內容都還在 檔案體積上限(只准拆);下拉不寫死
卡 2b 建議附件 compliance.ssp_control_attachments migration;上傳/列表/改說明/刪除 API(權限同 D18);FE 區塊放缺失修改建議正下方 新 domain/infra/app service、新 route、FE 新子元件 卡 1 在 460 某條控制項與其 AO 各上傳一份並寫說明,重新整理還在;程序書區與「程序書文件池」頁籤都看不到它 migration 鐵則(日期註解、GRANT、schema_migrations、只套 DEV、回報出貨基線待重產);審計欄位 enrich
卡 3 Excel 三欄+狀態選項+套件合併規則 兩路徑加三欄(匯入、匯出、欄名、模板版本);ssp_implementation_status seed 與 FE、Excel、BE 驗證讀 menu、匯出轉標準拼法;jedi-oscal-v2 update 模式 props 逐鍵合併;資源庫完整匯入不清空 sheet_definitions.py、header_i18n.py、ssp_control_impl_import_service.py、excel_to_oscal_ssp.py、ssp_excel_import_app_service.py、module_frame_template_import_service.py、pkg/jedi-oscal-v2/.../oscal_io_service.py、seed migration 卡 1 下載 460 的訪談表看到三個新欄;只填某條的「缺失」重新匯入,該條現況說明與其他條都沒被清掉;實施狀態下拉與 Excel 驗證一致、有「未評估」 jedi 套件異動(plan 列範圍與其他 consumer 風險、path dependency 不 commit、發版等令);system_menus 鐵則
卡 4 範本 460 缺失回填 把塞在現況說明的缺失拆到缺失欄,可半自動(列出含缺失字樣的條目給人確認) DEV 資料作業 卡 1、卡 2 在 460 抽五條,現況說明只剩現況,缺失欄有拆出來的那段 只動 DEV
卡 5 版本索引表+存版 API compliance.ssp_versions migration;存版(暫存→snapshot_ssp→依 id 對照補程序書池、建議附件、ssp_risks→索引→metadata 版號與 revision);版本列表;匯入成功自動存版;版本快照讀取入口唯讀 新 service、ssp_document_pool_service.py:91 複用 卡 1、卡 2b 與卡 6 一起驗 migration 鐵則;@transaction 一個存版一個交易
卡 6 FE 版本歷史頁+存版鈕 頁首「儲存成新版本」(填說明)、版本歷史頁、唯讀開舊版 新頁+新子元件、ui_routes 登記 卡 5 改兩條控制項後存成新版本,版本歷史多一列且來源寫「手動」;點舊版打開,所有欄位不能改 新頁路由 name 要登記 ui_routes;檔案體積上限
卡 7 比對與還原 既有 diff 加「SSP 對 SSP」入口,只比控制項與 AO 實施層;整份還原:算會改動筆數→確認框→存 pre_restore→複製→換 template_ssp_id 與 living_ssp_id ssp_diff_service.py、還原 service、比對頁 卡 5 比第 1、2 版只看到那兩條的差異標記;還原到第 1 版,確認框列出「會改動:控制項 2 條……」與新版號;確定後歷史多一列,再還原回去內容一字不差、程序書與建議附件仍在 先查再寫(diff 用既有引擎不另寫);查記住舊 id 的快取或背景工作
卡 8 啟動改指向+一對一守門+複製資源庫 前置:先盤點 project_start_app_service.py 複製鏈,分「啟動要留/搬去複製資源庫/順手塞的」三類回報,回報後才動;啟動不再複製、指向範本 SSP;擋「已綁定過任何專案」(新 error code);有專案不可刪;複製資源庫(帶程序書池、建議附件、表單設定、ssp_risks,不帶版本歷史) project_start_app_service.py、資源庫刪除、新複製端點與列表動作 卡 2b 盤點清單先交;從資源庫啟動專案,在資源庫改一條現況,專案規劃頁立刻看到;同一資源庫再啟動一次被擋(含該專案已結案或封存後);複製資源庫後新資源庫內容與兩種附件齊全、版本歷史是空的 分析後才改(盤點前置);先查再寫(搬既有複製邏輯)
卡 9 規劃頁唯讀+守門調整 規劃頁資源庫資料唯讀(任務設定照舊可編)、頁首提示;歸屬判斷認得範本(template_ssp_id 直比),專案側 SSP 寫入守門擋新模式專案;確認 11 支讀 living_ssp_id 的地方無寫入 ProjectPlanningView.vue(只加唯讀旗標與提示子元件)、common/authz/ssp.py、ssp_project_resolver.py 卡 8 新模式專案的規劃頁,控制項與 AO 欄位全灰、任務指派與到期日仍可改;用專案管理者帳號直接打寫入 API 被擋;舊模式專案行為不變 common/authz/ 當次跑 reviewer;檔案體積上限
卡 10 送審鎖版+稽核中鎖寫 主稽核與覆核送審都走「存版(submit+audit_round_id)→凍結→鎖寫」;範本 SSP 兩類寫入入口加「當前輪不是 planning 就鎖」 oscal_stage_handlers.py、範本 SSP 寫入守門 卡 5、卡 8 送審後回資源庫,暫存與存版鈕不能按、版本歷史多一列「送審」並標對應主稽核輪;輪次進整改、結案後仍不能編輯;覆核送審後再鎖、多一列標覆核輪 狀態轉換前置條件;新 error code 命名並同步 FE error-code.json
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
flowchart LR
    subgraph S1[子需求一 訪談欄位與匯入]
      C1[卡1 BE 新欄+共用 helper<br/>+批次存 API] --> C2[卡2 FE 控制項欄位<br/>+暫存鈕]
      C1 --> C2b[卡2b 建議附件<br/>表+API+畫面區塊]
      C1 --> C3[卡3 Excel 三欄+狀態選項<br/>+套件合併規則]
      C1 --> C4[卡4 範本 460 回填]
    end
    subgraph S2[子需求二 資源庫版本]
      C5[卡5 版本索引表+存版 API] --> C6[卡6 版本歷史頁<br/>+存版暫存鈕]
      C5 --> C7[卡7 比對與還原]
    end
    subgraph S3[子需求三 一對一與唯讀]
      C8[卡8 啟動改指向<br/>+一對一守門] --> C9[卡9 規劃頁唯讀<br/>+顧問編輯權]
      C8 --> C10[卡10 送審鎖版<br/>+稽核中鎖寫]
    end
    C1 --> C5
    C2b --> C5
    C5 --> C10
圖 2 — 十一張卡的依賴(實線=必須先做)

上版檢查項:STG/POC 上線前查有無「一資源庫多專案」(D21);兩張新表與 seed 的 migration 照環境異動鐵則只先套 DEV,寫完回報出貨基線待重產。


§8

端到端驗收

用 DEV 一個 CRA 資源庫(建議 460),批次走完再一次回報:

  1. 資源庫「適用控制項」頁籤:某條控制項與其一個 AO 填實施狀態「部分實作」、現況、備註、缺失、缺失修改建議;在建議附件各掛一份檔案並寫說明 → 按「暫存」→ 重新整理,全部還在;程序書區與「程序書文件池」頁籤看不到建議附件;實施狀態下拉有六項、含「未評估」。
  2. 下載訪談表,「適用控制項」分頁看到備註、缺失、缺失修改建議三欄且帶出剛填的值;在另一條只填「缺失」、其他欄留白,重新匯入 → 該條現況說明沒被清掉、其他條不變;版本歷史多一列「匯入自動存版」。
  3. 再改兩條控制項 → 「儲存成新版本」填說明 → 版本歷史多一列「手動存版」;檢視上一版,所有欄位不能改。
  4. 比對這兩版 → 只列出那兩條,差異著色。
  5. 還原到較早那版 → 確認框列出會改動的筆數並說明目前工作副本會先存成新版 → 確定 → 歷史多一列「還原前自動存版」,內容回到那版;再還原回去,內容一字不差,程序書與建議附件都在。
  6. 用此資源庫啟動專案 → 在資源庫改一條現況,專案規劃頁立刻看到;規劃頁控制項與 AO 欄位全灰、頁首提示同步自資源庫;任務指派與到期日仍可改。同一資源庫再啟動一次被擋(含該專案已結案或封存後);有專案綁著時刪資源庫被擋。
  7. 用專案管理者帳號直接打 SSP 共用寫入端點(例如系統特性)改這份 SSP → 被擋。
  8. 專案送審(啟動稽核)→ 資源庫暫存與存版鈕停用;版本歷史多一列「送審鎖版」標主稽核輪;直接打寫入 API 回 412。
  9. 輪次推進到整改、結案 → 資源庫仍唯讀。開覆核子輪回到規劃中時可再編輯;覆核送審後再鎖,版本歷史多一列標覆核輪。
  10. 複製此資源庫 → 新資源庫控制項內容、程序書、建議附件、表單設定齊全,版本歷史是空的。
  11. 一個舊模式專案(啟動時複製了 SSP 的既有專案):規劃頁與寫入行為和上線前相同。

§9

風險與陷阱

🔴 範本 SSP 同時是專案的 SSP,唯讀只做在畫面上擋不住

指向後範本 SSP 的 id 就是專案的 living_ssp_id。所有走 SspPermissionChecker 的共用端點會把它判成專案 SSP,套「專案管理者+規劃階段可寫」——客戶專案管理者能透過這些端點改到顧問的 SSP。範本判斷要用 template_ssp_id 直比,命中就走資源庫守門。快照沿用來源的 profile(ssp_clone_service.py:129-131 整列複製根節點),若日後接上雙模式解析器、靠 profile 反查,快照會被判成範本而變可寫——所以不靠 profile。

🔴 重複匯入會清掉上次的內容

套件 update 模式 props 整份覆寫、資源庫完整匯入清空重建,第二次匯入只填缺失,現況說明就沒了。修完要拿「只填一欄重匯」實測,不能只看程式。

🔴 啟動專案後的初始化會作用在範本 SSP 上

_init_ssp_control_implementations(project_start_app_service.py:385-389)對「剛複製出來的新 SSP」補建控制項;指向後它會直接寫範本 SSP,程序書池與 ssp_risks 的補複製會變成自己複製給自己。卡 8 的盤點前置是硬性的。

陷阱 後果 對策
props helper 有六份 漏改一處,那條路徑看不到缺失且不報錯;共用版沒保留「空字串刪鍵」「全空回 None」,清空欄位會存成空字串鍵 卡 1 收成一支並保留兩個行為
同一控制項多筆 IR 缺失寫進 A 筆、畫面讀 B 筆 讀寫、批次存、比對都走 _ir_for_control
守門只改一類入口 另一類入口就是漏洞 兩類入口同時套用能力點與鎖寫;卡 1 到卡 10 之間範本 SSP 沒有稽核中鎖,卡 8 上線前不會有新模式專案,可接受
snapshot_ssp 重產 IR/statement id 程序書掛載與建議附件指向舊 id 存版、還原、複製資源庫都複用 clone_pool_for_snapshot 的 id 對照,建議附件照同一份對照複製;任務與控制項對應(workflow_execution_control_mapping)用 control_id 字串+輪次,不受影響
snapshot_ssp 不含 ssp_risks 版本快照少了風險 存版與還原另外補複製(啟動專案現行做法)
還原換掉範本 SSP 的 id 記住舊 id 的快取或背景工作讀到舊版 template_ssp_id 與 living_ssp_id 同交易換;卡 7 查 task_alert 兩支等記 id 的地方
不可為空欄位(例 by_component.description) 複製路徑寫入失敗 沿用套件既有處理
送審產生兩份快照 容易誤以為重複 刻意保留:送審版帶建議附件、稽核凍結不帶,靠 audit_round_id 互指
ModuleFrameTemplateEditView.vue 2,246 行、ProjectPlanningView.vue 2,609 行 往裡加會被 reviewer 判阻斷 新邏輯一律新子元件,原檔只加一行掛載

§10

不做與後續

項目 去向
控制項填寫區重新設計(D12) 全部做完、顧問實際用過再看
其他七個頁籤改動、版本比對擴到控制項以外(D11) 另案
AO props 舊的 reference-documents JSON(D3) 不碰
docx 匯入加欄位(D4) 不在顧問訪談流程內
「顧問」角色定義(D6) 之後定義時把 oscal.resource-library.update 配進去
稽核流程本身的改動(D9) 不做
既有一資源庫多專案資料遷移(D21) 不做;上版前查 STG/POC
版本歷史隨複製資源庫帶走(D8) 不做
資源庫層公版與公版旗標(D8、D17) 公版屬框架層
建議附件分類(D15) 不做
逐項還原(D11) 不做
缺失報告產出 卡 4 回填完成後另議