證據管理 功能群總覽¶
本檔放「本功能群多個頁面共用的知識」:頁面地圖、AI 證據分類生命週期、兩種「證據」概念的區分、儲存後端與雲端 / Agent 來源、角色基調、核心資料模型。
各頁面 spec 引用本檔,只寫自己頁面的差異——改共用邏輯時改這裡一份。
1. 頁面地圖¶
本功能群橫跨證據分類閉環(AI 分類 → 覆核 → 報表)與證據來源基礎建設(雲端整合 / 檔案 Agent / 儲存設定)兩塊。
| 頁面 | FE route | 用途一句話 | spec |
|---|---|---|---|
| 自動分類批次清單 | /project/projects/:id/round/:roundUid/auto-classify |
該輪歷次自動分類作業的歷史清單(入口、續作、清理暫存檔) | ✅ 證據分類覆核 §14 |
| 自動分類批次流程頁 | /project/projects/:id/round/:roundUid/auto-classify/:batchUid |
一批作業的四步流程:上傳 → AI 分類 → 確認分類 → 歸檔完成 | ✅ 證據分類覆核 §14 |
| 證據分類覆核(批次線) | /project/projects/:id/evidence-batches/:batchUid/review/:runUid |
分類結果逐檔審閱 + 手動修正(嵌在批次流程頁第③步) | ✅ 證據分類覆核 |
| 證據分類覆核(Drive 線) | /project/projects/:id/ap/:apUid/classify-evidence/run/:runFolderId |
同上,舊 Drive 分類結果的入口 | ✅ 證據分類覆核 |
| 分類驗證報表 | .../run/:runFolderId/report/validation |
對照 User 修正後狀態,量化 AI 準度(召回 / 精確) | ✅ 分類驗證報表 |
| 分類誤判報表 | .../run/:runFolderId/report/adjudication |
以中立正解基準(CANON)裁判 AI vs User | ✅ 分類誤判報表 |
| 雲端整合(Drive) | /settings/cloud-integrations |
租戶 Google Drive 連接 / 同步狀態管理 | ✅ 雲端整合 |
| 檔案 Agent 管理 | /system/remote-agent-manage |
FR-039 客戶端檔案 Agent 端點登錄 / 狀態 | ✅ 檔案 Agent 管理 |
| 儲存設定 | /system/storage-config |
全租戶檔案儲存後端(local / MinIO / remote_agent / Drive)設定 | ✅ 儲存設定 |
兩份分類報表(validation / adjudication)是同一個 run 的下游唯讀檢視,各自對應獨立 FE route 與 view,分為兩份 spec:驗證報表(量化準確度)與誤判報表(質化誰對誰錯)。
2. AI 證據分類生命週期(本群分類閉環的核心)¶
分類有兩條線並存,差別在「檔案從哪來、分完去哪」:
| 批次線(現行主線) | Drive 線(既有資料) | |
|---|---|---|
| 檔案來源 | 使用者上傳進暫存批次,落在租戶自己的儲存後端(本機/MinIO/SeaweedFS/遠端 agent 皆可) | Google Drive 的 Evidences/ 資料夾 |
| 掛在誰身上 | 稽核輪次(round_id),每次新上傳開一個新批次 |
專案的 AP |
| 分完之後 | 歸檔進任務——檔案改綁對應的控制任務,在 job_evidences 真正寫入一筆,任務證據頁看得到 |
把檔案複製進 Drive 的 per-AO 資料夾,系統的任務證據表不寫入 |
| 前置要求 | 租戶已設定檔案儲存位置(未設定時整頁擋下並提示去系統設定) | 租戶 Drive CONNECTED + AP 已 init 資料夾 + Evidences 有檔案 |
| 定址 | run_uid(UUID),目標集吃 run 的 catalog_snapshot |
run_folder_id(Drive 資料夾 ID) |
落地版客戶沒有 Google Drive,批次線是讓分類功能對他們也能用的前提。Drive 線不再是新功能的落點,保留是為了讓既有分類結果仍打得開。
2.1 批次線的四步與狀態¶
畫面是四步流程(AutoClassifyBatch.vue):① 上傳證據 → ② AI 分類中 → ③ 確認分類 → ④ 歸檔完成;第③步嵌入的就是證據分類覆核頁。
批次狀態(compliance.evidence_batches.status):uploading → ready(按「完成上傳」)→ classifying(按「開始 AI 分類」)→ review(容器跑完)→ archived(按「歸檔進任務」);分類失敗落 failed,已上傳的檔都還在、重新分類不必重傳。
轉換規則的唯一真相是套件的 ALLOWED_TRANSITIONS(動作 → {來源狀態: 目標狀態}),查不到即非法轉換回 EC_409002。幾個不直觀但刻意的設計:
ready再加檔會退回uploading(要重按一次「完成上傳」)——批次的檔案清單是分類的輸入,加了檔就不再是先前那份。review可以再跑一次分類(換模型或門檻重判),也可以在審閱時剔掉不要的檔。archived → archived放行(重按歸檔冪等):擋掉第二次的話,「歸檔後才建出來的任務」永遠拿不到證據,而使用者看到的是一個無法補救的錯誤。已歸檔批次的按鈕字樣降級為「重新歸檔」,只補上次歸檔後才新建的任務。- 分類進行中封口(加檔/刪檔被擋回
EC_409003,前端顯示「分類進行中不能改檔」而不是泛用的狀態錯誤)。 - 心跳:執行緒每 60 秒蓋一次
job_heartbeat_at,BE 啟動時掃出逾時 30 分鐘的判失敗(failure_reason = heartbeat_timeout,前端據此顯示「可直接重跑」)。這是判「執行緒還活著嗎」不是「跑完了沒」,超大批次真跑三小時也會一路蓋心跳。
按「開始 AI 分類」前會先開一個設定視窗,三個欄位:
| 欄位 | 說明 |
|---|---|
| 信心門檻 | 低於這個信心的判斷留給人工確認(滑桿,0.50~1.00) |
| AI 模型 | 僅系統管理員可見(一般使用者不該也不需要挑模型)。平鋪一層列出可用型號,清單是動態算的——只列已設金鑰的供應商,沒設金鑰的家不出現也不提示。一把金鑰都沒設時下拉是空的、「開始分類」反灰並提示去系統設定填金鑰 |
| 思考深度 | 低/中/高三檔,預設中——控制模型花多少力氣推理。沒指定時的解析順序是「這一批指定的 → 分類設定的預設 → 系統預設(中)」 |
送出時型號與供應商要一起送:後端沒收到供應商會從碼表反查,反查不到才退預設那家——兩者都落空時選到的型號會被判成「不支援的分類模型」。
視窗上另有三個預估數字(耗時/用量/費用),用意是在「按下去之前」提供決策依據。
歸檔取的是審閱後的判定(run 的 state),且標了「不適用」或已刪除的檔一律不掛——審閱頁標這兩個旗標時不會一併清掉 placements,只看 placements 的話使用者標了「不適用」的檔還是會被掛上任務。歸檔回傳四個數字:掛進任務的檔數、新產生的證據筆數、原本就在任務底下所以略過的筆數、沒有對應任務的檔數。
清理(purge)只對已歸檔的批次開放,且已歸檔的檔永遠不在清理範圍內——那些檔背後有 job_evidences 指著同一個檔案 id,實刪後任務上的證據會變成打不開的死連結。
2.2 Drive 線(既有資料)¶
流程(FR-030):Drive Evidences/ 資料夾 → 觸發分類(manager)→ 容器 AI 逐檔分類 → run 資料夾 + _state.json → 覆核修正 → 報表 → 歸檔。
run 狀態(evidence_classification_runs.status):queued → processing → completed(成功)/ failed(容器 exit≠0);archived_files 旗標另記是否已把 placement 檔複製進 per-AO 資料夾(analyze-only 模式先不複製,覆核後手動歸檔)。
真相來源雙寫:placement 編輯狀態的真相是 Drive 上的 _state.json(覆核頁讀寫的就是它);evidence_classification_runs.state / report_original JSONB 是 DB 鏡像(供報表與跨頁查詢,_sync_run_state_to_db idempotent 同步)。報表以 report_original(AI 首次輸出,immutable)對照 state(User 修正後)計算。
2.3 兩條線共通的概念¶
分類單位是 per-檢查點 placement——一個檔案可以命中多個檢查點,命中幾個就在那幾個任務底下各掛一筆證據(不複製檔案,多個任務指向同一份檔)。兩條線的檢查點代號寫法不同:
| 代號形式 | 目標集(AI 可選的檢查點母體)從哪來 | |
|---|---|---|
| 批次線 | part_id + ao_letter(如 IA.L1-3.5.1_obj.1) |
run 的 catalog_snapshot——分類當下凍結的那一份,與這次判定必然對得齊 |
| Drive 線 | {ControlId}[{letter}](如 AC.L1-3.1.1[a]) |
living SSP 的 in-scope 控制集(見 專案規劃頁) |
目標集用凍結快照而不是即時查:控制集在分類跑完到使用者審閱之間可能被改動,拿即時的去對照會出現「AI 判到一個現在已經不存在的檢查點」。
哪些 AI 模型可選=該租戶已設定金鑰的供應商 × 系統支援的型號表取交集,由 GET /api/1.0/classification/available-models 動態算出,不寫死在畫面上。沒設定任何金鑰時回空清單並提示去系統設定填,比列出一堆選了才 401 的型號好。型號表是資料不是邏輯(支援新型號=加一列),實際可選清單隨金鑰設定與型號表變動——故本手冊不列型號名,要看當下有哪些請打該端點。金鑰維護見框架版本管理 §1.1。
3. 兩種「證據」概念(新人最易混淆,先分清)¶
系統中「證據」有兩種獨立但相關的身份,不是同一份資料:
| Job Evidence(任務佐證) | Classification Evidence(分類證據) | |
|---|---|---|
| 表 / 位置 | compliance.job_evidences(綁 job_execution_id) |
批次線:compliance.evidence_batch_files(暫存,未歸檔前)/ Drive 線:Evidences/[domain]/[control]/[ao]/ 資料夾內檔案 |
| 來源 | SYSTEM_UPLOAD(手動)/ DRIVE_SYNC(Drive 同步)/ DETECTION_TOOL(FR-056 檢測工具掃描報告,PDF)/ AI_CLASSIFIED(批次線歸檔寫入,帶 classification_run_id 可追溯) |
AI 分類放置或 User 手動複製 |
| 用途 | 任務執行的完成佐證(受稽方上傳) | AP 合規評估的框架相關檔案 |
| 涉及頁面 | 我的任務 | 本群分類覆核 / 報表 |
| 關聯 | 批次線歸檔會在此真正寫入一筆(source='AI_CLASSIFIED');Drive 線不寫 |
批次線歸檔後即成為左欄那筆;Drive 線分完仍留在 Drive |
批次線是這兩種身份唯一的接點:歸檔那一步把暫存批次的檔改綁控制任務,於是分類證據變成任務佐證(
source='AI_CLASSIFIED'+classification_run_id記得從哪一次分類來的)。Drive 線沒有這個接點——它分完只是把檔複製進 Drive 的 per-AO 資料夾,job_evidences一筆都不寫。除此之外兩者的交集只在「檔案存哪」——都由租戶的
STORAGE_CONFIG決定儲存後端(見 §4)。改 Drive 線邏輯不要誤動job_evidences,反之亦然。
4. 儲存後端與證據來源¶
本群管的是「證據檔案存哪、從哪來」的基礎建設:
| 面向 | 頁面 / 機制 | 說明 |
|---|---|---|
| 儲存後端切換 | 儲存設定(STORAGE_CONFIG system config,per-tenant) |
storage_type:local / minio / remote_agent / Drive;重用 jedi-file-upload 的 IUploadFileProvider adapter |
| 雲端來源 | 雲端整合(tenant_drive_integrations) |
Google Drive OAuth 連接、webhook 同步、資料夾對應(drive_folder_mappings,scope 含 EVIDENCES) |
| 客戶端落地 | 檔案 Agent 管理(remote_agents,FR-039) |
機敏證據不上雲、落地客戶自有設備;agent 以 device fingerprint 綁定、心跳回報 status |
背景同步:Drive 變更經 webhook → drive_sync_jobs 佇列非同步處理(詳見背景服務 spec)。分類前置要求:租戶 Drive CONNECTED + AP 已 init Drive 資料夾 + Evidences 有檔案。
5. 角色權限基調¶
角色是誰:
- manager(專案負責人)——觸發這一輪的 AI 證據分類。「身為 manager,我要對這次稽核的證據資料夾觸發 AI 分類,把檔案自動配對到對應控制項。」
- 稽核參與者(v1 簡化:任何登入者)——覆核 AI 分類結果、修正誤判、查看分類報表。「身為稽核參與者,我要檢查 AI 分類的檔案是否放對控制項,把錯的改回來。」
- 租戶 admin——設定證據存哪(本地 / MinIO / Drive)、管理雲端整合與客戶端檔案 Agent。「身為租戶 admin,我要設定這個租戶的證據要存在哪裡、要不要接 Google Drive。」
本群橫跨專案層(分類)與系統/租戶層(整合 / Agent / 儲存)兩種權限基礎:
| 動作 | 誰能做 | 檢查 |
|---|---|---|
| 批次的寫入類動作(建批次 / 上傳 / 刪檔 / 開始分類 / 歸檔 / 清理) | 專案 manager | service 層 is_project_manager(),否則 EC_403005(專用碼:泛用的「僅可觸發自動分類」文案對不上使用者當下在做的事) |
| 看批次清單與流程頁 | 專案參與者 | service 層 is_project_participant(),否則 EC_403002;auditor 進得去但按鈕整組隱藏並顯示一行說明(反灰會讓人一直想「怎樣才能按」) |
| AI 分類設定(profile)CRUD | 租戶管理員(跨租戶由 RLS 擋) | service 層;ROOT 出廠那份對業務租戶唯讀,改它回 EC_403004 |
| AI 供應商金鑰 | ROOT 平台管理員(第一版不開放客戶自填) | 系統設定頁另鎖,讀取時遮成 is_set 旗標、不回明文 |
| 觸發 AI 分類(Drive 線) | 專案 manager | service 層 project_participant.role == "manager",否則 EC_403001 |
| 覆核 / 編輯 placement / 存 / 歸檔 | v1 簡化:僅 JWT(未檢專案角色,實驗階段) | 見 evidence-classification-review §3 |
| 檢視報表 | 同覆核 | — |
| 雲端整合 / 儲存設定 / Agent 管理 | 租戶 admin(系統管理層) | 各頁 capability / route 層 |
本群 error code 前綴是
EC_(evidence_classification 模組),不是GRC_——命名規則同(EC_<HTTP狀態碼><序號>),檔案在common/code/evidence_classification_error_code.py。查錯別在grc_error_code.py找。
6. 核心資料模型¶
| 表 | schema | 角色 |
|---|---|---|
evidence_batches |
compliance | 批次線的一批作業(掛 round_id;status 六態、provider / model / confidence_threshold / profile_id 記這批用什麼跑、job_heartbeat_at 心跳、四個計數欄與歸檔/清理的時間與操作者) |
evidence_batch_files |
compliance | 批次內的暫存檔(status:pending / classified / no_task / archived / removed;archived 的列不可從批次這側實刪,背後有 job_evidences 指著同一個檔) |
classification_profiles |
compliance | AI 分類設定(per 租戶 × 框架版本;persona / guidance / evidence_hints + 供應商與模型預設值;tenant_id=1 是 ROOT 出廠通用設定。軟參照框架版本、刻意不建 FK——那張表屬另一支插件,插件互不相依) |
evidence_classification_runs |
compliance | 分類 run 記錄(兩條線共用;state / report_original / catalog_snapshot JSONB。批次線以 run_uid 定址,Drive 線以 run_folder_id 自然鍵並鏡像 Drive run folder) |
evidence_classification_ground_truth |
compliance | 正解基準(per-tenant × framework;mapping JSONB = {file_name:[ao_id]};誤判報表 CANON 來源) |
tenant_drive_integrations |
public | 租戶 Google Drive OAuth 連接(token / webhook / 同步狀態) |
drive_folder_mappings |
public | Drive 資料夾 ↔ 系統實體對應(scope_type 含 PROJECT/AP/EVIDENCES…) |
drive_sync_jobs |
public | Drive 同步任務佇列(webhook 驅動、非同步) |
remote_agents |
compliance | FR-039 客戶端檔案 Agent registry(device fingerprint / status / 心跳;capabilities 欄位 FR-056 起兼作檢測工具掃描能力清單) |
remote_agent_enroll_tokens |
compliance | Agent 綁定 enrollment token(sha256 hash) |
job_evidences |
compliance | 任務佐證(另一種證據,見 §3;儲存後端由 STORAGE_CONFIG 決定;source 含 DETECTION_TOOL 與 AI_CLASSIFIED,後者另有 classification_run_id 軟參照回分類 run) |
detection_executions |
compliance | FR-056 檢測工具執行歷史(狀態/摘要統計/報告與證據參照,見 任務執行抽屜、檢測工具管理) |
agent_tasks |
compliance | FR-056 Agent 派工單(掃描指令 + 加密憑證隨派下發,狀態機 pending→dispatched→running→succeeded/failed/cancelled) |
7. 本群共用的已知坑¶
- 兩種「證據」別混:
job_evidences(任務佐證)vs 分類證據,是不同資料;批次線歸檔是唯一把後者變成前者的路徑(見 §3) - 真相在哪要看是哪條線:Drive 線的 placement 真相是 Drive 上的
_state.json,DBstate是鏡像,直接改 DB 會與 Drive 脫鉤;批次線沒有 Drive,run 的state本身就是真相 2a. 批次線的目標集是凍結快照:審閱頁對照的檢查點來自 run 的catalog_snapshot,不是即時查控制集。快照缺part_id的項目會被歸檔略過(拿它去查任務只會全部落到「無對應任務」);EC_412007即「此 run 無目標集快照,請重新分類」 2b. 清理永遠不動已歸檔的檔:archived不在可清理範圍內且不該加進去——那些檔背後有job_evidences指著同一個檔案 id,實刪後任務上的證據會變成打不開的死連結 - 報表即時計算不存確認狀態:validation / adjudication 每次開都重算(對照
report_originalimmutable ×statecurrent),沒有「已確認」持久欄位 - error code 前綴 EC_ 不是 GRC_,且定義在套件裡不在主專案:查錯去套件
jedi_evidence_classification/common/error_code.py(EvidenceClassificationErrorCode),主專案common/code/下沒有這支 - 框架知識不再寫死、批次線不需要 Drive:要換框架改的是
classification_profiles這筆資料(AI 角色 / 指引 / 證據提示),不是改程式碼;四層退路是「租戶×框架版本 → ROOT×框架版本 → 租戶通用 → ROOT 通用」,全落空才用內建最小版(內建那份刻意不含任何框架名——寫死 CMMC 等於把框架名焊回分類引擎) - remote agent demo 邊界:FR-039 demo 階段落地不加密、無認證金鑰、無網路可達性檢查(見 FR-039 design)
- 兩條線的覆核權限不同:批次線的寫入類動作鎖專案 manager、看的人要是專案參與者(auditor 唯讀);Drive 線的覆核 / 存 / 歸檔仍僅需 JWT(實驗階段遺留,非資安定案)