版本:v1.2.1(2026-05-28)— 實驗階段(experimental) 狀態:dev demo-ready,正式環境不建議啟用 相關文件:
design.md— 設計決策與技術 trade-offimplementation-plan.md— 階段性實作計畫../../api/evidence-classification/api-spec.md— API 端點規格../../changelog/2026-05-28-*— 變更紀錄本文目的:作為此功能的「行為規格 source of truth」,涵蓋功能範圍、使用流程、資料模型、權限、限制。供開發 / QA / 文件 / 未來維護參考。
合規稽核準備階段,user 需把幾百份證據檔(政策文件、稽核 log、權限清單等)對照到合規框架的每個評估項目(Assessment Objective, AO)資料夾。以 CMMC Level 1 為例:6 個 domain、17 個 control、59 個 AO,134 份證據檔人工整理需 1-3 天。
使用 LLM(Claude Sonnet 4.6)分析每份檔案的內容與檔名,自動對應到一個或多個 AO,並把檔案 copy 到 Drive 上對應的三層分類資料夾。User 透過審閱介面逐檔複核與調整。
In scope:
Out of scope(列為 follow-up):
| 角色 | 觸發分類 | 編輯結果 | 儲存變更 | 查看結果 |
|---|---|---|---|---|
| Project Manager | ✓ | ✓ | ✓ | ✓ |
| Project Auditor / 一般成員 | ✗ | ✗ | ✗ | ✓(read-only,v1 未實作) |
| Tenant Admin | 視是否同時為 PM | 視是否同時為 PM | 視是否同時為 PM | ✓ |
| 跨 tenant Super Admin | 未支援(v1) | — | — | — |
權限檢查點:
POST .../classify-evidence):service 層查 project_participant,role == "manager" 才放行,否則 EC_403001 ForbiddenPUT .../state):v1 簡化,僅檢 JWT 不檢 project 角色(實驗階段可接受;正式版要補)GET .../file/.../preview):v1 同上tenant_integrations.status = 'CONNECTED')drive_folder_mappings 有對應 project / AP / Evidences mapping)
Evidences/ 子資料夾並寫 EVIDENCES scope mappingANTHROPIC_API_KEYdocker groupcmmc-classifier:latest image(scripts/evidence/classify/docker/)/project/projects/<uid>/ap/<ap_uid>/)drive_ready(透過 GET .../classify-evidence/jobs?ap_uid=<...>)
POST .../classify-evidence,回傳 { job_uid, status: queued, input_file_count, estimated_minutes }⚠ STG demo 期間例外:從 commit c6e9de1 起 drive_ready gate 暫時拿掉(ProjectAuditorOverview.vue v-if 沒檢查 driveReady),按鈕一律顯示。原因:STG 部署期間既有專案的 EVIDENCES mapping 尚未 backfill 完成。STG 部署到位後要加回(見 §9 限制 / §12 roadmap)。
cmmc-classifier:latest,傳入 tenant OAuth 憑證 + AP Evidences folder ID + framework catalogmatches 陣列(候選 AOs + confidence + reasoning)+ placements 陣列(confidence >= threshold 的 AOs)_state.json + _report-original.json 到 host /tmp/cm-jobs/<job_uid>/自動分類_YYYY-MM-DD_HH-MM/ run folder(Evidences/ 內)<run_folder>/[domain]/[control]/[ao]/ 三層資料夾_state.json + _report-original.json 到 run folderJobRegistry status = completed/evidence-classification-review/...)_state.json 顯示:
[0, 1],預設 0.80(原本 [0.5, 1],改成 0 起以利顯示 AI 沒抓到的 0 分檔)PUT .../state → BE diff 舊新 state → 跑 Drive copy / trash → 覆寫 _state.jsonGET .../file/<file_drive_id>/preview:
application/pdf → iframe(browser 原生 PDF viewer)image/* → <img>text/* / json / xml / yaml → <pre> 純文字JobRegistry 重啟後清空GET .../classify-evidence/jobs?ap_uid=<...>:
_derive_evidence_folder_id(tenant_id, ap_uid) 找該 AP 的 Evidences folder自動分類_* 命名規則的 subfolderstatus: completed、run_folder_id、started_at / completed_at(folder modifiedTime)run_folder_id,registry 紀錄優先JobRegistry(app/evidence_classification/service/job_registry.py):
{
"<job_uid>": {
"job_uid": str (UUID4),
"project_uid": str,
"project_id": int,
"tenant_id": int,
"evidence_folder_id": str, # Drive folder ID
"framework_id": str, # "cmmc-l1"
"confidence_threshold": float,
"status": "queued" | "running" | "completed" | "failed",
"started_at": ISO datetime,
"completed_at": ISO datetime | None,
"run_folder_id": str | None,
"run_folder_name": str | None, # "自動分類_2026-05-28_09-26"
"input_file_count": int | None,
"classified_count": int | None,
"started_by_user_id": int,
"error": str | None,
}
}compliance.drive_folder_mappings — 新增 EVIDENCES scope(本期 migration):
scope_type scope_uid parent_drive_folder_id drive_folder_id 說明
EVIDENCES AP.uid AP folder.id Drive folder.id AI 證據池
ARCHIVE AP.uid AP folder.id Drive folder.id (既有)
... ... ... ... (其他 scope)
無其他 DB schema 變動。
_state.json schema){
"metadata": {
"framework_id": "cmmc-l1",
"confidence_threshold": 0.80,
"model": "claude-sonnet-4-6",
"triggered_at": "ISO datetime",
"completed_at": "ISO datetime",
"drive_run_folder_id": "...",
"drive_run_folder_name": "自動分類_..."
},
"files": [
{
"file_drive_id": "...",
"file_name": "...",
"is_na": false,
"is_deleted": false,
"matches": [
{ "ao_id": "AC.L1-3.1.1[c]", "confidence": 0.97, "reasoning": "..." }
],
"placements": [
{ "ao_id": "AC.L1-3.1.1[c]", "placement_drive_id": "...",
"source": "ai" | "manual", "added_at": "ISO datetime" }
]
}
]
}GuidantAI/
└── <Project>/
└── <AP>/
├── Evidences/ ← 證據池(user 丟檔處)
│ ├── policy-doc.docx
│ ├── access-log.csv
│ ├── ...
│ ├── 自動分類_2026-05-28_09-26/ ← run folder 1
│ │ ├── _state.json
│ │ ├── _report-original.json
│ │ ├── [AC] Access Control/
│ │ │ ├── [AC.L1-3.1.1] Authorized Access Control/
│ │ │ │ ├── [a] authorized users are identified/
│ │ │ │ │ └── policy-doc.docx ← copy from Evidences
│ │ │ │ ├── [b] processes acting .../
│ │ │ │ └── ...
│ │ │ └── ...
│ │ ├── [IA] Identification and Authentication/
│ │ └── ...
│ └── 自動分類_2026-05-28_14-30/ ← run folder 2 (re-run)
├── _Archive/ ← (既有,軟刪除堆積區)
└── [AC] / [IA] / ... ← (既有,控制項分類資料夾,給人工配對用)
完整定義見 docs/api/evidence-classification/api-spec.md。
| Method | Path | 用途 |
|---|---|---|
| POST | /api/1.0/project/<project_uid>/ap/<ap_uid>/classify-evidence |
觸發分類 |
| GET | /api/1.0/project/<project_uid>/classify-evidence/jobs?ap_uid=<...> |
列 jobs + drive_ready flag |
| GET | /api/1.0/project/<project_uid>/classify-evidence/jobs/<job_uid> |
單 job 狀態(polling 用) |
| GET | /api/1.0/classification-run/<run_folder_id>/state |
讀 _state.json |
| PUT | /api/1.0/classification-run/<run_folder_id>/state |
儲存編輯後 state |
| GET | /api/1.0/classification-run/<run_folder_id>/file/<file_drive_id>/preview |
預覽證據檔(office→pdf) |
完整見 common/code/evidence_classification_error_code.py。
| Code | HTTP | 說明 |
|---|---|---|
| EC_403001 | 403 | 僅專案管理者可觸發 |
| EC_404001 | 404 | 專案不存在 |
| EC_404002 | 404 | Run folder 不存在 |
| EC_404003 | 404 | _state.json 不存在 |
| EC_404004 | 404 | Job 不存在 |
| EC_404005 | 404 | Evidences 資料夾不存在 / 無法存取 |
| EC_404006 | 404 | AP 尚未與 Drive 連結 |
| EC_404007 | 404 | AP 資料夾下找不到 Evidences 子資料夾 |
| EC_409001 | 409 | Job 已在執行(同 project 限一個 active) |
| EC_412001 | 412 | Tenant 未連 Drive |
| EC_412002 | 412 | Evidences 資料夾無檔案 |
| EC_412003 | 412 | Catalog 建立失敗 |
| EC_500001 | 500 | Container 執行失敗 |
| EC_500002 | 500 | Container 逾時 |
| EC_500003 | 500 | Drive ops 失敗 |
| EC_500004 | 500 | _state.json 解析失敗 |
| 項目 | 目標 | 實測(134 檔) |
|---|---|---|
| AI 分類 latency | < 15 分鐘 | ~10 分鐘 |
| BE Drive 收尾 | < 20 分鐘 | ~17 分鐘(270+ copy 操作) |
| 預覽 — text / pdf / image | < 3 秒 | 通常 < 1 秒 |
| 預覽 — docx 轉 PDF | < 10 秒 | 1-3 秒(LibreOffice 啟動成本) |
| Polling 間隔 | 5 秒 | 5 秒 |
failed + 紀錄 error,user 可重觸發placement.copy_error 欄位,其他 placement 繼續處理@jwt_required)drive_folder_mappings / tenant_integrations 都吃 RLS,跨 tenant 隔離由 PG 保證| 項目 | 影響 | 解法 / Workaround |
|---|---|---|
JobRegistry 是 in-memory |
BE 重啟後跑中 job 丟失 | 完成的可 Drive scan 復原(list_jobs 帶 ap_uid 時 BE 掃 Evidences folder 自動 reconstruct);跑中的需重觸發 |
drive_ready gate 暫時拿掉 |
未連 Drive 的專案也顯示「自動分類證據」按鈕,點下去才 toast | STG 部署 + 既有 project 重跑 init folders 補 EVIDENCES mapping 後,把 v-if 加回 && ecJobs.driveReady.value(commit c6e9de1 的反向) |
| run folder 命名時區 | UTC 跟 FE 本地時間差 8h | v1.2.1 b7fa0e9f 起硬綁 Asia/Taipei;舊紀錄留原樣 |
| 同 active job 顯示兩條歷史 | (已修)BE 建好 run folder 才把 run_folder_id 寫 registry → 中間期 Drive scan recovery dedup 比不到 | v1.2.1 543b2e1d 改為 create_folder 後立刻 update registry |
| Framework 硬綁 cmmc-l1 | 其他框架不支援 | 等 v1 把 catalog 搬 DB |
| 無 cross-tenant 支援 | super admin 跨 tenant 不能用 | 詳見 docs/analysis/2026-05-28-worker-thread-session-scope.md |
| 預覽大檔(>50MB)失敗 | 超大 spreadsheet / 掃描 PDF | FE 自動顯示「在 Drive 開啟」fallback |
| 同 run 並發儲存 last-write-wins | 兩 user 編輯衝突 | v1 加 ETag |
| 無 audit log | 只能從 Drive _state.json revisions 反查 |
v1 加 audit table |
app/oscal/service/export/ssp_libreoffice_converter.py(預覽 docx→pdf 共用)app/cloud_integration/(Drive OAuth + folder mappings)claude-sonnet-4-6 + prompt caching)ANTHROPIC_API_KEY(放 BE process env,不入版控)cmmc-classifier:latest Docker image(host 端 build)以 Gherkin 風格陳述,供測試 repo 對應 Cucumber feature file:
Feature: AI Evidence Auto-Classification
Background:
Given my tenant is connected to Google Drive
And the project's AP has been Drive-initialized with an Evidences folder
And the Evidences folder contains evidence files
Scenario: Manager can trigger classification
Given I am a project manager on the ProjectAuditorOverview
When I click "自動分類證據"
And I confirm with threshold 0.80
Then a job_uid is returned and a toast confirms queueing
And the main button switches to "分類中..." with a spinner
Scenario: Non-manager cannot see trigger button
Given I am a project auditor (not manager)
Then the "自動分類證據" button is not visible
Scenario: Drive not ready hides the trigger button
Given the AP has no Drive folder mapping
Then the "自動分類證據" button is not visible
Scenario: Classification completes and triggers toast notification
Given an active classification job
When the BE worker finishes drive operations
Then a success toast appears with "{classified}/{total} 已分類"
And the main button reverts to "自動分類證據"
Scenario: Reviewer adjusts placements then saves
Given a completed classification with run_folder_id "..."
When I open the review page
And I remove a placement
Then it reappears in "AI 推薦" section with original confidence
When I click "套用變更" in AOPicker after toggling AOs
Then placements are updated locally with proper "新加入" / "已標記移除" indicators
When I click "儲存變更"
Then a success toast confirms the operation count
And Drive folder contents reflect the changes (copies created / trashed)
Scenario: Docx preview inline
Given the file list shows a .docx evidence file
When I click the 👁 icon
Then a preview dialog opens
And the document is rendered as PDF inline (BE converted via LibreOffice)
Scenario: Unsupported preview falls back to Drive link
Given the file is an obscure format with no inline renderer
When I click the 👁 icon
Then a fallback message appears with "在 Drive 開啟" and "下載" buttons
Scenario: History survives BE restart
Given a completed classification exists in Drive
And the BE process has been restarted
When I open the trigger dialog
Then the history list shows the past run reconstructed from Drive scan
And clicking "查看分類結果" loads the review page successfully
詳見 docs/release_notes/v1.2.1.md §8。重點:
| 優先級 | 項目 | 觸發時機 |
|---|---|---|
| 高 | drive_ready gate 加回:STG 部署完整 + 既有 project 重跑 init folders 補 EVIDENCES mapping 後,把 && ecJobs.driveReady.value 加回 ProjectAuditorOverview.vue v-if |
STG 跑完 backfill 之後立刻 |
| 高 | DB 化 JobRegistry + run folder reverse-lookup | 上 staging 之前 |
| 高 | Cross-tenant super admin 支援 | 當第一個多 tenant 客戶需求出現 |
| 中 | Framework catalog 搬 DB(支援多框架) | 確認第二個目標框架時 |
| 中 | 並發鎖(ETag)+ audit log | 多 user 場景 |
| 低 | AOPicker 虛擬列表 | 評估項目 > 200 的框架時 |
| 低 | 預覽快取 + 大檔串流 | 預覽使用頻繁時 |
| 日期 | 版本 | 主要變更 |
|---|---|---|
| 2026-05-29 | v1.2.1 (未 push) | minConf slider 範圍 0.5→0 / 「未分類審閱」toggle 自動 minConf=0 / drive_ready gate 暫時拿掉(STG demo workaround,要加回)/ MF template edit jump-to-control tab 切換修正 |
| 2026-05-28 | v1.2.1 | Drive scan 歷史復原 / 預覽(含 LibreOffice docx→pdf)/ EVIDENCES scope mapping(init folders 自動建)/ worker thread session_scope 修正 / run folder 時區改 Asia/Taipei / dedup 修(run folder 建好立即 update registry)/ verify-and-repair user 屬性 typo 修 |
| 2026-05-27 | v1.2.0 ~ v1.2.1 過渡 | docker container 收口(S1)/ BE module(S2)/ FE review page(S3)/ trigger dialog(S4) |
| 2026-05-26 | POC | 純 script,以 docs/reference/CMMC-Level 1-Evidences 為測試集 |