# Feature:Pairing 流程(P0,雛形必做) > 父文件:[PRD.md](../PRD.md) | 對應 User Stories:US-04、US-05、US-06、US-18、US-19 --- ## 概述 Pairing 是 visionA Cloud 獨有的流程(local-tool 沒有):把使用者筆電上的 local agent 連到 visionA Cloud 的 remote-proxy,讓雲端能代管該裝置。 這個流程替代了 POC 中「Token = SHA256(MAC)[:16]」的硬編碼方式,改為**雲端發 token、綁 user + device、有 expiry、可撤銷**的產品化版本。 --- ## 使用者行為 ### 正向流程(Happy Path) 1. 使用者在瀏覽器登入 visionA Cloud 2. 在「裝置」頁面點「配對新裝置」 3. 彈出對話框,顯示: - 一組 Pairing Token(例如 `vAc_7f3c8e2a9b1d0f5e...`) - QR code(方便手機掃或直接貼) - 說明文字:「在你的 local agent 貼上這個 token」 - 倒數計時:「15 分鐘內要完成配對」 4. 使用者打開筆電上的 local-tool 5. (Phase 0 妥協)手動編輯 local-tool 的設定檔,填入: - `VISIONA_RELAY_URL=wss://relay.visiona.cloud` - `VISIONA_PAIRING_TOKEN=vAc_7f3c8e2a9b1d0f5e...` - 重啟 local-tool 6. local-tool 的 tunnel client 啟動,連到 remote-proxy 7. remote-proxy 驗證 token → 找到對應 user → 記錄 device 已配對 8. 雲端前端透過 WebSocket 收到「裝置上線」事件 → 即時更新裝置列表 9. 使用者看到新裝置出現,完成配對 ### 異常流程 **A. Token 過期** - 超過 15 分鐘未完成配對 → local-tool 連線時 remote-proxy 回 403 - local-tool 顯示「Pairing Token 已過期,請重新取得」 - 使用者回雲端重新產生 **B. Token 已被使用** - Token 預設為一次性。配對成功後不能再用 - 再次用同一 token → 回 409 Conflict - 雲端 UI 提示「此 token 已使用」 **C. Token 無效** - 亂打 token → 401 Unauthorized **D. 網路中斷後重連** - local-tool 已配對的裝置,tunnel 斷線後自動重連 - 重連時用的是 **Session Token(長期)**,不是 Pairing Token(一次性) - Session Token 在首次配對成功後由 remote-proxy 發給 local-tool,local-tool 存到本機 config --- ## Token 設計 ### Pairing Token(一次性、短期) | 屬性 | 值 | |------|---| | 格式 | `vAc_` + 32 字元 hex(範例:`vAc_7f3c8e2a9b1d0f5e...`)| | 產生者 | api-server | | 儲存 | Phase 0:in-memory map;Phase 1:DB | | TTL | 預設 15 分鐘(可調整)| | 使用次數 | 1 次 | | 綁定 | user_id(產生者)| ### Session Token(長期、可撤銷) | 屬性 | 值 | |------|---| | 格式 | `vAs_` + 64 字元 hex | | 產生者 | remote-proxy(首次 pairing 成功後發)| | 儲存 | Phase 0:in-memory map;Phase 1:DB
local-tool 端:寫入 config 檔 | | TTL | **90 天**(到期或使用者主動撤銷時失效)| | 使用次數 | 無限(TTL 內每次重連共用)| | 綁定 | user_id + device_id | > **兩階段 TTL 設計**: > - **Pairing Token 階段**:使用者在雲端產 token、貼到 local agent,15 分鐘內要完成首次連線,一次性使用 > - **Session Token 階段**:local agent 首次連上 remote-proxy 後,由 remote-proxy 發 Session Token 寫入 local config;之後 tunnel 斷線重連、跨 session 維持長連線都用這把 token,90 天內有效 > > Phase 0 先做固定 90 天 TTL;Phase 1 加 rotation(到期前一段時間自動換新 token,避免使用者介入)。 ### 為什麼分兩種 Token - Pairing Token 一次性、短期 → 防止 token 洩漏的危害被放大(最壞情況只影響 15 分鐘) - Session Token 長期 → 避免每次重連都要使用者介入,但 90 天 TTL 限制洩漏風險 - 兩階段模式類似 OAuth 的 authorization code + refresh token --- ## 介面契約(API 層面) 完整 API spec 由 Architect Agent 寫入 TDD,本文件只列出關鍵端點: ### POST `/api/pairing/generate` **Request** (需登入): ```json {} ``` **Response 200**: ```json { "pairing_token": "vAc_7f3c8e2a9b1d0f5e...", "expires_at": "2026-04-21T10:30:00Z", "relay_url": "wss://relay.visiona.cloud/tunnel/connect" } ``` ### WebSocket `wss://relay.visiona.cloud/tunnel/connect?token={token}` **流程**: 1. local-tool 發起 WebSocket 連線,帶 token(可能是 Pairing Token 或 Session Token) 2. remote-proxy 驗證: - 若是 Pairing Token:檢查未過期、未使用 → 發 Session Token(透過 WebSocket 首個 message 傳給 local-tool)→ 標記 Pairing Token 已使用 - 若是 Session Token:檢查未撤銷 → 接受連線 3. 建立 yamux session(沿用 POC 的設計) 4. 後續所有 HTTP/WebSocket 請求透過 yamux stream 轉發到 local agent ### POST `/api/devices/{device_id}/revoke` (Phase 1) **功能**:撤銷某 Session Token,強制該裝置斷線。 --- ## 驗收條件(Phase 0) - [ ] 登入後,裝置頁面的「配對新裝置」按鈕可點 - [ ] 點擊後彈出對話框,顯示 Pairing Token(明文 + QR code) - [ ] Pairing Token 格式符合規範(`vAc_` + 32 hex) - [ ] Pairing Token TTL = 15 分鐘,過期後 local-tool 連不上 - [ ] local-tool 用正確 token 連線 → 成功建立 tunnel - [ ] local-tool 用錯誤 / 過期 / 已使用的 token 連線 → 收到明確錯誤 - [ ] 配對成功後,雲端裝置列表 5 秒內顯示新裝置 - [ ] local-tool 收到 Session Token 並寫入本機 config - [ ] Session Token 格式符合規範(`vAs_` + 64 hex) - [ ] Session Token TTL = 90 天,到期後 local-tool 連線被拒,需重新 pairing - [ ] tunnel 斷線後,local-tool 用 Session Token 自動重連(TTL 內) - [ ] 全流程繁體中文 UI - [ ] TODO:Phase 0 不實作「撤銷」功能,但要在 UI 留按鈕(disabled) --- ## Phase 0 的 TODO - **TODO 1**:local-tool 端的整合 — Phase 0 先讓使用者手動編輯 config 檔;Phase 1 要在 local-tool 內建 UI「配對到 visionA Cloud」 - **TODO 2**:QR code 產生 — 可用前端套件(例如 `qrcode.react`),但優先級低,可先只顯示明文 token - **TODO 3**:Token 撤銷 — 介面留著,實作留到 Phase 1 - **TODO 4**:多 local agent 同時配對 — Phase 0 每個 user 最多 1 台 agent 同時連線,Phase 1 支援多台 - **TODO 5**:Session Token rotation — Phase 0 採固定 90 天 TTL(到期需重新 pairing);Phase 1 做到期前自動 rotation,無需使用者介入 - **TODO 6**:Pairing 流程的使用者引導(tutorial) — Phase 0 不做,Phase 1 加 onboarding --- ## 安全考量 **Phase 0 最小要求**: - Token 必須透過 TLS(`wss://`)傳輸,不能走明文 - Token 儲存在記憶體不要 log 出來 - Pairing Token 產生後不要再可讀取(只有產生當下顯示給使用者) **Phase 1 要加的**: - Token 在 DB 以 hash 儲存(不存明文) - Rate limiting(防暴力破解) - IP 地址記錄(配對時、連線時) - 異常偵測(同一 token 從不同 IP 嘗試連線) --- ## 連結 - 回:[PRD 索引](../PRD.md) - 相關:[介面契約](../interface-contracts.md)、[非功能性需求](../nonfunctional.md)