FR-145 · 設計定案 v1 · 2026-10-17

結案報告與一包下載:設計定案

稽核報告掛稽核次、階段結案報告與專案總報告自動建立、六章文件版面、報告包含凍結證據與問卷 PDF、定稿與下載日誌

稽核報告(Word/PDF/Excel)掛在每個稽核次後面,結案就能下載。「專案調查結果」改造成結案報告:輪次結案仍有不符合時自動建該輪的階段結案報告、專案完成時自動建專案總報告;六章只有「總結與建議」由人寫,其餘從稽核計畫、稽核結果、改善計畫即時算。下載報告包拿 Word、PDF、證據對照表、各稽核次報告與工作表、依控制族群/控制項/評估目標分資料夾的凍結證據(問卷填答轉 PDF)。定稿鎖總結記版號;Word 給顧問自行修改交付,系統只記下載日誌。本文件寫定案規則、為什麼這樣定、踩到會怎樣。

D1~D16 定案(2026-10-17) 六張卡;1、2 可先派,3~5 等 FR-143 不動套件;一支主線 migration 陷阱:證據必須取凍結版本、縮範圍的「未稽核」≠「未判定」

🔴 這份是設計決策,不是現況。 內文停在 2026-10-17 定稿當時,實作改動不回頭改寫這裡。

狀態:設計定案,已開卡|討論稿:discussion.md|雛形:prototype/index.html

檔案路徑與行號以 2026-10-17 為準,查不到時以函式名重新定位。路徑慣例:BE 路徑相對 compliance-manager-be/;FE 路徑相對 compliance-manager-fe/;pkg/ 代表 ~/Projects/Jedicogy/module/jedi-python-package/<套件>/<套件底線名>/;三個 repo 都在 feature/FR-139。

名詞:輪次=compliance.project_audit_rounds 一筆;稽核次=compliance.audit_round_passes 一筆,各自一組 AP/AR/POA&M;階段結案報告=一輪一份;專案總報告=一專案一份;定稿=鎖總結段、記版號、報告包改正式版;報告包=zip;證據對照表=報告包內的 Excel 索引;凍結佐證=FR-142 結案時 ar_close_service._freeze 寫進 assessment_observations 的採用佐證,帶 content-hash 與 frozen-at props。

§1

變更紀錄

日期 變更 對應
2026-10-17 v1:D1~D16 定案;資料模型、事件掛點、讀模型、端點契約、報告包契約、六張卡、端到端驗收 討論稿定案

§2

分工概述(30 秒版)

整案一句話:稽核報告掛在稽核次後面結案即可下載;「專案調查結果」改成結案報告,一輪一份階段報告(輪次結案仍有不符合才建)、專案完成一份總報告,六章只有總結由人寫,其餘系統算;報告包含 Word/PDF、證據對照表、各稽核次報告與工作表、依控制結構分資料夾的凍結證據。

卡 做什麼 產出 完成怎麼判定(決策者親手做什麼、看到什麼)
1 稽核作業清單每列「下載報告」下拉;BE 選檔端點;FR-142 Word 附件後加「改善計畫」一節 FE 清單欄、新 route、ar_docx_generator 加節 稽核作業清單已結案列點「下載報告」選 Word,開檔最後一節是改善計畫表(任務、執行人員、到期日、措施);無缺失稽核次該節印「本次稽核無不符合項目,無改善計畫」;矯正中印「改善計畫尚未送出」;稽核中列印「結案後開放」;Excel 有改善計畫給改善計畫工作表否則給稽核結果工作表
2 migration 加欄;輪次結案/專案完成掛「建報告」;清單端點一專案一列+子列;FE 清單頁重做;選單改名 scripts/sql/ 一支、app/project_summary_report/ 事件與清單、FE ProjectSummaryReportManage.vue 重做 DEV 跑一輪有缺失結案 → 清單該專案展開多一列「第 N 輪結案報告 待定稿」;跑一輪無缺失結案 → 只多「專案總報告 待定稿」;側選單顯示「結案報告」;既有舊列仍在、點開唯讀
3 階段結案報告讀模型(六章+附件一)、報告頁 FE、存檔/定稿/修訂、Word/PDF、下載日誌 新 closing_report_* service、docx 範本、FE 報告頁 開報告頁六章數字與 DEV 該輪 AP/AR/POA&M 對得上(符合數、不符合清單、改善任務);寫總結存檔→定稿後第 5 章唯讀、狀態「已定稿 v1」;下載 Word 開檔六章加附件一;側欄下載紀錄多一列;修訂→再定稿變 v2
4 報告包 zip:Word、PDF、證據對照表、各稽核次 Word 與 Excel、證據資料夾(凍結版本)、問卷填答 PDF;定稿版存檔 closing_report_bundle_service.py、survey_answer_pdf.py 下載 zip 解開:資料夾是 族群/控制項/評估目標;對照表每列路徑在 zip 內找得到;問卷佐證是 PDF 且題目答案齊;連結只在對照表;未採用佐證有列無檔;定稿後再下載檔名帶 _v1
5 專案總報告:七章讀模型(各輪演進、跨多次未改善、最終符合度逐條、各輪總結帶入)、總報告包收各輪子包+合併對照表 沿用卡 3/4 加 final 分支 專案完成後清單多「專案總報告 待定稿」;開頁第 2 章一列一次稽核、跨多次未改善列出判定軌跡;第 5 章帶入第 1 輪已定稿總結;zip 內有 第1輪/、覆核輪/ 與合併對照表(多「輪次」欄)
6 FR-143 改善計畫工作表匯出加「列全部評估目標」開關(追加到 FR-143 卡 4 CM-2844,不另開) poam_workbook_* 匯出後符合與不適用的列也在、改善欄空

依賴:1、2 可先派(1 的改善計畫節讀 FR-143 CM-2841 的 POA&M,若 CM-2841 未落地先用「尚未送出」分支);3 等 2 與 FR-143 CM-2842;4 等 3;5 等 3、4;6 隨 FR-143 CM-2844。


§3

決策定案

定案理由與被排除方案見討論稿 D1~D16,此處只列結論供實作對照。

D 結論
D1 稽核報告掛稽核次;closed 或 remediation 可下載,auditing 印「結案後開放」
D2 Word=FR-142 報告+「改善計畫」節(三態:有/無/尚未送出);Excel=有 POA&M 給改善計畫工作表否則稽核結果工作表,一律列全部評估目標;PDF 同 Word
D3 階段結案報告綁 audit_round_id 一輪一份;專案總報告綁 project_id 一專案一份
D4 輪次結案時最終稽核 not_met > 0 才建階段報告;= 0 專案完成只建總報告;覆核又沒過再開一輪照建
D5 系統自動建,不設建立鈕;建立即 draft
D6 狀態 draft/issued 兩態;清單分段鈕依專案:待撰寫/已完成/尚未結案
D7 清單一專案一列,展開子列依時間序,總報告固定最後
D8 文件版面;階段六章+附件一,總報告七章+附件一;只有總結由人寫、不標撰寫者
D9 階段報告定論取該輪最後一次稽核;總報告最終符合度逐評估目標取最後一次判定
D10 存檔/定稿/下載(下拉:Word、PDF、zip、報告包內容)三分開;定稿後存檔隱藏、定稿變修訂
D11 Word 與 PDF 都給;每次下載記稽核事件;系統不介入後續
D12 報告包結構與對照表欄位(見「報告包契約」);問卷轉 PDF;連結只進對照表;證據取凍結版本
D13 版本沿用 project_summary_report_history;定稿加 version_no/issued;還原只還總結段;定稿版 zip 存儲存後端
D14 總報告定稿不擋各輪未定稿;第 5 章該輪標「尚未定稿」
D15 能力點沿用 grc.summary-report.*:read/export 給 manager 與 auditor,update(存檔、定稿、修訂)只給 manager;稽核作業下載沿用 FR-142 守門
D16 Word 套 FR-141/142 同一份 docx 範本;編輯器沿用 TipTap;第 5 章 HTML 走既有 bleach 白名單

§4

現況接入點

元件 現況(2026-10-17 實查) 本案動作
compliance.project_summary_reports infra/project_summary_report/models/project_summary_report.py:uid、project_id、name、summary、is_delete 卡 2 加 report_type、audit_round_id、status、issued_version、issued_at、issued_user
compliance.project_summary_report_history models/project_summary_report_history.py:report_id、type(U/R)、name、summary 快照 卡 3 加 version_no、issued、bundle_ref
端點 api/project_summary_report/__init__.py:23-31:list(POST)、CRUD、export(PDF)、histories、history、history-revert 卡 2 改 list 回模型;卡 3 加 issue/revise/export?format=docx|pdf、下載日誌;卡 4 加 bundle
App service app/project_summary_report/service/project_summary_report_service.py:_require_participant(:38)守門、CRUD(:69-176) 卡 2 加 create_for_round/create_for_project、清單讀模型;卡 3 新檔 closing_report_app_service.py(讀模型)不往既有檔塞
側選單 ui_routes id 15:report-manage /project-summary-report 群組 42 sort 70;子頁 74(tab-view)、75(history) 卡 2 seed migration 改 name/i18n key 為 closing-report;路徑不動
FE src/views/project-summary-report/:Manage 329 行、Form 344、TabView 52、History 159、TipTapEditor 323 卡 2 重做 Manage;卡 3 新 ClosingReportView.vue(文件版面)取代 Form/TabView;History 沿用加定稿標記
稽核次結案與凍結 app/flow_control/service/ar_close_service.py:31 close():守門→_freeze(:54)→mark_closed→推進站;凍結項寫 assessment_observations 經 _observations.upsert_adopted,每項 props 帶 content-hash、frozen-at 卡 4 讀凍結項:relevant-evidence[].href 定位檔案/問卷/連結,props 取雜湊
輪次結案與專案完成 pkg/jedi-compliance-audit/app/service/audit_round_app_service.py:finalize_audit(:470,terminal=True 才 closed)、_sync_project_status(:157,全輪 closed → ProjectStatus.COMPLETED,呼叫點 :283/:435/:490) 卡 2 在主專案 audit_round_route 對應 app service 呼叫後掛 hook(不改套件):輪次轉 closed → create_for_round;專案轉 COMPLETED → create_for_project
稽核結果報告 ar_report_export_service.py(135 行)組 ArReportModel;ar_docx_generator.py(192 行):generate(:68)、_append_record_table(:85)橫式附件 卡 1 在 _append_record_table 之後加 _append_poam_section;model 加 poam_rows、poam_state
稽核結果 Excel ar_workbook_export_service.py:FORMATS=("xlsx","docx","pdf","zip"),export(round_uid, fmt, …) 卡 1 新 route 依 POA&M 存在選 poam_workbook_*(FR-143 CM-2844)或此
稽核計畫匯出 ap_report_export_service.py、ap_workbook_export_service.py,GET /ap/<uid>/export?format= 卡 4 直接呼叫組 zip
稽核作業清單 FR-142.8 稽核作業 表格,歸屬 project_participants role in (auditor, manager, reviewer) 卡 1 FE 加「稽核報告」欄
問卷填答 pkg/jedi-survey/app/service/question_answer_service.py:95 get_answer_list_by_task_survey_uid;凍結項 href urn:guidant:task-survey:<survey_uid>(ar_objective_view.py:77) 卡 4 新 survey_answer_pdf.py:題目+答案排表經 render_pdf
PDF 渲染 render_pdf(WeasyPrint,project_summary_report_route.py:171);SspLibreOfficeConverter(docx→pdf) 卡 3 Word 經 LibreOffice 轉 PDF,與 FR-141/142 一致
稽核事件日誌 既有埋點(reference_audit_event_logging_pattern) 卡 3 下載日誌 closing_report_download
儲存後端 既有 storage 設定(FR-039 系列) 卡 4 定稿版 zip 存檔

§5

詳細設計

① 稽核次下載與改善計畫節(卡 1)

端點:GET /audit-round/<round_uid>/pass/<pass_uid>/report?format=docx|pdf|xlsx,守門沿用 audit_round_route.py 的 AR 匯出。

選檔邏輯(app service 層):

pass.status in (closed, remediation) else 412 GRC_PASS_NOT_CLOSED
poam = poam_app_service.get_submitted(pass)        # FR-143 CM-2842;None=尚未送出或無缺失
format xlsx:
    poam and poam.submitted → poam_workbook_export(pass, all_objectives=True)   # CM-2844 開關
    else                    → ar_workbook_export(pass)
format docx|pdf:
    model = ar_report_export_service.build(pass)
    model.poam_state = 'has' | 'none' | 'pending'    # none=最終 not_met==0;pending=有不符合但 POA&M 未送出
    model.poam_rows  = [(ctrl, task, owners, due, measure)]
    docx = ar_docx_generator.generate(model); pdf 經 SspLibreOfficeConverter

ar_docx_generator:generate() 在 _append_record_table 後呼叫 _append_poam_section(doc, model):直式新節、標題「改善計畫」、poam_state 三態文案、has 時五欄表(控制項、改善任務、執行人員、到期日、改善措施),表頭重印沿用 _repeat_header。檔已 192 行,新節邏輯放新檔 ar_docx_poam_section.py 由 generator 一行呼叫。

FE:稽核作業清單加「稽核報告」欄,closed/remediation 放「下載報告」下拉(Word/PDF/Excel,Excel 項文字依後端回的 workbook_kind 顯示「改善計畫工作表」或「稽核結果工作表」);auditing 印「結案後開放」。清單端點回每列加 report_available: bool、workbook_kind: 'poam'|'ar'。

② 資料模型與自動建立(卡 2)

migration(主線 phase=active,一支):

ALTER TABLE compliance.project_summary_reports
  ADD COLUMN report_type varchar(20) NOT NULL DEFAULT 'legacy',   -- stage | final | legacy
  ADD COLUMN audit_round_id integer REFERENCES compliance.project_audit_rounds(id) ON DELETE CASCADE,
  ADD COLUMN status varchar(20) NOT NULL DEFAULT 'draft',          -- draft | issued
  ADD COLUMN issued_version integer NOT NULL DEFAULT 0,
  ADD COLUMN issued_at timestamptz,
  ADD COLUMN issued_user varchar(50);
CREATE UNIQUE INDEX uq_psr_round ON compliance.project_summary_reports(audit_round_id) WHERE audit_round_id IS NOT NULL AND is_delete = 0;
CREATE UNIQUE INDEX uq_psr_final ON compliance.project_summary_reports(project_id) WHERE report_type = 'final' AND is_delete = 0;
ALTER TABLE compliance.project_summary_report_history
  ADD COLUMN version_no integer, ADD COLUMN issued boolean NOT NULL DEFAULT false, ADD COLUMN bundle_ref varchar(500);
-- ui_routes id 15 name report-manage → closing-report(i18n key 跟著改)

既有列 report_type='legacy'、status='issued'(視為已定稿、唯讀)。

自動建立:主專案 app/project/service/(呼叫 audit_round_app_service.finalize_audit/close_round 的那層)在套件回傳後,同一 @transaction 內呼叫 closing_report_creator.on_round_closed(round):

if round.status != closed: return
not_met = ar_objective_app_service.final_not_met_count(round.last_pass)
if not_met > 0: create_for_round(round)            # stage,name=f"第 {round.round_no} 輪結案報告"
project = reload; if project.status == COMPLETED: create_for_project(project)   # final,name="專案總報告"

兩個 create 都 idempotent(查唯一索引已有就跳過)。不改套件;套件事件已有 _sync_project_status 寫 COMPLETED,主專案只需在呼叫後重讀。

清單端點:POST /project-summary-reports(既有)回模型改為一專案一列:

{"project_uid","project","framework","manager","consultant","progress":{"round_no","stage_label","at"},
 "bucket":"pending|done|none","draft_count","issued_count","latest_issued_at",
 "reports":[{"uid","report_type","label","covers":[稽核次標籤],"status","not_met_final","issued_at","issued_version"}]}

bucket 由後端算;分段鈕筆數走 meta.bucket_counts。歸屬:_require_participant 既有邏輯(manager/auditor),reviewer 不列(D15)。

FE:ProjectSummaryReportManage.vue 重做為 DataTable 行展開(expandedRows 用物件 key);子列欄照雛形;點子列進卡 3 報告頁。選單 i18n report-manage 改「結案報告」。

③ 階段結案報告讀模型與頁面(卡 3)

讀模型 closing_report_app_service.get_stage_report(report_uid),全部即時算:

章 資料來源與算法
封面/1 專案概況 project、round、audit_round_passes(nature、seq、audit_start/end)、最後一次 AP 的 terms-and-conditions(受稽單位、部門、顧問、稽核人員);期間=第一次 AP audit_start ~ 輪次 closed_at
2 整體符合度 每個 pass 的 AR findings 統計(met/not_met/na/total,符合率=met/(total−na));族群矩陣=findings 依 control family 分組 × passes,縮範圍未涵蓋為 null;定論=最後一個 pass
3 主要缺失與風險 最後一個 pass 的 finding state=not-satisfied,join risk characterizations severity(高→中→低排)、observation 稽核發現、remediation(recommendation) 稽核建議
4 改善計畫摘要 FR-143 POA&M(CM-2842 讀端點):poam-item → response(planned) → task(執行人員、到期日、改善措施);無 POA&M 印「本輪最終稽核無不符合項目」
5 總結與建議 summary 欄 HTML
6 附件清單 卡 4 bundle manifest
附件一 逐 part_id:各 pass 的 finding state(null=未稽核),最終=最後一個 pass

端點:

方法 路徑 說明
GET /closing-report/<uid> 讀模型(六章+附件一)+ status/version/下載紀錄
PUT /closing-report/<uid>/summary 存檔第 5 章(status=draft 才可;記 history type U)
POST /closing-report/<uid>/issue 定稿:守門 summary 非空→status=issued、issued_version+1、history 記 version_no/issued=true、卡 4 產定稿版 zip 存 bundle_ref。manager 守門
POST /closing-report/<uid>/revise 修訂:status=draft(版號不退)。manager 守門
GET /closing-report/<uid>/export?format=docx|pdf 完整報告;draft 時 PDF 加「草稿」浮水印、檔名不帶版號;issued 帶 _v<N>;記事件 closing_report_download

Word:新 closing_report_docx_generator.py,範本 app/oscal/templates/closing/stage_report_template.docx(從 FR-142 ar_report_template.docx 複製改章節);docxtpl 渲染六章,附件一用 python-docx 橫式表(沿用 ar_docx_generator._landscape_section、_repeat_header)。第 5 章 HTML → docx 走既有 bleach 白名單後以 html2docx 風格轉段落(先查 SSP 匯出是否已有 HTML→docx helper,有就用)。

FE ClosingReportView.vue:文件版面照雛形 round-closing-report.html(封面、章節、表格、右側目次與下載紀錄);頁首存檔/定稿/下載下拉;TipTap 第 5 章;定稿後唯讀+修訂。超過 800 行拆子元件(封面、章節表、附件表、側欄)。

④ 報告包(卡 4)

closing_report_bundle_service.build(report) -> BytesIO:

<專案>_<第N輪|專案總報告>_結案報告[_v<N>]/
├─ 00-完整報告.docx、00-完整報告.pdf                 ← 卡 3 export
├─ 01-證據對照表.xlsx                               ← 本卡
├─ 第<seq>次<內部|外部>稽核/                        ← 每個 pass
│   ├─ 稽核計畫.docx                                ← ap_report_export_service
│   ├─ 稽核報告.docx                                ← 卡 1 選檔(含改善計畫節)
│   └─ 改善計畫工作表.xlsx | 稽核結果工作表.xlsx     ← 卡 1 選檔
└─ 證據/<族群代碼 族群名>/<控制項>/<評估目標>/
    ├─ <原檔名>                                     ← upload_files 以凍結 content-hash 對應版本
    └─ 問卷填答_<問卷名>.pdf                         ← survey_answer_pdf

凍結項來源:assessment_observations 該 AR result 的採用項(_observations.list_adopted(ar_result_id),CM-2826 已有讀法),每項 relevant-evidence[].href:/files/<uid>→檔案、urn:guidant:task-survey:<uid>→問卷、其他→連結;props 取 content-hash、frozen-at。檔案以 content-hash 對 upload_files.sha256 取版本,取不到(檔被刪)在對照表標「檔案已不存在」不中斷。

證據對照表欄:稽核次、控制族群、控制項、評估目標、類型(檔案/問卷/連結)、名稱、包內路徑、雜湊/快照識別、採用(是/否)、備註。未採用項來自同 observation 的 adopted=false 紀錄,留列不收檔。

問卷 PDF survey_answer_pdf.render(task_survey_uid) -> bytes:get_answer_list_by_task_survey_uid 取題目與答案,HTML 表(問卷名、填答人、填答時間、題號/題目/答案)經 render_pdf。凍結時記的是 survey_uid,答案取當下最新一筆 history(問卷填答在稽核後不會再改,FR-142 D10 已鎖)。

定稿版存檔:issue 時 build 一次存儲存後端,history.bundle_ref 記路徑;歷史頁該筆可重下載。draft 下載即時 build 不存。

大小:證據檔總量超過 1 GB 時改背景工作(background_jobs)產檔後通知,本案先同步產、超過門檻回 413 提示;門檻進 config。

⑤ 專案總報告(卡 5)

同卡 3 讀模型加 report_type=final 分支:

章 算法
1 概況 全部輪次與 passes;最終狀態
2 各輪演進 每輪每 pass 統計一列;跨多次未改善=同 part_id 連續 ≥2 個 pass not-satisfied,列判定軌跡與最終通過日
3 最終符合度 逐 part_id 取最後一次 finding(任一輪),族群分組
4 缺失與改善紀錄 全部曾 not-satisfied 的 part_id:首次發現 pass、POA&M 任務、覆核結果
5 各輪總結 各 stage 報告 summary(issued 才帶,draft 標「尚未定稿」)
6 專案總結與建議 本報告 summary
7 附件清單、附件一 附件一各欄=全部 passes+最終

總報告包:第1輪/、覆核輪/ 各放該輪 stage 報告包內容(有定稿版用定稿版,否則即時 build);01-證據對照表.xlsx 合併各輪加「輪次」欄;00-專案總報告.docx/pdf。

⑥ FR-143 Excel 開關(卡 6,追加 CM-2844)

poam_workbook_export(..., all_objectives: bool = False):True 時列全部評估目標,符合/不適用列改善欄空、灰底唯讀;頁面匯出鈕旁勾選「列全部評估目標」預設勾;卡 1 呼叫固定 True。


§6

端到端驗收

  1. 稽核次下載:DEV 一個已結案有缺失的稽核次,稽核作業清單該列「下載報告」→ Word 最後一節「改善計畫」有表;同專案無缺失稽核次該節印「無」;矯正中列可下載、該節印「尚未送出」;稽核中列印「結案後開放」。Excel:有 POA&M 的下載到改善計畫工作表且含符合列、改善欄空;無 POA&M 的是稽核結果工作表。
  2. 自動建立:從 FR-140 流程開一輪,外稽留 2 條不符合結案 → 結案報告清單該專案展開多「第 1 輪結案報告 待定稿」;再開覆核輪全過 → 專案完成,多「專案總報告 待定稿」。另一專案一次全過結案 → 只有「專案總報告」。
  3. 報告頁:開第 1 輪報告,第 2 章各稽核次數字=DEV AR 統計;族群矩陣第 2 次內稽未涵蓋族群印「未稽核」;第 3 章兩條不符合與風險等級、稽核發現與稽核報告一字不差;第 4 章任務與 FR-143 送出內容一致;附件一列數=評估目標數。
  4. 存檔/定稿:第 5 章空白按定稿 → 擋;寫字存檔 → 歷史多一筆 U;定稿 → 狀態已定稿 v1、第 5 章唯讀、存檔鈕消失、定稿鈕變修訂、歷史該筆 issued;修訂→改字→定稿 → v2;歷史頁「還原到 v1」→ 第 5 章回 v1 文字、狀態仍 draft。
  5. 下載與日誌:draft 下載 PDF 有「草稿」浮水印、檔名無版號;issued 下載檔名 _v2;每次下載側欄「下載紀錄」多一列(人、時間、格式);DB 稽核事件表多 closing_report_download。
  6. 報告包:issued 下載 zip 解開:結構照契約;對照表每列「包內路徑」在 zip 內存在;問卷佐證是 PDF 開得了、題目答案齊;連結類只在對照表;未採用項有列無檔;改一個 DEV 證據檔再下載 → 包內仍是舊版(雜湊相符)。
  7. 總報告:專案完成後開總報告,第 2 章四列(內稽 1、內稽 2、外稽 1、覆核)、跨多次未改善兩條軌跡;第 3 章合計符合 57 不符合 0 不適用 2;第 5 章帶入第 1 輪 v2 總結;zip 內 第1輪/ 與 覆核輪/、合併對照表有「輪次」欄。
  8. 權限:auditor 帳號開報告頁可讀可下載、存檔與定稿 403;reviewer 帳號清單不列;viewer 403。
  9. 舊資料:既有「專案調查結果」列仍在清單(子列標「舊版」)、點開唯讀、無報告包。
  10. FR-142 既有:test/ 下 ar 相關測試與 FR-142 e2e 不壞;稽核結果頁「結案」行為不變。

§7

拆分表

卡 Notion 做什麼 主要檔 依賴 規模
1 CM-2855 稽核作業清單「下載報告」+選檔端點+Word 改善計畫節 api/project/routes/audit_round_route.py、新 ar_docx_poam_section.py、FE 清單元件 FR-143 CM-2841/2842(POA&M 讀);未落地先走 pending 分支 中
2 CM-2856 migration、自動建立 hook、清單端點、FE 清單重做、選單改名 scripts/sql/2026-10-17-closing-report-columns.sql、app/project_summary_report/、app/project/service/(hook)、FE Manage — 中
3 CM-2857 階段報告讀模型、端點、Word/PDF、FE 報告頁、下載日誌 新 app/closing_report/、docx 範本、FE ClosingReportView.vue 2、FR-143 CM-2842 大
4 CM-2858 報告包:zip、證據對照表、證據資料夾、問卷 PDF、定稿版存檔 closing_report_bundle_service.py、survey_answer_pdf.py 3 大
5 CM-2859 專案總報告七章、總報告包 卡 3/4 加 final 分支 3、4 中
6 CM-2860 FR-143 Excel 列全部開關 poam_workbook_* FR-143 CM-2844 小

序列組:卡 1 與卡 2 可平行;卡 3 之後序列。卡 1 與卡 3 都動 ar_docx_generator 周邊,卡 3 等卡 1 合回。


§8

坑與陷阱

  • 證據必須取凍結版本:assessment_observations 採用項 props 的 content-hash 才是報告包要用的;用 upload_files 現在的檔會在結案後被換。對應版本取不到要在對照表標出,不中斷打包。
  • 問卷 href 是 urn:guidant:task-survey:<uid>(ar_objective_view.py:77),不是檔案路徑;分類型時先判 scheme。
  • 縮範圍的 null ≠ 未判定:第 2 次內稽未涵蓋的評估目標在附件一與族群矩陣印「未稽核」,有 finding 但 state 空才是「未判定」。讀模型兩者分開欄位。
  • 改善計畫章節三態:has(POA&M 已送出)、none(最終 not_met==0)、pending(有不符合但未送出)。判 none 看 AR 不看 POA&M。
  • 自動建立要 idempotent:輪次結案事件可能重入(覆核輪 close_round 與 finalize_audit 都會 _sync_project_status),用唯一索引擋重複,不靠流程保證只叫一次。
  • hook 放主專案不放套件:_sync_project_status 在 jedi-compliance-audit;本案在主專案呼叫套件 app service 的那層之後掛,避免動套件發版。
  • 既有列 report_type 要有預設:NOT NULL DEFAULT 'legacy',否則 migration 在有資料的庫炸。
  • ar_docx_generator 已 192 行、ProjectSummaryReportManage.vue 329 行:新節與新頁一律新檔,不往裡塞(CLAUDE.md 800/60 行規則)。
  • PDF 浮水印:LibreOffice 轉出的 PDF 加浮水印要在 docx 範本層做(頁首浮水印文字框 + 條件),不是事後蓋 PDF。
  • 下載日誌 payload 不含內容:只記識別、格式、版本(資安 log 規則)。
  • DataTable 行展開:PrimeVue 3.53 expandedRows 用物件 {[uid]: true},不是陣列。
  • 報告包大小:證據總量大時同步產會逾時;門檻進 config,超過回 413,背景產檔列為後續。
  • 本卡 2 新增主線 migration 1 支:回寫時明講「出貨基線待重產」。