diff --git a/docs/autoflow/04-architecture/adr/adr-019-local-direct-media-upload.md b/docs/autoflow/04-architecture/adr/adr-019-local-direct-media-upload.md index 95f5f69..fcfbfce 100644 --- a/docs/autoflow/04-architecture/adr/adr-019-local-direct-media-upload.md +++ b/docs/autoflow/04-architecture/adr/adr-019-local-direct-media-upload.md @@ -1,7 +1,14 @@ # ADR-019: 影片 / 圖片 / 批次上傳走同機 localhost 直連 local-agent(混合路徑) ## 狀態 -Proposed(尚未實作)。**已依 security review(`.autoflow/05-implementation/review/adr-019-security-review.md`)修正契約(C1 / M1 / M2 / M3 / 議題1),待 security confirm-only 複審 + 實作完成後轉 Accepted。** C1 定案採方案 A(route 分離),見 §2.4。 +Accepted。 + +**底層能力已於 2026-07-30 完成並 merge 進 main(github PR #1、merge commit `3eaf3dc`)。** 走過完整審查流程:security pre-implementation review(1 Critical + 3 Major)→ 契約修正(C1 / M1 / M2 / M3 / 議題1)→ security confirm-only 複審 → 逐 WP reviewer 通過 → security code-level 複審 **APPROVED** → testing 回歸(270 測試全綠、既有 tunnel 路徑未打斷、無 regression)。C1 定案採方案 A(route 分離),見 §2.4。 + +> ⚠️ **「Accepted」≠「端到端功能已對使用者啟用」。** 本次 merge 的是 **backend/frontend 的底層能力**(local-agent CORS/PNA/token/新 route、雲端 ticket endpoint、前端 port 探測抽象、批次合計檢查)。**前端影片分頁 UI 尚未切到新的 localhost 路徑(WP-4 未做)**,故: +> - 影片上傳目前**仍走既有雲端 tunnel 路徑**,端到端「localhost 直連」尚未對使用者啟用。 +> - **90MB 過渡上限仍在生效**(見 `.autoflow/` 相關過渡處置)。 +> - WP-4 接線完成前,不可視為「ADR-019 功能已上線可用」。詳見 §7 合規性與 §8 WP 清單狀態標記。 ## 日期 2026-07-24 @@ -203,11 +210,16 @@ Token 設計方向(已經 security agent 審,核心設計通過,見 review ## 7. 合規性 - [x] 與使用者確認方向(同機 localhost 直連 + 混合路徑 + 範圍含影片/圖片/批次 + 非同機停用 + 僅 Chromium + 認證必做)— ✅ 已裁決 -- [x] **security agent 審 token / 隱私設計**(§5 兩點)— ✅ 已審(verdict: REQUEST CHANGES → 契約已依 C1/M1/M2/M3/議題1 修正,待 confirm-only 複審) -- [ ] backend agent 落地 local-agent CORS/PNA/token/endpoints + 雲端 ticket endpoint -- [ ] frontend agent 落地 port 探測抽象 + 影片分頁接線 + 批次合計檢查 -- [ ] testing agent 回歸:既有 tunnel 路徑(無 Origin)不受 token 影響;跨瀏覽器(Chrome/Edge)驗證 -- [ ] 成本影響:**無新雲端資源**(沿用現有 DB / tunnel),主要是三 module 開發工時,粗估 3.3–5.4 人天(見 §8 WP 清單);反而降低 stage 磁碟與頻寬壓力 +- [x] **security agent 審 token / 隱私設計**(§5 兩點)— ✅ 已審(初審 REQUEST CHANGES [1C+3M] → 契約已依 C1/M1/M2/M3/議題1 修正 → confirm-only 複審 → code-level 複審 **APPROVED**) +- [x] backend agent 落地 local-agent CORS/PNA/token/endpoints + 雲端 ticket endpoint — ✅ 已 merge(PR #1) +- [x] frontend agent 落地 port 探測抽象(WP-3)+ 批次合計檢查(WP-7)— ✅ 已 merge(PR #1) +- [ ] frontend agent **影片分頁接線(WP-4)** — ⏳ **未做(下一批)**。WP-3 port 探測抽象與 WP-7 批次合計檢查已完成,但「影片分頁 UI 切到 `/api/local/media/upload/video` 新路徑」屬 WP-4,尚未落地 → 端到端功能未對使用者啟用、90MB 過渡上限仍生效 +- [x] testing agent 回歸:既有 tunnel 路徑(無 Origin)不受 token 影響 — ✅ 270 測試全綠、既有 tunnel 未打斷、無 regression +- [x] 成本影響:**無新雲端資源**(沿用現有 DB / tunnel),主要是三 module 開發工時(見 §8 WP 清單);反而降低 stage 磁碟與頻寬壓力 — ✅ 已實作,符合預期(無新增雲端資源) + +> **Backlog(本次 merge 未處理,記錄於此供後續追蹤):** +> - **同機程序存取控制**(優先級 Low):既有 loopback 攻擊面(非本 ADR 新增,見 §2.4.1 誠實揭露的殘留風險)。同機惡意程序仍可直打舊 tunnel-path route;根治需 OS 層 peer credential / socket 權限驗證,超出本 ADR 範圍。 +> - **WP-4 接線時的真實 Kneron 序號實機驗收**:需做真實序號的前後端 hash 實機驗證——後端 `SHA-256` 輸入的序號格式(`0x%08X` 大寫)與前端 `serialNumber` 須同形,否則 hash 不符會誤判非同機。此為 fail-closed(不符即停用分頁),WP-4 接線時必驗。 --- @@ -217,16 +229,18 @@ Token 設計方向(已經 security agent 審,核心設計通過,見 review > **本清單已依 security review 更新**(C1 route 分離、M1 size 上限 + temp 清理必做、M2 Host 驗證必做、M3 CORS 完整 origin 精確比對)。 -| WP | 內容 | 負責 agent | 依賴 | 人時 | -|----|------|-----------|------|------| -| WP-0 | Spike:Chrome/Edge 實測 `https/http 入口 → http://127.0.0.1:3721` + PNA console warning | frontend | 無 | 2–4 | -| WP-1 | local-agent CORS / Host / PNA:雲端 origin **完整 origin 精確比對**(獨立於既有 hostname-only 邏輯,**不放寬既有 scheme 檢查**)+ **`Allow-Credentials: false`(雲端 origin)** + **Host header 驗證 = loopback(M2 必做,套用 `/api/local/*` 與舊 media route)** + PNA header + `Access-Control-Max-Age: 600` | backend(Go) | 契約 §2.5 | 5–7 | -| WP-2 | local-agent:**新 route `/api/local/media/upload/{video\|image\|batch-images}`(一律要 token、不看 Origin、內部轉呼叫既有 handler)** + `/api/local/hello`(回 salted SHA-256 serialHashes) + `/api/local/issue-token` + token store(single-flight 持鎖)+ token 驗證中介(放 `FormFile` 前)+ **media size 上限(video ≤500MB 硬牆 / batch 合計 80MB,M1 必做)** + **temp 檔清理(`stopActivePipeline` 補 `os.Remove` + batch 生命週期刪檔,M1 必做)** | backend(Go) | WP-1 | 9–13 | -| WP-3 | 前端:`lib/local-agent.ts`(port 探測並發+快取+timeout、同機判定用 salted SHA-256 比對 serialHashes、`uploadToLocalAgent()` endpoint 無關通用函式;上傳目標改新 route `/api/local/media/upload/*`) | frontend | 契約 §2.3/§6.3 | 6–10 | -| WP-4 | 前端:影片分頁接線(取 token、改上傳目標為 `/api/local/media/upload/video`、三種錯誤訊息 i18n、tunnel 離線檢查 R-3) | frontend | WP-3 | 4–6 | -| WP-5 | 雲端:`POST /api/devices/:serial/local-upload-ticket`(經 tunnel 轉發 issue-token) | backend(Go) | 契約 C-1 | 2–4 | -| WP-6(可選) | 圖片 + 批次接上 localhost 路徑 | frontend | WP-4 驗證通過 | 3–5 | -| WP-7(獨立,建議先做) | `validateBatchFiles` 加合計大小檢查 | frontend | 無 | 0.5–1 | +> **實作狀態(2026-07-30,PR #1 merge commit `3eaf3dc`)**:WP-1 / WP-2 / WP-3 / WP-5 / WP-7 ✅ 已完成並 merge;WP-0 / WP-4 / WP-6 為**下一批(未做)**。**底層能力已具備,但 WP-4(影片分頁接線)未做 → 前端 UI 尚未切到新 localhost 路徑、端到端功能未對使用者啟用、90MB 過渡上限仍生效。** + +| WP | 內容 | 負責 agent | 依賴 | 人時 | 狀態 | +|----|------|-----------|------|------|------| +| WP-0 | Spike:Chrome/Edge 實測 `https/http 入口 → http://127.0.0.1:3721` + PNA console warning | frontend | 無 | 2–4 | ⬜ 下一批(未做) | +| WP-1 | local-agent CORS / Host / PNA:雲端 origin **完整 origin 精確比對**(獨立於既有 hostname-only 邏輯,**不放寬既有 scheme 檢查**)+ **`Allow-Credentials: false`(雲端 origin)** + **Host header 驗證 = loopback(M2 必做,套用 `/api/local/*` 與舊 media route)** + PNA header + `Access-Control-Max-Age: 600` | backend(Go) | 契約 §2.5 | 5–7 | ✅ 已完成並 merge | +| WP-2 | local-agent:**新 route `/api/local/media/upload/{video\|image\|batch-images}`(一律要 token、不看 Origin、內部轉呼叫既有 handler)** + `/api/local/hello`(回 salted SHA-256 serialHashes) + `/api/local/issue-token` + token store(single-flight 持鎖)+ token 驗證中介(放 `FormFile` 前)+ **media size 上限(video ≤500MB 硬牆 / batch 合計 80MB,M1 必做)** + **temp 檔清理(`stopActivePipeline` 補 `os.Remove` + batch 生命週期刪檔,M1 必做)** | backend(Go) | WP-1 | 9–13 | ✅ 已完成並 merge | +| WP-3 | 前端:`lib/local-agent.ts`(port 探測並發+快取+timeout、同機判定用 salted SHA-256 比對 serialHashes、`uploadToLocalAgent()` endpoint 無關通用函式;上傳目標改新 route `/api/local/media/upload/*`) | frontend | 契約 §2.3/§6.3 | 6–10 | ✅ 已完成並 merge | +| WP-4 | 前端:影片分頁接線(取 token、改上傳目標為 `/api/local/media/upload/video`、三種錯誤訊息 i18n、tunnel 離線檢查 R-3) | frontend | WP-3 | 4–6 | ⬜ **下一批(未做)** — 端到端啟用的關鍵缺口;接線時須做真實 Kneron 序號前後端 hash 實機驗收(後端 `0x%08X` 大寫 vs 前端 serialNumber 須同形、fail-closed) | +| WP-5 | 雲端:`POST /api/devices/:serial/local-upload-ticket`(經 tunnel 轉發 issue-token) | backend(Go) | 契約 C-1 | 2–4 | ✅ 已完成並 merge | +| WP-6(可選) | 圖片 + 批次接上 localhost 路徑 | frontend | WP-4 驗證通過 | 3–5 | ⬜ 下一批(未做) | +| WP-7(獨立,建議先做) | `validateBatchFiles` 加合計大小檢查 | frontend | 無 | 0.5–1 | ✅ 已完成並 merge | **推薦範圍(WP-0..WP-5 + WP-7)總計:26.5–43 小時 ≈ 3.3–5.4 人天。**