` 包進度文字(不用 `aria-live="assertive"`、避免每秒朗讀) |
| 進度條 | `
` |
| 失敗 modal | `role="alertdialog"`(比 dialog 更強的語意、screen reader 會主動朗讀) |
| 鍵盤導航 | Tab 順序:分頁切換 → 第 1 張卡片的升級按鈕 → 第 1 張卡片的版本切換按鈕 → 第 2 張卡片… |
| Focus ring | 沿用 `ring.2 · color.ring`、2px outline-offset |
| 色彩對比 | FW badge 紅 / 黃 / 綠對白色文字皆 ≥ 4.5:1(critical 信號不妥協) |
| 觸控目標 | 升級按鈕、版本切換按鈕、⚙ icon 全部 ≥ 44×44px tap area(即使視覺更小、padding 補足) |
| Reduced motion | `prefers-reduced-motion: reduce` → 進度條改靜態顯示百分比文字、modal 動畫 0ms、卡片高亮 1s 改為直接最終色(不淡入淡出) |
---
## 11. Design Tokens 沿用 / 新增
### 11.1 沿用既有 tokens(`spec/07-design-tokens.md`)
所有色彩、字級、間距、圓角、elevation、focus ring 全部沿用 v1 既有 token。
具體沿用的 semantic token:
- `color.destructive` / `color.warning` / `color.success` / `color.info`
- `color.muted` / `color.muted-foreground` / `color.foreground`
- `color.card` / `color.background` / `color.border`
- `color.primary` / `color.primary-foreground`
- `color.ring`
- `radius.md` / `radius.lg` / `radius.full`
- `space.2` ~ `space.8`
- `font.size.xs` / `sm` / `base` / `lg`
- `font.weight.medium` / `semibold`
- `font.family.mono`(技術資訊區用)
### 11.2 新增 component-level tokens(本檔提案)
只在「需要」時新增、避免過度膨脹 token 系統:
| 新 token | 推導自 | 用途 |
|---------|-------|------|
| `color.fw-badge.current.bg` | `color.success` | FW badge 綠底 |
| `color.fw-badge.current.fg` | `color.background`(白) | FW badge 綠底文字 |
| `color.fw-badge.older.bg` | `color.warning` | FW badge 黃底 |
| `color.fw-badge.older.fg` | `color.foreground` | FW badge 黃底文字(黑、確保對比) |
| `color.fw-badge.legacy.bg` | `color.destructive` | FW badge 紅底 |
| `color.fw-badge.legacy.fg` | `color.background`(白) | FW badge 紅底文字 |
**為什麼要拆 component token**:
- Light / Dark 模式下,warning 黃底配什麼前景需獨立調(直接用 `color.warning-foreground` 可能對比不足)
- 未來如果調 badge 視覺、不需要動 semantic token 影響其他元件
**推導表(Light / Dark)**:
| Token | Light value | Dark value | 對比比率(對 fg) |
|-------|------------|-----------|----------------|
| `color.fw-badge.current.bg` | `oklch(0.65 0.17 145)` | `oklch(0.75 0.17 145)` | 4.7 : 1 |
| `color.fw-badge.current.fg` | `oklch(1 0 0)` | `oklch(0.145 0 0)` | — |
| `color.fw-badge.older.bg` | `oklch(0.75 0.18 85)` | `oklch(0.80 0.18 85)` | 5.2 : 1 |
| `color.fw-badge.older.fg` | `oklch(0.145 0 0)` | `oklch(0.145 0 0)` | — |
| `color.fw-badge.legacy.bg` | `oklch(0.577 0.245 27.325)` | `oklch(0.704 0.191 22.216)` | 4.8 : 1 |
| `color.fw-badge.legacy.fg` | `oklch(1 0 0)` | `oklch(0.145 0 0)` | — |
> **對比比率實測責任**(v2.2 三方互審後對齊):
>
> 表中 4.7:1 / 5.2:1 / 4.8:1 為 Design 在 oklch 色彩空間的**推算值**、提供給後續實作 / 驗收作參考。
>
> **實測為 M9-12 Frontend Agent 責任**:M9-12 Frontend 在落地 6 個 component token 到 `frontend/src/app/globals.css` 後、於 Design QA 階段用 axe-core / Lighthouse / Chrome DevTools contrast checker 工具驗證真實對比 ≥ 4.5:1(WCAG AA)、特別需注意 Dark 模式下 `legacy.fg` 黑底紅 `oklch(0.704 0.191 22.216)` 配 `oklch(0.145 0 0)` 文字。實測未達標時、Frontend 與 Design 對齊調整 token 數值。
>
> **此項不需 Architect 互審回應**——是 implement-time verification、不是 design-time decision。
---
## 12. R-FW 風險的 Design 對策
### 12.1 R-FW-11:一般使用者誤觸降版 brick 風險
依 architect 42 §6 風險評估、Design 提供多層 mitigation:
| 風險路徑 | Design 緩解措施 | 對應 §章節 |
|---------|--------------|----------|
| 點到「版本切換」就直接降 | 二次確認 modal、需輸入「DOWNGRADE」字串 | §6.1 |
| 沒讀風險警告就降 | 風險列表大字、`color.warning` 背景區塊、KDP1 額外紅色 banner | §6.1 §6.2 |
| 降到 KDP1 後發現功能不可用 | KDP1 額外警告語、明示「不支援多模型」 | §6.2 |
| 降版進行中拔 USB | 全螢幕 hover 攔截 + 紅色 banner「永久損毀」 + 不可關閉 modal | §6.3 |
| 降版進行中關 app | 同上、加上 `beforeunload` event handler 攔截(Frontend 實作) | §6.3 + 給 Frontend 提示 |
| 升錯版本當降版 | Architect 42 §2.4 driver 層 guard:拒絕目標版本 >= current(這是後端職責) | UI 不需處理、driver 拒絕後顯示「無效操作」error modal |
| 找不到救援路徑 | 失敗 modal 提供「取得協助」連結 + 「複製錯誤訊息」給技術支援 | §7.2 |
### 12.2 R-FW-11.5(Design 自提):使用者輸入「downgrade」小寫繞過
依 §6.1,input 嚴格 case-sensitive 比對字面 `DOWNGRADE`、小寫 / 全形 / 半形 / 空白都不接受。
**Frontend 實作提示**:用 `event.target.value === 'DOWNGRADE'`(嚴格相等)、不要用 `.toUpperCase()` 後比對。
### 12.3 R-FW-11.6(Design 自提):意外觸發 deep-link 跳轉
從 Devices 頁的 ⚙ icon deep-link 到 Settings → 韌體後、**不自動展開「版本切換」accordion**——只 highlight 卡片邊框 600ms。
**理由**:deep-link 對應的是「使用者想關注此裝置的韌體狀態」、不是「使用者已決定要降版」。展開 accordion 等於暗示「快來降版」、與整體謹慎策略矛盾。
---
## 13. 與既有 design v2.1 的銜接點
### 13.1 與 `v2/settings-update.md` 的銜接
- Settings 分頁結構從 4 變 5、第 3 個分頁新增「韌體」
- v2.1 既有的「一般」「硬體」「模型」「進階」內容**不變**、只是順序調整
- 本檔不重寫 settings-update.md、但 settings-update.md 應在下次補丁加註「分頁順序見 firmware-management.md §2」
- **Settings 整體分頁切換高度**:保持與既有分頁一致(依 `spec/03-wireframes.md §3.X Settings` 既定高度),新分頁內容若超出視窗高度則加 scroll(不擴張 Settings 整體高度)
### 13.2 與 `spec/03-wireframes.md §3.3 Devices` 的銜接
- Devices 卡片現有結構 5 行(標題 / status / FW / kn / button)保持
- FW 那行從純文字 `FW 2.1.0` 改為 `FW [● v2.2.0]` pill badge(+ 黃/紅時加 ⚙ icon)
- pill badge 寬度依版本字串自適應、但 FW 行整體高度不變(仍 18px)
- 點 badge / ⚙ 行為見 §4.4
### 13.3 與 `v2/control-panel.md` 的銜接
控制台**不涉及 FW 管理**——FW 管理在瀏覽器端 Settings、不在控制台。
- 升級 / 切換 modal 的 dialog 不會在控制台顯示
- 但升級 / 切換的 log(後端 stage 訊息)會出現在控制台 log panel(INFO / WARN / ERROR)
- log 等級依 architect 30 §M9-3 設計、Design 不重複定
### 13.4 與 `spec/08-states.md`(全域錯誤分級)的銜接
韌體升級 / 切換失敗的 **嚴重級別屬於 Error**(08 表的 `Error` 級別、非 Critical):
- 不擋整個 app
- 顯示 modal、可關閉
- 提供重試 + 排錯提示
- 對應 08 §8.3 inline error 規格、但因為涉及裝置操作、用 modal 而非 inline
---
## 14. v2.1 → v2.2 索引變更摘要(給 design-spec-v2.md)
### 14.1 索引變更
在 `design-spec-v2.md` §文件結構 表格、加一行:
```markdown
| **v2.7** | **韌體管理**(v2.2 新增) | **`v2/firmware-management.md`** | **Kneron dongle FW 升級 + 版本切換完整規格:Settings 新分頁、Devices 頁 FW badge、二次確認流程、51 個 i18n keys、R-FW-11 設計緩解** |
```
### 14.2 版本標頭變更
- 版本:`v2.1` → `v2.2`
- 子標題增補:「v2.2(2026-05-24 補丁)」吸收 R5-Q9 翻案 + B2 階段降版面向一般使用者的設計規格
### 14.3 「v2 → v2.2 差異總覽」表格新增段
```markdown
## v2.1 → v2.2 差異總覽(2026-05-24 補丁)
v2.2 是吸收 R5-Q9 翻案後的補丁,新增 FW 管理面向一般使用者的設計規格。
| 面向 | v2.1 | v2.2(2026-05-24 補丁)| 來源 |
|------|------|---------------------|------|
| Settings 分頁數 | 4(一般 / 硬體 / 模型 / 進階)| **5**(一般 / 硬體 / **韌體** / 模型 / 進階)| R5-Q9 + architect 42 |
| Devices 頁 FW 顯示 | 純文字 `FW 2.1.0` | **pill badge**(紅 / 黃 / 綠三色)+ deep-link ⚙ icon | R5-Q9 第 5 點 |
| FW 升級 UX | 未設計 | **單步驟確認 + 進度 modal**(不可中斷)| architect 30 §M9-4 |
| FW 降版 UX | 未設計 | **二次確認**(輸入「DOWNGRADE」字串)+ 進度 modal + 全螢幕 hover 攔截 | architect 42 §5.3 |
| 失敗復原 UX | 未設計 | **8 種失敗類型對應 friendly message + 復原行動** | architect 42 §5.5 |
| 新增 i18n keys | — | **51 keys**(zh-TW + en)| 本檔 §9 |
| 新增 component tokens | — | **6 個 fw-badge token** | 本檔 §11.2 |
```
### 14.4 「給 Orchestrator 的問題(懸而未決)」新增
```markdown
**v2.2 新增懸而未決**:
4. **降版 modal 字串「DOWNGRADE」未來 i18n 化的處理**:當前 Design 規格要求使用者輸入字面字串 `DOWNGRADE`(en),中文使用者也輸入這個字。若未來改為 i18n(如中文使用者輸入「降版」),需與 Architect / Frontend 確認後端 confirmToken 是否同步調整(目前 architect 42 §2.3 後端固定接受 `confirmToken: "DOWNGRADE"`)。建議**短期維持英文字串**(跨語言一致、避免後端多語對應)、長期看是否分語系 token。
5. **bundled 版本清單的「發布日期」資料源**:§3.3 範例顯示「2024-08 發行」等文案,但目前 architect 42 §2.1 `FirmwareVersion.ReleaseDate` 為 optional。需 Backend 在 bundle firmware 時準備 metadata(每個 version 目錄附 `META.json` 含 releaseDate / notes)。如果 metadata 缺、UI fallback 為不顯示日期、只顯示版本號。
6. ~~**降版進行中關閉 Wails 控制台視窗會發生什麼**~~ **(已解決、v2.2 三方對齊)**:依 R5-2 控制台關閉 = 結束 server。降版進行中關控制台 = 中斷降版 = 可能 brick。**解法(三方對齊)**:(a) Architect 在 TDD §8.6 補 server graceful shutdown 拒絕邏輯(偵測 active firmware task → 拒絕 shutdown → 通知 Wails 控制台);(b) Design 在 `v2/control-panel.md` 補對應 UI——降版進行中按關閉視窗 → 跳警告 modal「韌體更新進行中、強制關閉會造成裝置損毀」+ 預估剩餘時間 + 兩個按鈕(「繼續等待」主、「強制關閉」destructive)。
```
---
## 15. 給 Orchestrator 派 PM / Architect 互審的注意點
### 15.1 派 PM 互審重點
- **驗 PRD 是否需要新增章節**:R5-Q9 翻案後、PRD-v2 應有對應 §「Firmware 管理 v2.2 補丁」、Design 已對齊 architect 30 §M9-0 PM 任務、但 PM 是否實際補了 PRD 是 Orchestrator 應追蹤的點
- **驗 user story 覆蓋**:本檔 §1 列了 4 種使用者降版情境(architect 42 §1.1 取出)、PM 應檢查是否與 PRD 既有 user story 相容、是否需要新增 user story「進階使用者切換 FW 版本」
- **驗 UI 用語**:Design 採用「韌體 / 版本切換」中性詞、不用「降版」對 user-facing UI。PM 確認此用語策略與 PRD 整體 product voice 一致
- **驗成功指標**:本功能的 PRD 是否定了 success metric(如「90% 升級成功率」「Brick 事件 < 0.1%」),Design 文件未涵蓋指標、但實作前 PM 應補
### 15.2 派 Architect 互審重點
- **§2.1 分頁順序**:Architect 是否覺得「韌體」放在「硬體」與「模型」之間是合理的(vs 放最後 / 進階)
- **§4.1 FW badge 配色**:Architect review §11.2 推導表的對比比率、特別是 Dark 模式下 `legacy.fg` 用黑底紅、需用 contrast checker 工具驗證真實對比
- **§6.1 「DOWNGRADE」嚴格比對**:Architect 42 §2.3 後端要求 `confirmToken: "DOWNGRADE"`、Design 對應 UI 強制使用者輸入字面字串、確認前後端規格一致
- **§7.1 失敗類型對應**:Design 列了 7 種失敗類型、對應 backend stage(`preparing / loading / flashing / verifying`)+ 兩個橫切性失敗(timeout / disconnect)+ `FirmwareProgress.Reason` 細分原因(見 TDD §3.4)。確認所有後端可能 throw 的 error 都有對應 friendly message、沒有遺漏
- **§8 狀態機**:v2.2 三方對齊後、stage 命名以 Design `preparing / loading / flashing / verifying` 為 source of truth、Architect TDD §4.3 對齊此命名
- **§11.2 token 命名**:`color.fw-badge.*` 命名是否符合 Architect / Frontend 對 token 階層的期望(vs 用 `color.status.firmware-*` 等替代方案)
- ~~**§14.4 懸而未決第 6 點**~~ **(已解)**:降版進行中關 Wails 控制台 = brick 風險。**v2.2 三方對齊後解法**:Architect TDD §8.6 補 server graceful shutdown 拒絕;Design 在 `v2/control-panel.md` 補 graceful shutdown 警告 modal UI。
### 15.3 互審回合預期(v2.2 補丁)
| 互審項 | 狀態 |
|--------|------|
| Architect §11.2 顏色對比實測值 | 已解:實測責任歸 M9-12 Frontend、Design 提供推算值參考(§11.2 備註) |
| Architect §8 狀態機名稱對齊 | 已解:三方統一採 `preparing / loading / flashing / verifying`(Design §5.3 §8 / TDD §4.3 / i18n keys 全對齊) |
| Architect graceful shutdown 拒絕邏輯 | 已解:TDD §8.6 + Design `v2/control-panel.md` graceful shutdown modal |
| PM user story 覆蓋 / 用語策略 / 成功指標 | PM 在下次 PRD 補丁處理(見 PM review)|
| §7.1 失敗復原 4 vs 8 對齊 | 已解:對齊 backend `FirmwareProgress.Reason`、TDD §3.4 補完整 mapping |
三方互審 v2.2 已收斂、本檔可進 M9-12 Frontend 實作。
---
## 16. 文件大小與拆檔策略
本檔 v2.2 修訂後 ~930 行(含表格、wireframe、i18n table、v2.2 互審吸收紀錄),已逼近原訂的 800 行拆檔門檻、但尚未跨越 1000 行強制拆檔門檻。
**判斷**:**v2.2 暫不拆**。理由:
- v2.2 主要新增是吸收三方互審後的「對齊紀錄」(stage 命名、reason mapping、graceful shutdown 解法),不是新增獨立章節
- 拆檔反而會讓「升級流程」「切換流程」「失敗復原」三個密切相關的章節分散
- §9 i18n keys 佔 ~140 行、本身是一張長表、拆出去也不會增加可讀性
- Frontend 實作時需要對照所有章節(從 IA 到 i18n),單檔較便利
**下次拆檔觸發**:若本檔超過 **1000 行**(如 KL630/KL730 特殊降版流程落地、或補新的失敗情境),則拆為:
- `firmware-management.md`(索引 + IA + 主流程,目標 ≤ 600 行)
- `firmware-i18n.md`(i18n keys 細表)
- `firmware-error-recovery.md`(失敗類型細表 + reason mapping)
---
**下一步**:
1. 更新 `design-spec-v2.md` 索引(§14.1 / §14.2 / §14.3 / §14.4)
2. Orchestrator 派 PM Agent 互審(依 §15.1)+ Architect Agent 互審(依 §15.2)
3. 互審通過後、本檔 + design-spec-v2.md 一起進 git
4. 進 M9-12 Frontend 實作前、Design 同步 confirm Architect 補 TDD `v2/device-firmware.md` 章節與本檔一致
---
## 變更紀錄
| 日期 | 版本 | 變更 | 作者 |
|------|------|------|------|
| 2026-05-24 | v2.2-draft | 初版(R5-Q9 翻案 + B2 階段降版設計)| Design Agent |
| 2026-05-25 | v2.2 | 吸收三方互審:(1) §5.3 / §8 / §9.6 / §9.8 stage 命名統一為 `preparing/loading/flashing/verifying`(A-MISMATCH-1);(2) §7.1 失敗類型對齊 backend `FirmwareProgress.Reason` 細分原因(A-MID-3);(3) §11.2 token 對比實測責任明示歸 M9-12 Frontend(A-MID-2);(4) §14.4 第 6 點 graceful shutdown 標已解、UI 落地至 `v2/control-panel.md`(A-MID-1);(5) §9 i18n keys 51 個(原 52 減 1);(6) §15.3 互審回合預期改為 v2.2 收斂狀態表 | Design Agent |