依 autoflow-agent workspace v2 設計把 PRD / 設計 / 架構 / 交付類 共享文件從個人層 .autoflow/(ignored)搬到 docs/autoflow/(進 git), 讓團隊可共享產品與架構文件,個人層只留 progress / review / testing 等 per-branch 筆記。 - 02-prd/ 21 個檔(PRD、features、market-analysis 等) - 03-design/ 18 個檔(design-spec、wireframes、flows 等) - 04-architecture/ 31 個檔(TDD、design-doc、ADR×14、API 規格等) - 07-delivery/ 3 個檔(project-summary、phase-0.6-handover、stage-deployment-setup) 合計 73 檔。原檔已從 .autoflow/ 移除(migration 工具執行 git mv, 但因 .autoflow/ 在 .gitignore 中、git 將此操作視為新增、無 rename history)。
505 lines
27 KiB
Markdown
505 lines
27 KiB
Markdown
# Pairing 流程設計 — visionA Cloud
|
||
|
||
> **雲端版最關鍵的新增流程**。使用者要能在雲端 Web 取得 Pairing Token、帶到自己電腦上的 local agent、完成配對,之後就能從瀏覽器遠端控制自己的 Kneron 裝置。
|
||
>
|
||
> 配套的文字版 wireframe 見 [`wireframes/wf-pairing.md`](../wireframes/wf-pairing.md)。
|
||
|
||
---
|
||
|
||
## 1. User Story
|
||
|
||
> **作為** 一個 Kneron 開發者,
|
||
> **我想要** 用一組短短的 token 讓雲端和我桌機上的 Kneron 裝置建立連線,
|
||
> **這樣** 我就能從任何地方(出差、客戶端、家裡)用瀏覽器操作我的裝置,不需要每次都連 VPN 或 SSH。
|
||
|
||
**成功條件**:
|
||
- Token 產生到完成連線 < 3 分鐘
|
||
- 使用者不需要懂 tunnel / yamux / WebSocket 等技術細節
|
||
- 失敗時能明確告訴使用者哪一步錯、怎麼修
|
||
|
||
---
|
||
|
||
## 2. 流程全景圖
|
||
|
||
```
|
||
雲端 Web 使用者電腦 雲端後端
|
||
─────── ───────── ────────
|
||
local agent
|
||
(Go binary)
|
||
|
||
[登入] ──→ [/devices/pair] ──────────────────────────────────→ POST /api/pairing/token
|
||
▼ ↓
|
||
產生 token 產生 vAc_ + 32 hex token
|
||
▼ (綁 user_id, TTL 15 分鐘)
|
||
[PairingTokenCard 顯示 token] ↓
|
||
▼ 回傳 token
|
||
使用者按「複製」 ←─────
|
||
▼
|
||
切換到「下載 local agent」分頁
|
||
▼
|
||
根據 OS 顯示對應下載連結 + 指令
|
||
▼
|
||
使用者下載、安裝、啟動 local agent
|
||
▼ local agent 啟動 ────→ GET /tunnel/connect?token=xxx
|
||
▼ ↓
|
||
第 3 步:等待連線 WebSocket 升級
|
||
▼ yamux session 建立
|
||
[polling] GET /api/pairing/status?token=xxx ──────────────────→ ↓
|
||
▲ 回 200 + 裝置資訊
|
||
│ ↓
|
||
◀───────────────────────────────────────────────────────────
|
||
▼
|
||
「✓ 已連線!」+ 顯示裝置資訊
|
||
▼
|
||
[繼續] 按鈕
|
||
▼
|
||
跳 /devices,顯示新裝置
|
||
```
|
||
|
||
---
|
||
|
||
### 2.1 Token 格式與兩階段 Token 模型
|
||
|
||
**雲端有兩種 token,使用者只會接觸到第一種:**
|
||
|
||
| Token | 用途 | 格式 | TTL | 使用者可見 |
|
||
|-------|------|------|-----|----------|
|
||
| **Pairing Token** | 一次性配對 token,使用者貼到 local agent 啟動連線 | `vAc_` + 32 字元 hex(總長 36)| **15 分鐘** | ✅ 看得到、要複製 |
|
||
| **Session Token** | Local agent 換到後維持 tunnel 連線用 | 後端規格(使用者不關心) | 90 天 | ❌ 完全看不到 |
|
||
|
||
**換取流程(使用者無感):**
|
||
|
||
```
|
||
1. 雲端 Web 產生 Pairing Token(vAc_xxxx…)→ 使用者複製
|
||
2. 使用者貼到 local agent → local agent 用這個 token 打 /tunnel/connect
|
||
3. 雲端驗證 Pairing Token → 核發 Session Token 給 local agent
|
||
4. Pairing Token 立即失效(one-time use)
|
||
5. 後續 local agent 所有連線都帶 Session Token,使用者完全感受不到
|
||
```
|
||
|
||
**UI 顯示策略(36 字元太長、15 分鐘很緊):**
|
||
|
||
- API 回傳完整 `vAc_` + 32 hex(一整串,共 36 字元,無空格)
|
||
- **UI 顯示切成兩行**提升可讀性(`font-mono text-xl tracking-wider`):
|
||
- 第 1 行:`vAc_` 前綴 + 前 16 字元 hex(共 20 字元)
|
||
- 第 2 行:後 16 字元 hex
|
||
- 行內用 `-` 或純空白切開都行,**切法純視覺**;`select-all` 選取時選到整個區塊
|
||
- **實際複製到剪貼簿的永遠是無空格、無換行的完整字串**(`vAc_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8`)
|
||
- Mobile(< 640px):字級降為 `text-lg`,仍切兩行;不允許水平捲動
|
||
- 螢幕閱讀器:`aria-label` 給完整字串,但文字節點用分組避免一字一念
|
||
|
||
---
|
||
|
||
## 3. 三步式 Stepper
|
||
|
||
使用既有視覺語彙,以 Tabs 或 Stepper UI 呈現。**建議使用 Stepper**(因為步驟有順序依賴)。
|
||
|
||
### 3.1 視覺
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ ← 返回 │
|
||
│ │
|
||
│ 配對新裝置 │
|
||
│ 讓你的 Kneron 裝置連上雲端,就能從任何地方遠端操作 │
|
||
│ │
|
||
│ ●──────────────────●──────────────────○ │
|
||
│ 1 2 3 │
|
||
│ 取得 Token 設定 Local Agent 確認連線 │
|
||
│ │
|
||
│ [當前步驟內容] │
|
||
│ │
|
||
│ [上一步] [下一步] │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 3.2 Stepper 規格
|
||
|
||
- 步驟指示器:`flex items-center gap-2`,使用 Lucide `Circle` / `CheckCircle`
|
||
- 已完成:`bg-primary text-primary-foreground` + `CheckCircle` 填色
|
||
- 當前:`ring-2 ring-primary bg-background`
|
||
- 未完成:`bg-muted text-muted-foreground`
|
||
- 步驟間連線:`h-0.5 bg-muted`(已完成段落 `bg-primary`)
|
||
- 下方步驟標題:`text-sm font-medium`(已完成/當前)、`text-muted-foreground`(未完成)
|
||
|
||
### 3.3 底部按鈕
|
||
|
||
- 上一步:`variant=outline`,第 1 步 disabled
|
||
- 下一步:`variant=default`,第 3 步改為「完成 → 進入裝置列表」
|
||
|
||
---
|
||
|
||
## 4. Step 1 — 取得 Token
|
||
|
||
### 4.1 版型
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────┐
|
||
│ Step 1 · 取得 Pairing Token │
|
||
│ │
|
||
│ 複製下方 token,在 Step 2 讓 local agent 使用這組 token 連線雲端 │
|
||
│ │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ 🔗 你的 Pairing Token │ │
|
||
│ │ │ │
|
||
│ │ ┌──────────────────────────────────────────────────┐ │ │
|
||
│ │ │ vAc_a1b2c3d4e5f6a7b8 │ │ │
|
||
│ │ │ c9d0e1f2a3b4c5d6e7f8 │ │ │
|
||
│ │ └──────────────────────────────────────────────────┘ │ │
|
||
│ │ (視覺切兩行,複製永遠是完整 36 字元無空格) │ │
|
||
│ │ │ │
|
||
│ │ [📋 複製] [🔄 重新產生] │ │
|
||
│ │ │ │
|
||
│ │ ⏱ 剩餘 14:52 ─────────────────────── │ │
|
||
│ │ 進度條(bg-primary,隨時間變 amber → red) │ │
|
||
│ │ 📅 產生時間:14:30 │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ ⚠ 這組 token 15 分鐘內有效,請立刻到 Step 2 完成配對 │
|
||
│ token 是一次性使用,完成配對後自動失效 │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 4.2 主要元件
|
||
|
||
- `PairingTokenCard`(見 `components.md` 10.2)— 含倒數計時器
|
||
- 下方安全提示:`Callout` 樣式(`bg-amber-50 border-amber-300`,或用 Alert 元件)
|
||
|
||
### 4.3 初始狀態
|
||
|
||
- 進入頁面自動呼叫 `POST /api/pairing/token` 產生新 token(`vAc_` + 32 hex,TTL 15 分鐘)
|
||
- 客戶端啟動 1 秒一次的倒數計時(從 `expiresAt - now()` 算起),不 polling 後端
|
||
- 若 API 失敗:顯示 error state 「無法產生 token,請重試」+ 重試按鈕
|
||
|
||
### 4.4 倒數計時器視覺規格
|
||
|
||
TTL 從 72 小時降到 15 分鐘,倒數計時器要**顯著且突出**,讓使用者意識到要馬上行動:
|
||
|
||
| 剩餘時間 | 視覺 | 行為 |
|
||
|---------|------|------|
|
||
| > 10:00 | `text-foreground` + 進度條 `bg-primary` | 正常顯示 |
|
||
| 10:00 – 3:00 | `text-amber-600` + 進度條 `bg-amber-500` | 文字變粗 `font-medium` |
|
||
| 3:00 – 0:30 | `text-red-600` + 進度條 `bg-red-500` + 卡片 `ring-1 ring-red-300` | 計時文字前加 ⚠;建議配 `prefers-reduced-motion` 尊重,不閃爍 |
|
||
| ≤ 0:30 | 同上 + Toast「Token 即將過期,請立刻完成或重新產生」 | 只 Toast 一次 |
|
||
| 00:00 | Token 轉灰 `text-muted-foreground line-through`;複製按鈕 disabled;顯示「此 token 已過期,請重新產生」 | `aria-live="assertive"` 宣告 |
|
||
|
||
**格式**:`mm:ss`(例:`14:52`、`02:17`、`00:08`);不要顯示小時,15 分鐘內絕不超過 15:00。
|
||
|
||
### 4.5 互動行為
|
||
|
||
| 操作 | 行為 |
|
||
|------|------|
|
||
| 點「複製」| 呼叫 `navigator.clipboard.writeText(token)` 複製**完整 36 字元無空格**字串;按鈕暫態變「已複製 ✓」2 秒;toast「Token 已複製到剪貼簿,15 分鐘內有效」|
|
||
| 點「重新產生」| 開 AlertDialog:「確定要重新產生?舊 token 將立即失效,新 token 有效期 15 分鐘。」→ 確認後 POST API,更新 UI,重啟倒數 |
|
||
| Token 過期(0:00)| 自動將 UI 切至過期狀態;主 CTA 從「下一步」改為「重新產生 token」|
|
||
| 進入 Step 2 前 | 檢查使用者是否已複製(用 state)。未複製則禁止下一步,提示「請先複製 token」或允許繼續但 toast warning |
|
||
|
||
### 4.6 i18n key
|
||
|
||
```
|
||
pairing.step1.title → Step 1 · 取得 Pairing Token
|
||
pairing.step1.description → 複製下方 token,15 分鐘內到 Step 2 完成配對
|
||
pairing.token.title → 你的 Pairing Token
|
||
pairing.copy → 複製
|
||
pairing.copied → 已複製
|
||
pairing.regenerate → 重新產生
|
||
pairing.timeRemaining → 剩餘 {time}
|
||
pairing.expiresIn15min → 15 分鐘內有效
|
||
pairing.generatedAt → 產生時間:{time}
|
||
pairing.security.warning → 這組 token 15 分鐘內有效,請立刻到 Step 2 完成配對
|
||
pairing.security.oneTime → token 是一次性使用,完成配對後自動失效
|
||
pairing.regenerateConfirm.title → 確定要重新產生?
|
||
pairing.regenerateConfirm.description → 舊 token 將立即失效,新 token 有效期 15 分鐘
|
||
pairing.toast.copied → Token 已複製到剪貼簿,15 分鐘內有效
|
||
pairing.toast.generateFailed → 無法產生 token,請重試
|
||
pairing.toast.expiringSoon → Token 即將過期,請立刻完成或重新產生
|
||
pairing.token.expired.label → 此 token 已過期,請重新產生
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Step 2 — 設定 Local Agent
|
||
|
||
### 5.1 版型
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────┐
|
||
│ Step 2 · 設定 Local Agent │
|
||
│ │
|
||
│ 在你的電腦下載並啟動 local agent,讓它連上雲端 │
|
||
│ │
|
||
│ 選擇作業系統: │
|
||
│ [ macOS ] [ Windows ] [ Linux ] │
|
||
│ ▲ active │
|
||
│ │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ 1. 下載 local agent │ │
|
||
│ │ [📥 下載 visionA-local-agent-macos.dmg] │ │
|
||
│ │ │ │
|
||
│ │ 2. 安裝並啟動 │ │
|
||
│ │ 打開 DMG,拖曳到 Applications,雙擊啟動 │ │
|
||
│ │ │ │
|
||
│ │ 3. 輸入 Pairing Token │ │
|
||
│ │ 在 local agent 的「雲端」設定頁貼上 token │ │
|
||
│ │ │ │
|
||
│ │ 或使用命令列(CLI 進階使用者): │ │
|
||
│ │ ┌──────────────────────────────────────────────────┐ │ │
|
||
│ │ │ visiona-agent --pair-token=\ │ │ │
|
||
│ │ │ vAc_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8 │ │ │
|
||
│ │ └──────────────────────────────────────────────────┘ │ │
|
||
│ │ (複製時為完整單行無反斜線) │ │
|
||
│ │ │ │
|
||
│ │ 4. 連線成功後,回到這個頁面進入 Step 3 │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 💡 已經有 local agent?[跳到 Step 3] │
|
||
└──────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 5.2 作業系統分頁
|
||
|
||
使用 `Tabs` 元件,三個 tab:`macOS` / `Windows` / `Linux`,自動偵測 `navigator.userAgent` 設預設。
|
||
|
||
**平台差異:**
|
||
|
||
| OS | 下載檔案 | 安裝步驟 | 命令列 |
|
||
|----|---------|---------|--------|
|
||
| macOS | `.dmg` | 拖曳到 Applications | `visiona-agent --pair-token=vAc_...` |
|
||
| Windows | `.exe` installer | 雙擊執行 | `visiona-agent.exe --pair-token=vAc_...` |
|
||
| Linux | `.AppImage` | `chmod +x` 後執行 | `./visiona-agent --pair-token=vAc_...` |
|
||
|
||
### 5.3 指令區塊
|
||
|
||
- 使用 `bg-muted font-mono text-sm p-3 rounded-md` 樣式
|
||
- 右上角有「複製」小按鈕
|
||
- 將使用者 token 自動嵌入指令(`--pair-token=[當前 token]`)
|
||
|
||
### 5.4 互動
|
||
|
||
| 操作 | 行為 |
|
||
|------|------|
|
||
| 切換 OS Tab | 內容重新渲染 |
|
||
| 點「下載」按鈕 | 直接下載對應 OS 的 installer |
|
||
| 點指令「複製」| 複製整行 `visiona-agent --pair-token=vAc_xxxx…`(完整 36 字元 token,單行無跳行)|
|
||
| 「已經有 local agent?」| 直接跳 Step 3 |
|
||
|
||
### 5.5 i18n key
|
||
|
||
```
|
||
pairing.step2.title → Step 2 · 設定 Local Agent
|
||
pairing.step2.description → 在你的電腦下載並啟動 local agent...
|
||
pairing.step2.selectOS → 選擇作業系統
|
||
pairing.step2.download → 下載 local agent
|
||
pairing.step2.install → 安裝並啟動
|
||
pairing.step2.installHint.macos → 打開 DMG,拖曳到 Applications...
|
||
pairing.step2.installHint.windows → 雙擊 installer...
|
||
pairing.step2.installHint.linux → chmod +x 後執行...
|
||
pairing.step2.enterToken → 輸入 Pairing Token
|
||
pairing.step2.tokenHint → 在 local agent 的「雲端」設定頁貼上 token
|
||
pairing.step2.orCli → 或使用命令列(CLI 進階使用者):
|
||
pairing.step2.waitConnect → 連線成功後,回到這個頁面進入 Step 3
|
||
pairing.step2.alreadyHaveAgent → 已經有 local agent?[跳到 Step 3]
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Step 3 — 確認連線
|
||
|
||
### 6.1 視覺(等待中)
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────┐
|
||
│ Step 3 · 確認連線 │
|
||
│ │
|
||
│ ⏳ 等待 local agent 連線... │
|
||
│ │
|
||
│ 已等待 0:15(最長 3 分鐘) │
|
||
│ │
|
||
│ [取消] [查看 Troubleshooting] │
|
||
│ │
|
||
│ 提示: │
|
||
│ • 確認 local agent 已啟動 │
|
||
│ • 確認 token 正確無誤 │
|
||
│ • 確認你的網路可以連到 cloud.visiona.ai │
|
||
└──────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 6.2 視覺(成功)
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────┐
|
||
│ Step 3 · 確認連線 │
|
||
│ │
|
||
│ ✓ 已成功連線! │
|
||
│ │
|
||
│ 檢測到的裝置: │
|
||
│ ┌────────────────────────────────────┐ │
|
||
│ │ 🔌 Kneron KL520 │ │
|
||
│ │ Firmware 2.3.1 · Host: office-mac│ │
|
||
│ └────────────────────────────────────┘ │
|
||
│ │
|
||
│ [進入裝置列表 →] │
|
||
└──────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 6.3 視覺(失敗 / 超時)
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────┐
|
||
│ Step 3 · 確認連線 │
|
||
│ │
|
||
│ ⚠ 連線超時 │
|
||
│ │
|
||
│ 超過 3 分鐘沒收到 local agent 連線 │
|
||
│ │
|
||
│ 可能原因: │
|
||
│ • local agent 尚未啟動 │
|
||
│ • token 輸入錯誤 │
|
||
│ • 防火牆擋住 WebSocket 連線 │
|
||
│ │
|
||
│ [重新檢查] [回到 Step 2] [查看完整說明] │
|
||
└──────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 6.4 行為
|
||
|
||
- 進入 Step 3 自動開始 polling `/api/pairing/status?token=xxx`(每 3 秒)
|
||
- 計時器顯示已等待時間
|
||
- 成功(`status: connected`):停止 polling,顯示成功畫面 + 裝置資訊
|
||
- 超時(> 3 分鐘):停止 polling,顯示失敗畫面
|
||
- 「取消」:返回 `/devices`,token 保留(使用者可稍後重試)
|
||
- 「重新檢查」:重啟 polling
|
||
|
||
### 6.5 i18n key
|
||
|
||
```
|
||
pairing.step3.title → Step 3 · 確認連線
|
||
pairing.step3.waiting → 等待 local agent 連線...
|
||
pairing.step3.elapsed → 已等待 {time}(最長 3 分鐘)
|
||
pairing.step3.cancel → 取消
|
||
pairing.step3.troubleshooting → 查看 Troubleshooting
|
||
pairing.step3.hints.title → 提示:
|
||
pairing.step3.hints.running → 確認 local agent 已啟動
|
||
pairing.step3.hints.token → 確認 token 正確無誤
|
||
pairing.step3.hints.network → 確認你的網路可以連到 cloud.visiona.ai
|
||
pairing.step3.success → 已成功連線!
|
||
pairing.step3.success.detected → 檢測到的裝置:
|
||
pairing.step3.success.continue → 進入裝置列表 →
|
||
pairing.step3.failure.timeout → 連線超時
|
||
pairing.step3.failure.reason → 超過 3 分鐘沒收到 local agent 連線
|
||
pairing.step3.failure.causes → 可能原因:
|
||
pairing.step3.failure.retry → 重新檢查
|
||
pairing.step3.failure.backToStep2 → 回到 Step 2
|
||
pairing.step3.failure.docs → 查看完整說明
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 邊界情境
|
||
|
||
### 7.1 Pairing Token 過期(15 分鐘後)
|
||
|
||
- 進入 Step 3 polling 時若收到 `status: expired` → 顯示「Token 已過期」+ 「回到 Step 1 重新產生」
|
||
- Step 1 若使用者停留超過 15 分鐘未下一步,倒數歸零 UI 會自動切到過期狀態(見 4.4)
|
||
- **注意**:這裡過期的是 Pairing Token(15 分鐘)。Local agent 一旦換到 Session Token(90 天),後續連線不受影響,使用者看不到這層
|
||
|
||
### 7.2 同一 token 被多次使用
|
||
|
||
- Architect 端決策:token 應該是**一次性**的(綁第一個連上的 local agent)
|
||
- 後續若同 token 被其他 agent 嘗試連線 → Step 3 polling 顯示「此 token 已被其他裝置使用」
|
||
|
||
### 7.3 網路中斷(polling 失敗)
|
||
|
||
- 顯示臨時錯誤 + 自動重試(指數退避)
|
||
- 3 次失敗後提示「網路不穩,請檢查連線」
|
||
|
||
### 7.4 頁面離開 / 重新整理
|
||
|
||
- 若 token 已產生但未完成連線:重新進入頁面應該偵測到並回到 Step 3(或重回 Step 1 重新產)
|
||
- 使用 URL query param `?token=xxx` 保存進行中的 token
|
||
|
||
### 7.5 多裝置一次配對
|
||
|
||
- Phase 0:一次只配對一個裝置(一個 token 對一台 agent / 一台 host)
|
||
- Phase 1:考慮支援一台 host 多張 Kneron 卡(agent 端回報多裝置)
|
||
|
||
---
|
||
|
||
## 8. 成功後的導航
|
||
|
||
完成配對後:
|
||
|
||
1. 在 `/devices` 列表看到新裝置(`RemoteDeviceBadge` = 在線)
|
||
2. Toast:「裝置 Kneron KL520 已成功配對」
|
||
3. Activity Timeline 新增一筆 `device_paired` 紀錄
|
||
|
||
---
|
||
|
||
## 9. 給 Architect / Backend 的 API 契約提議
|
||
|
||
### 9.1 `POST /api/pairing/token`
|
||
|
||
Pairing Token:`vAc_` 前綴 + 32 字元 hex,TTL 15 分鐘,一次性使用。
|
||
|
||
```json
|
||
Request: (需 auth,雛形可 skip auth)
|
||
Response 200:
|
||
{
|
||
"token": "vAc_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8",
|
||
"expiresAt": "2026-04-21T14:45:00Z",
|
||
"createdAt": "2026-04-21T14:30:00Z",
|
||
"ttlSeconds": 900
|
||
}
|
||
```
|
||
|
||
Session Token(使用者看不到,雲端 ↔ local agent 內部):TTL 90 天,Pairing Token 成功換取後發給 local agent。此層 UI 無關,僅記錄備查。
|
||
|
||
### 9.2 `GET /api/pairing/status?token=xxx`
|
||
|
||
```json
|
||
Response 200:
|
||
{
|
||
"status": "pending" | "connected" | "expired" | "used",
|
||
"device": {
|
||
"id": "kl520-usb-0001",
|
||
"name": "Kneron KL520",
|
||
"type": "KL520",
|
||
"firmwareVersion": "2.3.1",
|
||
"hostName": "office-mac"
|
||
} | null,
|
||
"pairedAt": "2026-04-21T14:35:00Z" | null
|
||
}
|
||
```
|
||
|
||
### 9.3 `DELETE /api/pairing/token/:token`
|
||
|
||
重新產生時,先刪除舊的。
|
||
|
||
### 9.4 `POST /api/devices/:id/unpair`
|
||
|
||
解除配對(從 `/devices/[id]` 的 DeviceSettingsCard 或 `/account` 觸發)。
|
||
|
||
---
|
||
|
||
## 10. 無障礙檢查
|
||
|
||
- Stepper:`role="list"` + 每個 step `role="listitem"` + 當前 step `aria-current="step"`
|
||
- Token 顯示:`aria-label="Pairing token, {token}"`(但不念出字元)
|
||
- 複製按鈕:`aria-live="polite"` 宣告「已複製」
|
||
- Step 3 等待:`aria-live="polite"` 宣告 status 變更
|
||
- 所有按鈕可 Tab 聚焦、Enter / Space 觸發
|
||
- 錯誤訊息:`role="alert"`
|
||
|
||
---
|
||
|
||
## 11. TODO
|
||
|
||
| 項目 | 時機 |
|
||
|------|------|
|
||
| Local agent UI 的「雲端」分頁設計(接收 token 的那端)| Phase 0 同步設計(需跨 local-tool,另開需求)|
|
||
| ~~Token 過期警告~~ → 已納入 Phase 0(見 4.4 倒數計時器,因 TTL 降至 15 分鐘必做)| — |
|
||
| 支援 Email 發送 token(方便跨裝置)| Phase 2 |
|
||
| QR Code 配對(手機掃描)| Phase 2 |
|
||
| 一次性 pairing code(更短 6 位數字,UX 更好)| Phase 2 |
|