證據分類覆核(Evidence Classification Review)
功能群:證據管理|分類生命週期、兩種證據概念、EC_ error code、核心資料模型先讀 功能群總覽
事實基準:2026-07-05 從 FE / BE code 掃出(FR-030 AI 證據自動分類 v1);state JSON 形狀對照
app/evidence_classification/service/evidence_classification_service.py,UI 對照EvidenceClassificationReview.vue全檔
1. 功能描述
證據分類覆核頁是 AI
證據自動分類的人工覆核工作區:一個分類
run(run_folder_id)跑完後,逐檔檢視 AI 建議的
placement(檔案 → AO 的對應),手動新增 / 移除 placement、標記
N/A、刪檔,最後儲存(同步回 Drive
_state.json)並在需要時歸檔(把 placement 檔複製進 per-AO
資料夾)。編輯的真相是 Drive 上的
_state.json(見 _overview
§2)。
主要使用者:觸發分類的專案 manager(覆核 / 存 / 歸檔 v1 僅 JWT、未鎖專案角色,見 §3)。
角色速覽(完整見 _overview §5):
| 角色 | 一句話 |
|---|---|
| manager | 專案經理 — 觸發分類(上游)並覆核修正 |
| (覆核者) | v1 覆核 / 存 / 歸檔僅需 JWT(未鎖專案角色,實驗階段) |
1.1 功能總覽(本頁全部功能)
| # | 功能 | 說明 | 位置 | 詳述 |
|---|---|---|---|---|
| 1 | 分類統計列 | 總檔數 / 已分類數+% / 未分類(可點篩選)/ placement 總數 / 覆蓋度(covered_aos/總 AO) | Header 下方 ClassificationStatsRow |
§10 |
| 2 | 未歸檔警示 + 立即歸檔 | archive_files=false(analyze-only)時顯示警示,可「立即歸檔」把
placement 檔複製進 Drive |
警示條 | UC-EC-02 |
| 3 | 篩選列 | 未分類收件匣 toggle / 搜尋(檔名)/ 領域下拉 / 狀態(all/unclassified/single/multi/heavy/na)/ 最低信心 slider / 重設 | ClassificationFilterBar |
§5 |
| 4 | 檔案清單(左欄) | 虛擬捲動表:檔名(+ N/A / 未分類 tag、AO 數)/ 信心(迷你進度條,色分 tier)/ placement 數;可排序 | ClassificationFileList(34%) |
§5 |
| 5 | 檔案詳情(右欄) | 選中檔的 header(Drive ID / AO 數 / placement 數)+ 前後鍵導覽(j/k);三態身:N/A / 未分類 / 已分類 | ClassificationFileDetail(66%) |
UC-EC-01 |
| 6 | placement 卡 | 已放置:領域→控制項→AO 麵包屑 + 信心 / MANUAL 徽章 + reasoning + 移除 | PlacementCard |
UC-EC-01 |
| 7 | AI 候選卡 | 未放置的 AI 建議(≥ minConf):麵包屑 + 信心 + reasoning +「加入」 | CandidateCard |
UC-EC-01 |
| 8 | 加入 AO(AOPickerDialog) | 從全 AO 清單勾選加/減 placement(勾=保留、取消=移除、新勾=新增) | 存底列「Add AO」 | UC-EC-01 |
| 9 | 標記 N/A / 復原 | 整檔標為不適用(不需分類)/ 復原 | 存底列 / N/A 態「Undo」 | UC-EC-01 |
| 10 | 刪除檔案 | 把檔案移出證據池(is_deleted) |
存底列「Delete File」 | UC-EC-01 |
| 11 | 儲存 / 捨棄 | 儲存 diff 回 Drive(copy/trash)+ 鏡像 DB;捨棄重載 | 存底列(未存變更 badge) | UC-EC-01 |
| 12 | 檔案預覽 | 開 Drive 檔預覽(docx/xlsx/pptx/pdf/text/image,<50MB) | 清單 / 詳情預覽鈕 → EvidenceFilePreviewDialog |
§6 |
| 13 | 開 Drive 資料夾 / 報表捷徑 | 開 run 資料夾;DEV_MODE 顯示驗證 / 誤判報表捷徑 | Header 動作鈕 | 驗證 / 誤判 |
| 14 | 重跑分類 | 返回上頁重新觸發(本頁不觸發,router.back()) |
Header | §12 |
UC(§2)只展開 1(逐檔覆核與儲存)、2(歸檔)這些核心操作路徑;統計 / 篩選 / 預覽是輔助檢視。觸發分類本身不在本頁(在上游專案 / AP 頁,見 §12)。
2. Use Case
角色速覽(完整見 _overview §5):
| 角色 | 一句話 |
|---|---|
| manager | 專案經理 — 觸發分類(上游)並覆核修正 |
| (覆核者) | v1 覆核 / 存 / 歸檔僅需 JWT(未鎖專案角色,實驗階段) |
流程圖視覺慣例:菱形 = 判斷、橘底 = 例外/擋下、紅框 = 錯誤(標 error code)、綠框 = 成功終點、虛線 = 可選路徑。
UC-EC-01 逐檔覆核分類並儲存
| 項目 | 內容 |
|---|---|
| 角色 | 覆核者(v1 JWT) |
| 前置條件 | 分類 run 已 completed、_state.json 存在 |
| 產出 / 後置條件 | placement 增減 / N/A / 刪檔在記憶體 → 儲存時 diff → Drive copy/trash
+ overwrite _state.json + DB 鏡像同步 |
UC-EC-02 歸檔 run(analyze-only → 落檔)
| 項目 | 內容 |
|---|---|
| 角色 | 覆核者(v1 JWT) |
| 前置條件 | run archive_files=false(analyze-only,placement
檔尚未複製) |
| 產出 / 後置條件 | 無 placement_drive_id 的 placement copy 進 per-AO
資料夾、填回 id;archive_files=true +
archived_at |
3. 權限矩陣
角色基調見 _overview §5。本頁檢查點:
| 操作 | FE 判定 | BE 強制 | BE 檢查位置 |
|---|---|---|---|
| 觸發分類(上游) | 專案 manager | project_participant.role == "manager" →
EC_403001 |
app/evidence_classification/service/evidence_classification_service.py:99-150 |
| 讀 state / 存 / 歸檔 / 預覽 | 能到 URL 即可(無頁內角色判定) | v1 僅
@jwt_required(),未檢專案角色 |
api/evidence_classification/routes/evidence_classification_route.py |
⚠️ v1 覆核權限未鎖(收進 §12):觸發分類鎖 manager,但覆核 / 存 / 歸檔 / 預覽目前只驗 JWT——實驗階段(FR-030 v1 demo-ready)可接受,非資安定案。日後正式化須補專案角色檢查。
4. 狀態機與前置條件
分類 run 狀態機見 _overview §2。本頁相關 gate:
| 條件 | 效果 | 出處 |
|---|---|---|
run status = completed |
才有可覆核的 _state.json |
evidence_classification_service(run state 讀取) |
archive_files = false |
顯示未歸檔警示 + 立即歸檔鈕;placement
placement_drive_id 為 null |
ClassificationFileDetail / metadata |
| 未存變更 | 存 / 捨棄鈕啟用,pending 數 badge(原始 snapshot vs 當前 placement diff) | useEvidenceClassification.hasUnsavedChanges |
| 檔案三態 | placements 空且非 N/A → 未分類;N/A → 不適用;有 placements → 已分類(single/multi/heavy = 1/2–4/≥5) | FE 分類邏輯 |
5. UI 設計
📸 實際畫面截圖待補(一律亮色模式拍攝):以 playwright 對 STG 擷取,預計補以下四張到
assets/img/: ① 整頁(統計列 + 篩選 + 左檔案清單 + 右詳情)ec-review-overview.png② 檔案詳情 — 已分類(placement 卡 + AI 候選卡)ec-review-classified.png③ 未分類 + AI 候選(低於門檻警示)ec-review-unclassified.png④ AOPickerDialog + 未歸檔警示ec-review-aopicker.png
版面骨架與區塊職責(2 欄 Splitter,狀態存 localStorage
ec-review-splitter;彩色區塊可點跳本頁小節錨點,API
僅標代表性):
狀態呈現:信心 tier 色(高 ≥0.85 綠 / 中 ≥0.70 橘 / 低 紅);未分類 / N/A 列有底色標;存 / 捨棄 per-按鈕狀態;鍵盤 j/k / 上下鍵切檔。無 socket,覆核為前端記憶體操作、存時才寫 Drive。
6. API 規格
Envelope:成功 {"status": true, "data": …}、失敗
{"status": false, "error_code": "EC_…", "msg": "…"}。
6.1 總清單(本頁呼叫的全部 endpoint)
| 分類 | Method + Path | 說明 | 完整規格 |
|---|---|---|---|
| 載入 | GET /classification-run/{run_folder_id}/state |
讀 _state.json(metadata + files + placements) |
§6.2 |
| 儲存 | PUT /classification-run/{run_folder_id}/state |
存編輯(BE diff → Drive copy/trash → 覆寫 + DB 鏡像) | §6.2 |
| 歸檔 | POST /classification-run/{run_folder_id}/archive |
analyze-only run 落檔 | §6.2 |
| 預覽 | GET
/classification-run/{run_folder_id}/file/{file_drive_id}/preview |
Drive 檔預覽 | GAI-SD-02 |
| 報表 | GET
.../report/validation・.../report/adjudication |
DEV 捷徑(下游頁) | 驗證報表 / 誤判報表 |
| 上游(非本頁) | POST
/project/{project_uid}/ap/{ap_uid}/classify-evidence、GET
.../classify-evidence/jobs |
觸發分類 / job 清單(在專案/AP 頁) | §12 |
6.2 分類 run state 類
[GET] /classification-run/{run_folder_id}/state
Response data:{metadata, files[]}——
metadata:
| 欄位 | 型別 | 說明 |
|---|---|---|
| drive_run_folder_id | string | Drive run 資料夾 id |
| drive_run_folder_name | string | Drive run 資料夾名稱 |
| framework_id | string | 合規框架(v1 = cmmc-l1) |
| confidence_threshold | number | 信心門檻 |
| model | string | 使用模型 |
| archive_files | bool | 是否已複製 placement 檔進 per-AO 資料夾 |
| token_usage | object | token
用量:{total_tokens, cache_read_input_tokens, estimated_cost_usd} |
| last_edited_at | string | 最後編輯時間 |
| last_edited_by_user_id | int | 最後編輯者 |
| archived_at | string | 歸檔時間(歸檔後才有) |
| archived_by_user_id | int | 歸檔者(歸檔後才有) |
files[](每檔):
| 欄位 | 型別 | 說明 |
|---|---|---|
| file_drive_id / file_name | string | Drive 檔識別 / 名稱 |
| is_na / is_deleted | bool | 標記不適用 / 移出證據池 |
| matches[] | array | AI
候選:{ao_id(如 AC.L1-3.1.1[a]), confidence(0–1), reasoning} |
| placements[] | array | 確定放置:{ao_id, placement_drive_id(歸檔後才有), source(ai/manual), added_at?} |
出處:evidence_classification_service.py::get_state(讀
Drive _state.json)
[PUT] /classification-run/{run_folder_id}/state
Request:同 GET 的 {metadata, files[]}
完整結構(前端整包送回)。BE diff old vs new
placements:新增 → copy_file 進 per-AO 資料夾填
placement_drive_id;移除 → trash_file;蓋章
last_edited_*;覆寫
_state.json;_sync_run_state_to_db(idempotent)。Response
data:{operations_applied, drive_copied, drive_trashed, errors[]}。出處:evidence_classification_service.py::put_state
[POST] /classification-run/{run_folder_id}/archive
無 body。對每個無 placement_drive_id 的 placement copy
進 per-AO 資料夾;設
archive_files=true、archived_at。Response
data:{drive_copied, already_archived, errors[]}。出處:evidence_classification_service.py::archive_run
7. 前端檔案地圖(compliance-manager-fe/)
| 檔案 | 角色 |
|---|---|
src/views/evidence-classification/EvidenceClassificationReview.vue |
主檢視(2 欄 Splitter、統計、篩選、存 / 歸檔) |
src/views/evidence-classification/components/ClassificationStatsRow.vue |
統計列 |
.../components/ClassificationFilterBar.vue |
篩選列 |
.../components/ClassificationFileList.vue |
左檔案清單(虛擬捲動) |
.../components/ClassificationFileDetail.vue |
右詳情(三態) |
.../components/PlacementCard.vue /
CandidateCard.vue / AOPickerDialog.vue |
placement / 候選 / 加 AO |
.../components/EvidenceFilePreviewDialog.vue |
Drive 檔預覽 |
src/service/EvidenceClassificationService.js |
API 包裝(getState / putState / archiveRun / 報表) |
src/composables/useEvidenceClassification.js |
state 管理(load / add/remove placement / markNa / save / hasUnsavedChanges) |
src/config/router/index.js:859-862 |
route evidence-classification-review |
src/config/locales/i18n/{zh-tw,en}/evidence-classification.json |
i18n(namespace lang.evidence_classification.*) |
8. 後端檔案地圖(本頁核心鏈路)
| 鏈路 | Route | App Service | 底層 |
|---|---|---|---|
| 讀 / 存 state | api/evidence_classification/routes/evidence_classification_route.py::ClassificationRunStateRoute |
app/evidence_classification/service/evidence_classification_service.py::get_state
/ put_state(diff + Drive ops + DB 鏡像) |
EvidenceDriveOps(copy/trash/update_json)+
ClassificationRunDomainService.update_state |
| 歸檔 | 同檔 ClassificationRunArchiveRoute |
archive_run |
EvidenceDriveOps |
| 觸發分類(上游) | 同檔(classify-evidence route) | trigger_classify(_check manager)→
ClassifierContainerRunner(Docker)→ Drive + DB
persist |
evidence_classification_runs repo |
DDD 提醒:本模組 route → app service → domain
service / repo(ClassificationRunDomainService)+ infra 的
EvidenceDriveOps(Drive 操作限縮在 infra)。error code 前綴
EC_(common/code/evidence_classification_error_code.py)。
9. DB
9.1 資料表總清單(本頁讀寫的全部表)
| 表 | 讀/寫 | 說明 | 欄位詳述 |
|---|---|---|---|
| compliance.evidence_classification_runs | 讀/寫(鏡像同步 state) | 分類 run 記錄;真相在 Drive _state.json,本表
state/report_original JSONB 為鏡像 |
§9.3 |
(Drive _state.json /
_report-original.json) |
讀/寫 | placement 編輯的真相來源(非 DB,見 _overview §2) | — |
本頁不直接寫
ground_truth(那是誤判報表 CANON 匯入);ground truth 表見 _overview §6 與 驗證報表。
9.3 核心表欄位(取自 DEV DB dump)
compliance.evidence_classification_runs — 證據分類 run 結果
| 欄位 | 型別 | 說明 |
|---|---|---|
| run_folder_id | varchar(128) | Drive run folder id(自然鍵) = 頁面 URL 的 runFolderId |
| tenant_id / project_uid / ap_uid | int / varchar | 租戶 / 專案 / AP |
| framework_id | varchar(64) | 合規框架(v1 = cmmc-l1) |
| model / confidence_threshold | varchar / numeric(4,2) | 使用模型 / 信心門檻 |
| status | varchar(32) | queued / processing / completed / failed |
| archive_files | boolean | 是否已複製 placement 檔進 per-AO 資料夾 |
| input_file_count / classified_count | int | 輸入 / 已分類檔數 |
| estimated_cost_usd | numeric(10,4) | 估算費用 |
| state | jsonb | _state.json 鏡像(User 修正後) |
| report_original | jsonb | _report-original.json 鏡像(AI
首次輸出,immutable;報表對照基準) |
| container_log | text | 容器日誌 |
| triggered_at / completed_at / last_edited_at / archived_at | timestamptz | 生命週期時間 |
| triggered_by / last_edited_by / archived_by _user_id | int | 各動作使用者 |
10. 頁面邏輯與資料對應
載入時序:
關鍵欄位對應(畫面 ↔︎ API):
| 畫面元素 | FE state | API 欄位 |
|---|---|---|
| 統計列 | computed | files 聚合(classified / unclassified / placements / coverage) |
| 信心進度條 | match.confidence |
matches[].confidence(tier 前端算) |
| placement 卡 | file.placements |
placements[](source=manual → MANUAL 徽章) |
| AI 候選卡 | 未放置的 matches ≥ minConf |
matches[] \ placements[] |
| 未存 badge | pendingCount(原始 vs 當前 diff) |
— |
| 未歸檔警示 | notArchived(metadata.archive_files=false) |
metadata.archive_files |
儲存流程:前端整包 PUT state → BE diff
→ Drive copy/trash → 覆寫 _state.json → DB 鏡像;捨棄 =
重載。歸檔另走 POST archive。
錯誤對應:BE EC_ envelope → toast;常見
EC_403001(觸發非
manager)、EC_404003(_state.json
不存在)、EC_404008(run 未存 DB
無法產報表)、EC_500003(Drive
檔操作失敗)、EC_500004(state JSON 解析失敗)。
11. 背景行為與外部依賴
| 類型 | 內容 |
|---|---|
| AI 分類 | 觸發後 Docker 容器 cmmc-classifier 逐檔呼 Claude
API(prompt caching);產 _state.json +
_report-original.json(背景,非本頁即時) |
| Drive | 覆核存檔 = Drive copy/trash + 覆寫
JSON(EvidenceDriveOps);歸檔複製 placement 檔進 per-AO
三層資料夾 |
| Socket | 本頁無 socket;覆核為前端記憶體操作、存時才寫 |
| jedi-* 套件 | Drive 操作 / classifier 容器(模組自有
infra);jedi-auth(JWT) |
| 系統參數 | 分類模型允許集、信心門檻預設 0.80;DEV_MODE 顯示報表捷徑 |
12. 邊界情況與已知坑
- 真相在 Drive
_state.json不是 DB:DBstate是鏡像;直接改 DB 會與 Drive 脫鉤(見 _overview §7 坑 2) - 覆核權限 v1 未鎖:觸發鎖 manager,覆核 / 存 / 歸檔僅 JWT(§3)
- 觸發分類不在本頁:本頁「重跑分類」是
router.back();實際觸發POST /project/{uid}/ap/{apUid}/classify-evidence在上游專案 / AP 頁(單 project 單 AP、無並行,同 project 一次一 job) - analyze-only 模式 placement_drive_id 為 null:未歸檔前 placement 只在 JSON、檔案未複製;歸檔後才落檔
- 儲存是整包 diff 不是增量:前端送完整 files 陣列,BE 自行 diff;多人同時覆核同一 run 會互蓋(無鎖)
- 限 CMMC L1 + Drive(v1):非 CMMC L1 框架 / 非 Drive 來源 v1 不支援(見 _overview §7 坑 5)
- 報表即時算、無確認狀態:驗證 / 誤判報表每次開重算(見 驗證報表 / 誤判報表)
- 預覽限檔型 / 大小:docx/xlsx/pptx/pdf/text/image、<50MB
13. 開發與驗證
- 跑起來:BE
python main_socketio.py(port 8000,log 在log/app.log);FE 在compliance-manager-fe/起 Vite dev server。BE 改 service code 後必須重啟(無 hot reload) - 測試帳號:dev 環境專案 manager 帳號(密碼見
.env/ 部署文件) - 導航路徑:登入 → 專案 / AP 觸發分類 → 分類 job 完成
→ 進覆核頁(
.../classify-evidence/run/{runFolderId}) - 前置資料:租戶已連 Google
Drive(
CONNECTED)+ AP 已 init Drive 資料夾 + Evidences 有檔案 + 已跑過一個 completed 分類 run - E2E:
compliance-manager-test/repo(Cucumber + Playwright);以證據分類/classification搜尋 - 相關文件:FR-030(AI
證據分類,
docs/features/FR-030-2605-auto-evidence-classification/)、FR-031(報表);下游報表見 驗證報表 與 誤判報表;DB / API 全量見 GAI-SD-02/03