# Overnight Progress Report — 2026-05-28 (early morning)

> 對應 spec：`../design.md`
> 對應 plan：`../implementation-plan.md`
> 緣由：user 睡前說「持續作業下去」，目標把 S1–S4 全做完，user 早上 review

| 項目 | 值 |
|---|---|
| BE branch | `fearure/ai-evidence-classify` |
| FE branch | `fearure/ai-evidence-classify` |
| BE commits（新） | `b1936c35` Docker container · `410f3f46` S2 BE module |
| FE commits（新） | `7519b5f` S3 review page · `2f71eb9` S4 trigger panel |
| Push 狀態 | **未 push**，等你早上 review 後決定 |
| Docker image | `cmmc-classifier:latest` build 完成（196MB content） |
| 預估 review 時間 | 30-45 分鐘 |

---

## §0 接手讀序

按順序看比較好理解全貌：

1. **本檔**（先看，知道做了什麼）
2. `docs/features/FR-030-2605-auto-evidence-classification/design.md` — 整體規格（Phase 0）
3. `docs/features/FR-030-2605-auto-evidence-classification/implementation-plan.md` — S1-S4 切分
4. `docs/api/evidence-classification/api-spec.md` — 3 endpoints API 規格
5. **跑 BE** 看 startup log 有沒有 evidence_classification 模組註冊（見 §3 測試）

---

## §1 完成的事

### S1 — Docker Container ✅

新建 `scripts/evidence/classify/docker/`：
- `Dockerfile` — python:3.11-slim base，~200MB
- `requirements.txt` — anthropic / google-api / docx / sqlalchemy / cryptography
- `container_entrypoint.py` — self-contained，subcommand `service-classify`
- `jedi_helpers/` — 內聯 FernetCrypto + GoogleOAuthClient（不 import infra/）
- `README.md` + `.dockerignore`

**驗證**：`docker run --rm cmmc-classifier:latest service-classify --limit 3 ...` 跑 3 檔 16.8s，輸出 `_state.json` + `_report-original.json` 結構正確。

### S2 — BE 模組 ✅

新模組 `api/evidence_classification/` + `app/...` + `infra/...` + `di_containers/...`

3 個 endpoints（auto-registered via Blueprint）：
- `POST /api/1.0/project/<project_uid>/classify-evidence` — 觸發
- `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` — 寫 + diff + Drive ops

關鍵實作：
- `ClassifierContainerRunner` — `subprocess.Popen(['docker', 'run', ...])` block 等結果
- `EvidenceDriveOps` — Drive copy/trash/upload-json/list-children helper
- `JobRegistry` — in-memory thread-safe dict（無 DB，restart 後消失，可接受）
- 容器跑完後，BE 在背景 thread 內：
  - 建 Drive run folder `自動分類_YYYY-MM-DD_HH-MM`
  - 建 domain/control/AO 三層子資料夾結構
  - `files.copy` 每筆 placement 進對應 AO 資料夾
  - upload `_state.json` + `_report-original.json` 到 run folder

DDD 規範遵守：
- `@transaction` 在 app service public methods
- Domain service 透過 DI 注入（ProjectDomainService / ProjectParticipantDomainService / TenantDriveIntegrationDomainService）
- 用既有 `GoogleDriveTokenManager` 拿 access_token
- Error codes `EC_*` (`common/code/evidence_classification_error_code.py`)

### S3 — FE 審閱頁 ✅

新 Vue route：
`/project/projects/:id/ap/:apUid/classify-evidence/run/:runFolderId`

元件結構（全 PrimeVue + Ultima theme + FE CLAUDE.md 規範）：
```
src/views/evidence-classification/
├── EvidenceClassificationReview.vue        頁面 entry
├── aoLookup.js                              flatten catalog helper
└── components/
    ├── ClassificationStatsRow.vue           5 stat cards
    ├── ClassificationFilterBar.vue          search/domain/status/conf + inbox
    ├── ClassificationFileList.vue           DataTable virtual scroll
    ├── ClassificationFileDetail.vue         right panel
    ├── PlacementCard.vue                    breadcrumb + reasoning + remove
    ├── CandidateCard.vue                    for unclassified files
    └── AOPickerDialog.vue                   searchable AO picker
```

支援功能：
- 整頁繁中（zh-tw locale，evidence-classification.json）
- LoadingState 蓋整頁直到 state.json 載完
- 5 stat cards（未分類那張黃色可點切進 inbox 模式）
- 篩選：search / domain / status / min confidence slider / reset
- 「未分類審閱」inbox toggle button
- 鍵盤導航 ↑↓ / j/k 切上下個檔
- 完整 AO breadcrumb 顯示（domain code + name → control id + name → letter + AO description）
- Claude reasoning 全文顯示
- 編輯：移除 / 加入 / 標非證據 / 刪除
- AO picker 含 type-as-you-search filter
- Sticky save bar + pending edit count
- useConfirm for destructive actions / useToast for success/error feedback

**build 驗證**：`npm run build:DEV` 通過，`EvidenceClassificationReview-09cca9de.js` 43 KB / gzip 11 KB

### S4 — 觸發按鈕整合 ✅

新元件 `src/components/grc/project/AIEvidenceClassificationPanel.vue`：
- 接受 Drive Evidences 資料夾 URL 或裸 ID（auto-parse）
- Confidence threshold slider
- 觸發按鈕 + ConfirmDialog
- 觸發後 polling `/jobs` 每 5s
- 顯示歷史 jobs + 「審閱分類結果」連結到 review page

嵌入到 `ProjectPlanningView.vue` 的 Cloud Integrations TabPanel 內，跟既有 `ProjectCloudIntegrationsPanel` 並列。

---

## §2 怎麼測試（你早上的順序）

> ⚠ **你昨晚說 BE 對 project AP → Drive 連結有問題**。我已經把 trigger endpoint 設計成從 request body 收 `evidence_folder_id`（不從 DB derive），FE panel 也是要 user 手動貼 URL/ID。這樣繞過 AP-Drive 連結問題，可以直接用你給的測試資料夾 `1fTAAUXpo66PUkfyHhTpMf4xjUJexCZ8v`。

### Step 1：啟動 BE

```bash
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
# 你自己用既有方式起 BE（main_socketio.py 或 main_app.py）
```

觀察 startup log：應該看到 `Evidence Classification module registered`。

### Step 2：啟動 FE

```bash
cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe
npm run dev
# http://localhost:5180
```

### Step 3：UI 測試流程

1. 登入 → 進 project `40c3f612-00a4-4574-868b-276a82d30ef0` → AP `eaa521f1-...` → **專案規劃** 頁
2. 點「**雲端整合**」TabPanel
3. 看到新區塊「**AI 證據分類**」
4. 在輸入欄貼：`https://drive.google.com/drive/folders/1fTAAUXpo66PUkfyHhTpMf4xjUJexCZ8v` 或直接貼 ID
5. 信心閾值預設 0.80，可調
6. 按「**自動分類證據**」→ 確認 dialog → 開始
7. 看到按鈕變「**分類中…**」，5s 一次 polling
8. **預計 10-15 分鐘**（134 個檔 × Claude API call）
9. 完成後在 job 歷史看到一筆 completed，按「**審閱分類結果**」
10. 跳到審閱頁，看 stats / 檔案清單 / detail panel
11. 試移除 / 加入 / 標 N/A / 刪除 → 按儲存 → 看 toast 結果

### Step 4：純 API 測試（可選）

```bash
# 觸發
curl -X POST http://localhost:8000/api/1.0/project/40c3f612-00a4-4574-868b-276a82d30ef0/classify-evidence \
  -H "Authorization: Bearer <jwt>" \
  -H "Content-Type: application/json" \
  -d '{"evidence_folder_id": "1fTAAUXpo66PUkfyHhTpMf4xjUJexCZ8v", "framework_id": "cmmc-l1", "confidence_threshold": 0.80}'

# Poll
curl -H "Authorization: Bearer <jwt>" \
  http://localhost:8000/api/1.0/project/40c3f612-00a4-4574-868b-276a82d30ef0/classify-evidence/jobs

# 完成後讀 state
curl -H "Authorization: Bearer <jwt>" \
  http://localhost:8000/api/1.0/classification-run/<run_folder_id>/state
```

### Step 5：直接跑 container（最低層 sanity）

```bash
mkdir -p /tmp/cm-jobs/manual
cp "docs/reference/CMMC-Level 1-Evidences/cmmc_l1_aos.json" /tmp/cm-jobs/manual/catalog.json
docker run --rm \
  -v /tmp/cm-jobs/manual:/job \
  --env-file .env \
  cmmc-classifier:latest service-classify \
    --tenant-id 102 \
    --evidence-folder-id 1fTAAUXpo66PUkfyHhTpMf4xjUJexCZ8v \
    --catalog-file /job/catalog.json \
    --output-dir /job \
    --min-confidence 0.80 \
    --limit 3
ls /tmp/cm-jobs/manual/    # 看到 _state.json + _report-original.json
```

---

## §3 已知問題 / Workaround

| 問題 | 影響 | Workaround |
|---|---|---|
| **AP → Drive 資料夾連結 BE 有 bug**（你昨晚提的） | 無法從 DB 自動 derive evidence_folder_id | FE panel 要 user 手動貼 URL/ID。已實作。等 BE 修好後 panel 可改自動 |
| BE restart 後 in-memory job state 消失 | 跑中的 container 不受影響（subprocess 獨立），但 job 狀態 UI 看不到 | 等 v1.0 改 DB tables |
| `_state.json` 讀取必須有 in-memory job 才知道 tenant | restart 後不能 GET state | 等 v1.0 改用 project_uid 路徑（會把 project 找 tenant） |
| 兩人同時 PUT state 後改的覆蓋前改的 | 並發編輯衝突 | 實驗階段先這樣，v1.1 加 ETag |
| Drive folder 內若有大量已存在的 run folder（重跑多次）會看起來雜亂 | 視覺上 | 手動刪舊 run folder 或 v1 加 cleanup policy |

---

## §4 沒做完 / 後續

| 項 | 說明 |
|---|---|
| **E2E 實測** | 我沒辦法起 BE 跑 curl，所有 BE 程式碼透過 syntax + import + AST parse 通過，但 actual HTTP request 要你早上測 |
| **AP-Drive 自動連結** | 等你 BE bug 修好後，把 AIEvidenceClassificationPanel 的「user 輸入 folder URL」改為從 BE 取自動帶 |
| **正式版 DB schema** | design.md §「v1.0 之後的 DB schema」三表，目前實驗階段不做 |
| **多框架支援** | 目前 hardcoded cmmc-l1，catalog from `cmmc_l1_aos.json`；BE 加 OSCAL API + FE 加 framework 選擇器後可支援 NIST 800-171 / ISO 27001 等 |
| **E2E 測試（compliance-manager-test repo）** | 等 UI 穩定後在 test repo 加 Cucumber feature |
| **Drive 重新整理** | 每次跑完 BE 把 `_state.json` upload 到 run folder，但 Drive web UI 偶爾要 manual refresh 才看到 |

---

## §5 行為規範遵守 checklist（我自我審查）

- ✅ 不切 branch（全程在 `fearure/ai-evidence-classify`）
- ✅ Commit 顯式 git add 檔案路徑，不用 -am
- ✅ 沒 push（等你 review）
- ✅ 沒掃進別處的 working tree 變更（infra/associations/...py、parse-response.json 等保持原狀）
- ✅ FE 用 PrimeVue + Ultima global classes + LoadingState
- ✅ 繁中 i18n + 英文並行
- ✅ Add 按鈕用 outlined per FE 規範
- ✅ Icon-only button 用 `v-tooltip.top`
- ✅ Typography 用 PrimeFlex `text-2xl` / `text-sm` 等
- ✅ BE DDD 層級遵守（route 不查 DB / app service `@transaction` / domain service via DI）
- ✅ Error code 命名規則 `EC_<HTTP-status><序號>`
- ✅ API spec md 寫好
- ✅ 沒寫 changelog 等你確認後再寫（per memory「收尾才寫」）

---

## §6 快速指令給你早上用

```bash
# === BE side ===
cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
git log --oneline -5                    # 看新 commits
docker images | grep cmmc-classifier    # 確認 image 在
# 起 BE（用你的方式）

# === FE side ===
cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe
git log --oneline -3
npm run dev                             # 啟動 dev server

# === Quick container sanity ===
mkdir -p /tmp/cm-jobs/quick && \
cp "docs/reference/CMMC-Level 1-Evidences/cmmc_l1_aos.json" /tmp/cm-jobs/quick/catalog.json && \
docker run --rm -v /tmp/cm-jobs/quick:/job --env-file .env \
  cmmc-classifier:latest service-classify \
    --tenant-id 102 --evidence-folder-id 1fTAAUXpo66PUkfyHhTpMf4xjUJexCZ8v \
    --catalog-file /job/catalog.json --output-dir /job --limit 3
cat /tmp/cm-jobs/quick/_state.json | head -50
```

---

## §7 撞牆時看哪裡

- BE 起不來 → BE log（`log/app.log`），搜 `evidence_classification` 看是否註冊
- BE 起來但 endpoint 404 → 確認 `config/app_modules.py` 有 `evidence_classification`
- Trigger 後 container 沒跑 → BE log 看 subprocess 是否 spawn；確認 BE process 能 `docker`（user 是不是有 docker group 權限）
- Container 跑但寫 Drive 失敗 → BE log 看 `[classifier] job=... drive op ...`
- FE 報 403 → user 不是專案 manager
- FE 報 412 EC_DRIVE_NOT_CONNECTED → tenant Drive integration status 不是 CONNECTED
- FE 報 404 EC_EVIDENCE_FOLDER_NOT_FOUND → 貼的 folder ID 拼錯，或 tenant OAuth 沒權限存取
- FE 顯示 hint-bar 但收不到 toast → 看瀏覽器 Network 看 BE response shape
- 審閱頁 GET state 404 → `_resolve_tenant_for_run_folder` 找不到 in-memory job（BE restart 後就會這樣）

---

## §8 我覺得明天最應該先做的事

1. **跑通 E2E**（trigger → 等 10-15 分 → 開審閱頁 → 編一兩個檔 → 儲存）
2. 確認 Drive 上產出 `自動分類_<datetime>` 資料夾結構正確
3. 確認 review UI 把每個檔的 reasoning 顯示得清楚
4. 修 BE AP→Drive 連結 bug，把 FE panel 的「手動輸入 URL」改自動 derive
5. 等所有都跑通了再 push + 寫 changelog
