規劃日期:2026-05-27 撰寫人:raymond + Claude 狀態:Phase 0 草稿,待 brainstorm 後搬至
docs/features/<feature-name>/
在專案頁加一個「自動分類證據」按鈕,按下後系統會把這輪 AP 上傳到 Drive 的所有證據檔,透過 AI 自動分到對應的 CMMC 控制項 / AO 資料夾,user 在審閱頁微調確認後完成歸檔。
目前 user 跑完一輪 AP 後,要把幾十到幾百份證據手動分類到 17 個控制項 × 59 個 AO 的對應資料夾,耗時且容易漏分。POC 證明 Claude AI 可以做到 ~98% 自動分類準確度,可大幅降低人工。
① 上傳證據到 Drive 暫存
↓
② Web 按按鈕觸發分類 (BE 收 request)
↓
③ BE 開 Docker container 跑分類 (~10 分鐘 / 130 檔)
↓
④ Container 把檔自動 copy 到對應 AO 資料夾 (in Drive)
↓
⑤ User 進審閱 UI 微調 / 確認
↓
⑥ User 儲存後 BE 把調整落實寫回 Drive,完成歸檔
現況沿用,不需新功能
新增 「🪄 自動分類證據」 按鈕
按鈕狀態邏輯:
| 條件 | 按鈕狀態 |
|---|---|
| 專案沒連 Drive | 隱藏 |
| Evidences 資料夾沒檔案 | 灰 disabled,提示「請先上傳證據檔」 |
| 上次分類 job 還在跑 | 灰 disabled,顯示「分類中... 已處理 23/130 (預估剩 7 分鐘)」 |
| 上次分類完成 | 正常啟用,hover 提示「上次執行 2026-05-27 14:30 · 點此重新分類」 |
點按鈕:
POST /api/projects/{uid}/auto-classify-evidence 給 BE202 Accepted + job_uid(job_uid, project_uid, framework_id, status=queued, started_by, started_at)docker run --rm \
-v /var/lib/cm/jobs/<job_uid>:/job \
-e DB_HOST=... -e DB_SECRET=... \
-e DRIVE_TOKEN_ENCRYPTION_KEY=... \
-e ANTHROPIC_API_KEY=... \
cmmc-classifier:latest \
classify --project-uid X --tenant-id Y \
--catalog /job/catalog.json \
--output /job/report.json/job/report.json + 更新 job status = completed 或 failedcompliance.tenant_drive_integrations 撈 tenant 的 OAuth refresh token,解密 + 換 access token/job/report.json 退出(不直接寫 Drive,留給 BE)POC 實測 134 檔 + Claude Sonnet 4.6 + 5 workers 並行 = ~10 分鐘。
每次分類都建一個獨立 run 資料夾放結果,互不覆蓋:
Project Drive/
AP-Q1-2026/
Evidences/
├── A.docx ← 原始檔(保留不動)
├── B.csv
├── ...
│
├── 自動分類_2026-05-27_14-30/ ← 第一次跑 (run folder)
│ ├── [AC] Access Control/
│ │ ├── [AC.L1-3.1.1] Authorized Access Control/
│ │ │ ├── [a] authorized users are identified/
│ │ │ │ └── A.docx ← copy of original
│ │ │ ├── [b] .../
│ │ │ └── ...
│ │ └── [AC.L1-3.1.2] .../
│ ├── [IA] .../
│ ├── ...
│ ├── _report.json ← Claude reasoning 完整報告
│ └── _summary.md ← 人可讀統計摘要
│
└── 自動分類_2026-05-27_15-00/ ← 第二次跑(re-classify)
└── ... (同上結構)
格式:自動分類_YYYY-MM-DD_HH-MM(依 BE timezone)
如果同分鐘內重跑:加 _2、_3 後綴避免衝突。
files.copy 把原檔複製到對應 AO 資料夾_report.json 和 _summary.md 寫到 run folder 根(給未來 audit / 機器讀)completed| 優點 | 說明 |
|---|---|
| 多次重跑不衝突 | 第二次跑不會覆蓋第一次的結果,user 可比對哪次更準 |
| 完整 audit trail | 過去每次 AI 分類的結果 + reasoning 都保留 |
| Drive 結構乾淨 | Evidences 根只有原始檔 + N 個 run 資料夾,不會跟 AO 結構混在一起 |
| 可獨立刪 / 歸檔 | 舊的分類 run 可整資料夾砍掉或搬到 archive |
| Job 對應清楚 | 一個 job = 一個 run folder,1:1 mapping |
功能(已雛形實作):
審閱期間 user 的每個動作是 pending 狀態,沒寫回 Drive。Save bar 顯示「N 個變更待儲存」。 User 可隨時 discard 或 save。
User 點「儲存變更」:
所有編輯都套用在「目前審閱中的 run folder」內(不影響其他 run)。
| 編輯類型 | Drive 動作(在 run folder 內) |
|---|---|
| 新增 AO 配對 | files.copy 把原檔複製到 <run-folder>/[XX]/[YY]/[z]/ |
| 移除 AO 配對 | 從 <run-folder>/[XX]/[YY]/[z]/ trash 副本 |
| 標為非證據 | 不動 Drive,只更新 BE flag(該 run 的未分類隊列隱藏) |
| 從證據池刪除 | trash 原檔(Evidences 根) + 所有 run folder 內的副本 |
(user_id, job_uid, run_folder, file_id, action, before_aos, after_aos, timestamp)實驗階段不動 DB,全部 state 都用 JSON 存在 Drive 的 run folder 內,BE 當 thin proxy。
Evidences/
自動分類_2026-05-27_14-30/
├── _state.json ← UI 讀寫的 single source of truth
├── _report-original.json ← Claude 原始輸出(immutable 留底)
├── [AC] Access Control/... ← 實體檔副本(依 _state.json 內容生成)
└── [IA] ...
_state.json 結構⚠️ 以下為 FR-030 初版 schema。實際欄位已隨 FR-030.2/030.3 擴充(token_usage / archive_files / archived_at / error 等),且
run_uid/edit_log實際未實作。完整最新 schema 以docs/api/evidence-classification/state-json-schema.md為準。
{
"metadata": {
"run_uid": "abc-123",
"drive_run_folder_id": "1xyzABC...",
"drive_run_folder_name": "自動分類_2026-05-27_14-30",
"framework_id": "cmmc-l1",
"confidence_threshold": 0.80,
"model": "claude-sonnet-4-6",
"triggered_at": "2026-05-27T14:30:15Z",
"completed_at": "2026-05-27T14:40:22Z",
"last_edited_at": "2026-05-27T15:05:33Z",
"last_edited_by": "user@example.com"
},
"files": [
{
"file_drive_id": "1yktzl...",
"file_name": "authorized-device-registry.csv",
"is_na": false,
"is_deleted": false,
"matches": [
{"ao_id": "AC.L1-3.1.1[c]", "confidence": 0.97, "reasoning": "..."},
{"ao_id": "AC.L1-3.1.1[f]", "confidence": 0.95, "reasoning": "..."}
],
"placements": [
{"ao_id": "AC.L1-3.1.1[c]", "placement_drive_id": "1b36g1...", "source": "ai", "added_at": "2026-05-27T14:35:01Z"}
]
}
],
"edit_log": [
{"at": "2026-05-27T15:02:11Z", "by": "user@...", "file_drive_id": "1yktzl...", "action": "remove_placement", "ao_id": "AC.L1-3.1.1[f]"}
]
}兩個 key 概念分開:
matches:Claude 原始評估,immutable。降閾值重看都靠這個算placements:當前真實狀態,mutable。UI edit 就是改這個| Endpoint | 行為 |
|---|---|
POST /api/projects/<uid>/classify-evidence |
起 container,回 { run_folder_id, status: "queued" } |
GET /api/classification-runs/<folder-id>/state |
從 Drive 拉 _state.json 回傳 |
PUT /api/classification-runs/<folder-id>/state |
收新 state → diff 舊 placements vs 新 → Drive copy/trash → 覆寫 _state.json |
① Container 跑完
↓ 寫 _state.json + _report-original.json 到 run folder
② User 進審閱 UI
↓ GET _state.json → 載入瀏覽器 in-memory
③ User 編輯
↓ 所有 pending changes 累積在瀏覽器 state.files[].placements / is_na 等
④ User 按儲存變更
↓ PUT 整份新 state
BE:
a. diff 舊 vs 新 placements
b. 對每筆 diff 跑 Drive copy / trash
c. 把新版 _state.json 覆寫回 Drive
d. Drive 自動保留舊版 revision(內建 audit log)
| 好處 | 說明 |
|---|---|
| 零 schema migration | 完全不動 DB,純 Drive 操作 |
| 開發快 | BE 3 個 endpoint + UI 接 GET/PUT |
| Audit 內建 | Drive file revisions = 免費 audit log |
| 跨 run 自然 isolated | 不同 run folder 各自有 _state.json |
| 取捨 | 應對 |
|---|---|
| 不能 cross-run 跨查 | 實驗期沒需求,正式版再轉 DB |
| 並發編輯衝突 | 加 ETag / If-Match 鎖;後改的拒絕 |
| 大 JSON 全寫 | 134 檔 ~400KB OK,過萬檔再考慮 |
| Drive API rate limit | 編輯 batch save,不要每次 edit 都打 |
[現在 — 實驗階段] 純 JSON in Drive,BE 當 thin proxy
↓
[v1.0 正式版] DB schema (3 tables),Drive 結構照舊
_state.json 仍寫但變 derived export
↓
[v2.0 性能版] DB 為主,可跨 run 查 + filter
_state.json 純 export 不再 source
此段為未來規劃,v1 實驗階段不實作
3 個新表:
evidence_classification_runs — run metadataevidence_classification_results — 每檔每 AO match(含被切掉的低信心)evidence_classification_edits — user 編輯 audit log具體 schema 詳見後續 Phase 3 implementation plan。
queued → running → completed
↘ failed (可重試)
↘ cancelled (user 主動取消)
| 狀態 | 說明 |
|---|---|
queued |
剛建,尚未起 container(通常很短) |
running |
container 跑中,BE 可以顯示「已處理 X/Y」進度 |
completed |
分類完成,user 可進入審閱 |
failed |
container 異常退出,user 可重試 |
cancelled |
user 主動取消(少見) |
| 情境 | 處理 |
|---|---|
| 檔案太多(>500) | BE 分批起 container(每批 100 檔),UI 顯示批次進度 |
| 單檔太大(>50MB) | 跳過 + log 警示,列在「未處理」清單供 user 知悉 |
| 不支援檔型(.zip / .mp4 / .pdf 純圖等) | 跳過 + 顯示在「未處理」清單 |
| 同名檔案多次上傳 | Drive 允許重名,UI 用 Drive 內部 fileId 區分顯示 |
| Container 中途失敗 | 保留已處理的 report 部分,user 可選「採用部分結果」或「重跑全部」 |
| Review 期間 user 又上傳新檔 | 新檔不在本 job 範圍,需要再跑一次自動分類 |
| 同專案重複觸發 | 第二次點按鈕擋下,顯示「已有分類 job 在跑」 |
| Drive OAuth 失效 | Container 偵測到 401 → fail job + 提示 user 重新連線 Drive |
| AO 資料夾已被 user 手動建過 | 重用既有資料夾,不重建 |
| AO 資料夾下已有同名檔 | 跳過 copy(避免重複),report 標記「已存在」 |
✅ 包含:
❌ v1 不包含(後續再說):
_archived 資料夾?superpowers:brainstorming skill)細究 UX 流程docs/features/FR-030-2605-auto-evidence-classification/scripts/evidence/classify/classify_evidence_drive.pydocs/reference/CMMC-Level 1-Evidences/cmmc_l1_aos.jsonscripts/evidence/classify/prototype-ui/index.htmlscripts/evidence/classify/classification_report_drive.jsondocs/reference/CMMC-Level 1-Evidences/CMMC-Level 1-Evidences-sample/docs/analysis/2026-05-27-cmmc-ao-classification-disputes.md