visionA/local-tool/.autoflow/03-design/v2/firmware-management.md
jim800121chen 46514d77d7 docs(local-tool): M9 — Kneron Dongle FW 偵測 + 升降版(A+B、翻案 R5-Q9)
L 級新功能、PRD/Design/TDD/ADR 三方協作 + 互審 + M9-6 SDK 雙驗證、總計 ~9000 行文件。

範圍:
- A 階段(MVP、5 人天):KL520 + KL720 自動升級 KDP1 → KDP2
- B 階段(10.5 人天):手動降版面向一般使用者 + KL630 / KL730 擴展
- 合計 15.5 人天、安裝包 +7MB(保守 bundle 策略)

關鍵決策:
- 翻案 R5-Q9(progress.md 第二輪使用者決策「韌體燒錄 flash → B 砍掉」)
- 跨平台用 KneronPLUS Python C API、不用 DFUT.exe
- 多版本目錄結構選 C metadata(firmware/<chip>/{version}/ + CURRENT_VERSION)
- Kneron firmware redistribution 授權與 R5-B4 預置模型同性質、發佈前評估

文件產出:
- PRD v2.2(PRD-v2.md 495 行 + features/feature-firmware-management.md 599 行)
- Design v2.2(firmware-management.md 948 行 + control-panel.md §6a graceful shutdown)
- TDD v2.2(v2/firmware-management.md 823 行 + ADR-001 218 行)
- 8 份 research(含 M9-6 弱驗證 + 強驗證、~3200 行)
- 3 份三方互審報告(PM/Design/Architect cross-review)

M9-6 強驗證重大發現(影響 B 階段):
- KL730 product_id 實際是 0x732(不是 0x0730)
- KL630/KL730 firmware 是 embedded Linux rootfs(不是 .bin、不同代設計)
- KneronPLUS Python 沒 update_kdp_firmware_from_files 公開 API、warrenchen 走 ctypes
- 不影響 A 階段、B 階段 M9-8 需 spike

下一步:派 backend M9-1 起跑(bridge.py handle_firmware_upgrade)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 07:40:56 +08:00

62 KiB
Raw Blame History

v2.7 — Kneron Dongle FW 管理(升級 + 版本切換)

本章對應 R5-Q9 翻案FW 管理面向一般使用者)+ Architect research 30-integration-plan §M9-2/3/4 + 42-manual-downgrade-for-end-users §5。 上層索引:../design-spec-v2.md 版本:v2.2 新增 · 建立日期2026-05-24 相關:

  • 架構參考:.autoflow/04-architecture/research-kl520-fw-management/30-integration-plan.md42-manual-downgrade-for-end-users.md
  • UI 銜接:v2/settings-update.md(新增分頁進這個檔的結構)、spec/03-wireframes.md §3.3 DevicesFW badge

1. 定位與職責

「韌體管理」是 Settings 內新增的第 5 個分頁,使用者在此:

  1. 看到每張 Kneron dongle 當前 FW 版本 + bundled 最新版的對照
  2. 升級到最新 FW一鍵動作、KL520 KDP1→KDP2 為主要場景)
  3. 切換 FW 版本(含降版)——進階使用者操作,多層 safety guard 保護
  4. 看升級 / 切換進度、失敗復原指引

這個分頁不做的事

  • 不做 device-level inference / model 操作(那是 Workspace 的事)
  • 不顯示非 Kneron 裝置
  • 不做 OTA / 線上版本更新(所有 FW 從安裝包內 bundleR5-Q9 決策)

為什麼是 Settings 分頁、不是 Devices 頁主流程

  • 降版屬於高風險操作(理論上可能 brick、不應放在使用者點擊頻率最高的 Devices 頁
  • 升級雖然低風險,但「升級」與「切換」介面共用同一套版本選單較自然
  • 對應 architect 42 §1.2 的 trade-off 分析

2. IA 整合Settings 分頁順序

v2/settings-update.md §1 的 4 分頁結構(一般 / 硬體 / 模型 / 進階)擴充為 5 分頁

Tab 順序 變更
一般 1 不變
硬體 2 不變
韌體 3 本檔新增
模型 4 順序後移
進階 5 順序後移

為什麼放在「硬體」與「模型」之間

  • 概念分組:硬體(裝置本身)→ 韌體(裝置韌體)→ 模型(裝置上跑的軟體資產),由低階到高階
  • 「硬體」分頁列出裝置掃描策略,使用者看完掃描設定後,自然會問「裝置韌體呢」
  • 進階分頁仍放最後(不變)

2.1 分頁標籤文案

Key zh-TW en
settings.tabs.firmware 韌體 Firmware

用詞警告:分頁名稱不能叫「降版」——對一般使用者過於負面。一律稱「韌體」或「韌體管理」。「版本切換」是進階操作的中性說法。


3. 頁面結構Wireframe

3.1 整體佈局(韌體分頁主畫面)

預設狀態(有偵測到 2 張 dongle、其中 KL520 有可升級的版本):

┌─ Settings > 韌體 ───────────────────────────────────────────────────┐
│                                                                       │
│  韌體管理                                                             │
│  管理已連接 Kneron 裝置的韌體版本。                                   │
│                                                                       │
│  ─────────────────────────────────────────────────────────────       │
│                                                                       │
│  ┌─ KL520 #1 ─────────────────────────────────────────────────┐     │
│  │                                            kn_number:        │     │
│  │  ●  KDP1 (legacy)                          0x1A2B3C4D        │     │
│  │     建議升級到 KDP2 v2.2.0                                   │     │
│  │                                                                │     │
│  │  當前版本KDP1                                               │     │
│  │  最新版本KDP2 v2.2.0 (建議)                                 │     │
│  │                                                                │     │
│  │  [ 升級到 KDP2 v2.2.0 ]    [ 版本切換 ▾ ]                    │     │
│  └────────────────────────────────────────────────────────────┘     │
│                                                                       │
│  ┌─ KL720 #1 ─────────────────────────────────────────────────┐     │
│  │                                            kn_number:        │     │
│  │  ●  KDP2 v2.2.0 (current)                  0x5E6F7890        │     │
│  │     裝置使用最新韌體                                          │     │
│  │                                                                │     │
│  │  當前版本KDP2 v2.2.0                                        │     │
│  │  最新版本KDP2 v2.2.0                                        │     │
│  │                                                                │     │
│  │  [ 版本切換 ▾ ]                                              │     │
│  └────────────────────────────────────────────────────────────┘     │
│                                                                       │
│  ⓘ 沒看到裝置?檢查 USB 連接後到「硬體」分頁重新掃描。               │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

配色解讀(裝置卡片左側圓點)

圓點顏色 條件 文字標籤
🔴 color.destructive KDP1 / legacy FW KDP1 (legacy)
🟡 color.warning 有可用較新版本 KDP2 v2.1.0 (older)
🟢 color.success 已是最新 bundled 版本 KDP2 v2.2.0 (current)

3.2 空狀態(無 dongle 連接)

┌─ Settings > 韌體 ───────────────────────────────────────────────────┐
│                                                                       │
│  韌體管理                                                             │
│                                                                       │
│  ┌──────────────────────────────────────────────┐                   │
│  │                                              │                   │
│  │              🔌                              │                   │
│  │                                              │                   │
│  │       尚未偵測到 Kneron 裝置                  │                   │
│  │                                              │                   │
│  │   插上 USB 裝置後,到「硬體」分頁點擊         │                   │
│  │   「重新掃描」便會出現在這裡。                │                   │
│  │                                              │                   │
│  │           [ 前往硬體分頁 ]                    │                   │
│  │                                              │                   │
│  └──────────────────────────────────────────────┘                   │
│                                                                       │
└───────────────────────────────────────────────────────────────────────┘

3.3 「版本切換」展開後accordion 樣式、不是 dropdown

版本切換 ▾ 後、卡片下半部展開:

┌─ KL520 #1 ─────────────────────────────────────────────────────────┐
│  ●  KDP2 v2.2.0 (current)                       kn_number: 0x...    │
│     裝置使用最新韌體                                                  │
│                                                                       │
│  當前版本KDP2 v2.2.0                                                │
│  最新版本KDP2 v2.2.0                                                │
│                                                                       │
│  [ 版本切換 ▴ ]                                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ ⚠  切換到舊版可能導致:                                       │   │
│  │      • 部分新版 .nef 模型無法載入                              │   │
│  │      • 推論效能與穩定性下降                                    │   │
│  │      • KDP1 無法執行多模型載入                                 │   │
│  │   切換過程約需 30 秒KL520/ 3 分鐘KL720切勿拔除裝置。│   │
│  │                                                               │   │
│  │   可用版本:                                                  │   │
│  │   ○ KDP2 v2.2.0 (current)    當前版本                         │   │
│  │   ○ KDP2 v2.1.0              發布於 2024-08與舊模型相容   │   │
│  │   ○ KDP1 (legacy)            僅供 third-party 工具相容測試    │   │
│  │                                                               │   │
│  │                          [ 取消 ]   [ 切換到此版本 ]          │   │
│  └─────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────┘

展開區的元件規格

元素 類型 細節
Inline warning <div role="note"> color.warning/10 背景、color.warning 邊框1px、padding 16、圓角 radius.md
⚠ icon inline SVG 20×20、color.warning
版本 radio list <input type="radio"> + <label> name 共用「fw-version-{deviceId}」、預設選中 current
版本說明 <span> 12px / color.muted-foreground、跟版本 label 同行右側
「切換到此版本」按鈕 Button destructive md disabled 條件:選中的就是 currentenabled 條件:選了非 current 版本
「取消」按鈕 Button ghost md 點擊 → 收起 accordion、radio 重置為 current

為什麼用 radio list 不用 dropdown

  • bundled 版本通常 ≤ 3 個current + 1 舊版 + KDP1不需要 dropdown 的省空間優勢
  • radio list 讓所有選項與描述都可見、降低使用者「不知道有什麼選項」的疑慮
  • 對 a11y 友善screen reader 一次讀完所有選項)

4. Devices 頁面FW Badge 整合

依 R5-Q9 第 5 點Devices 頁 device card 需顯示 FW badge。

4.1 既有 Devices 卡片(spec/03-wireframes.md §3.3)的補強

┌──────────────────┐         ┌──────────────────┐
│ KL720-A          │         │ KL520-B          │
│ 🟢 Ready         │         │ 🟢 Ready         │
│ FW [● v2.2.0]    │ ← 綠    │ FW [● KDP1] ⚙    │ ← 紅 + 連結
│ kn: 0x5E6F...    │         │ kn: 0x1A2B...    │
│ [ Workspace ]    │         │ [ Workspace ]    │
└──────────────────┘         └──────────────────┘

4.2 Badge 規格

Badge 狀態 顏色 token 文字 形狀
Current color.success bg + color.success-foreground fg ● v2.2.0 或對應版本 Pill, padding 2 8, radius radius.full, 11px medium
Older color.warning bg + color.warning-foreground fg ● v2.1.0 同上
Legacy color.destructive bg + color.destructive-foreground fg ● KDP1 同上

版本後綴規則

  • bundled current → 不加後綴(純版本號)
  • 較舊的 bundled 版本 → 不加後綴(但用黃色提示)
  • 非 KDP2 系列KDP1→ 顯示 KDP1(不顯示版本號,因為 KDP1 沒有 semver

4.3 Tooltiphover badge

Badge Tooltip 文案
韌體為最新版本({version})。
韌體版本較舊,建議升級。點擊前往韌體管理 →
此韌體為舊版 KDP1建議升級到 KDP2 以支援完整功能。點擊前往韌體管理 →

4.4 點擊行為(⚙ icon

  • 黃 / 紅 badge → badge 右側顯示 ⚙ icongrey、12×12
  • 綠 badge → 不顯示 ⚙ icon避免吸引使用者進入降版
  • 點 ⚙ icon → deep-link 跳轉到 Settings > 韌體 並 scroll 到該裝置卡片(並 flash 該卡片邊框 600ms 提示)
  • 點 badge 本體 → 同 ⚙ icon 行為(提高 hit area
  • 鍵盤badge / icon 都可 Tab 聚焦Enter 觸發 deep-link

4.5 為什麼 Devices 頁不放升級 / 切換按鈕

依 architect 42 §1.2 / R5-Q9 第 5 點:

  • Devices 頁是使用者最常用的 Workspace 入口前置頁,避免誤觸高風險操作
  • Badge + ⚙ deep-link 維持「資訊呈現」的職責
  • 真正執行升級 / 切換的操作集中在 Settings → 韌體分頁、視覺更隆重

5. 升級流程 UX一鍵升級到 bundled latest

5.1 升級確認 Modal低風險、單擊 + 一次確認)

點裝置卡片的 升級到 KDP2 v2.2.0 按鈕後彈出:

┌─ 升級韌體 ──────────────────────────────────────┐
│                                                   │
│   升級 KL520 #1 的韌體                            │
│                                                   │
│   當前版本KDP1 (legacy)                         │
│   升級到:  KDP2 v2.2.0                           │
│                                                   │
│   ⓘ 升級過程約需 30 秒,期間切勿拔除裝置或關閉   │
│      應用程式。完成後裝置會自動重新識別。         │
│                                                   │
│                       [ 取消 ]    [ 開始升級 ]    │
│                                                   │
└───────────────────────────────────────────────────┘

規格

  • 寬度 480px、color.card 背景、elevation.4 陰影
  • 標題 18px / SemiBold
  • 「開始升級」按鈕 primary 變體(不是 destructive,因為升級是建議行為)
  • 「取消」按鈕 ghost
  • 可點外部關閉(升級不可中斷的警告留給降版 modal、升級單純確認意願即可
  • ESC 可關閉

5.2 升級進度 Modal不可中斷

點「開始升級」後 modal 不關閉、切換為進度狀態:

┌─ 升級韌體 ──────────────────────────────────────┐
│                                                   │
│   升級 KL520 #1 的韌體                            │
│                                                   │
│   ████████████████░░░░░░░░░░░  60%                │
│                                                   │
│   階段 3 / 5寫入韌體                            │
│                                                   │
│   ⚠ 請勿拔除裝置                                  │
│                                                   │
│                                                   │
│   (沒有取消按鈕)                                  │
│                                                   │
└───────────────────────────────────────────────────┘

規格

  • 進度條:高 8px、color.primary fill、color.muted track、圓角 radius.full
  • 階段文字14px / regular / color.muted-foreground
  • ⚠ banner紅色 destructive升級失敗風險仍存在
  • 不顯示 ✕ / 取消按鈕(不可中斷)
  • 點擊外部 / ESC不關閉(捕獲事件並抖動 modal 200ms 提示)
  • 預估時間(如可從後端取得):「預估剩餘 X 秒」附在階段文字下方

5.3 升級階段對應

依 architect 30 §M9-1 stage 對應。stage 命名以本檔 §8 狀態機為準v2.2 對齊修正、取代早期草稿的 scan/connect/loader/upgrade/verify

後端 stageFirmwareProgress.Stage UI 顯示文字 預估佔比
preparing 階段 1 / 4準備偵測 + 連接裝置) 5%
loading 階段 2 / 4載入引導程式僅 KDP1→KDP2 路徑) 20%
flashing 階段 3 / 4寫入韌體 50%
verifying 階段 4 / 4驗證完成 90%
done 階段完成 100%

如果是 KDP2→KDP2 同代升級(loading 引導程式路徑跳過),階段壓縮為 3 階段(preparingflashingverifyingUI 顯示文字改為 階段 n / 3

stage 名稱對齊備註

  • 早期 Architect TDD 曾用 connecting / loading_loader / loading_firmware / verifying、Design 早期草稿曾用 scan / connect / loader / upgrade / verify
  • v2.2 三方對齊後、以本檔 §8 狀態機的 preparing / loading / flashing / verifying 為唯一 source of truth
  • 後端 FirmwareProgress.Stage 欄位、Frontend i18n key§9.6)、失敗 stage 對應§7.1)全部用此命名

5.4 升級成功 Toast

升級成功後 modal 關閉、右上角 toast

┌──────────────────────────────────────────┐
│ ✓  KL520 #1 升級成功                      │
│    從 KDP1 升級到 KDP2 v2.2.0(耗時 28 秒)│
└──────────────────────────────────────────┘
  • variant: success
  • 停留 6 秒(比預設 3 秒長、讓使用者讀完細節)
  • 同時對應裝置卡片自動重新整理rescan APIFW badge 變綠

5.5 升級失敗

詳見 §7「失敗復原 UX」。


6. 版本切換流程 UX含降版、高風險

依 R5-Q9 第 5 點「使用『輸入 DOWNGRADE 字串』二次確認」+ architect 42 §5.3。

6.1 進入二次確認 Modal

使用者在 §3.3 accordion 選了非 current 版本、點「切換到此版本」後:

┌─ 切換到 KDP2 v2.1.0 ─────────────────────────────────────────┐
│                                                                │
│   ⚠ 確認切換到舊版韌體?                                       │
│                                                                │
│   你正在將 KL520 #1 的韌體切換到較舊的版本。                  │
│                                                                │
│   ┌──────────────────────┬──────────────────────┐            │
│   │ 當前版本             │ 將切換到             │            │
│   ├──────────────────────┼──────────────────────┤            │
│   │ KDP2 v2.2.0          │ KDP2 v2.1.0          │            │
│   │ 2025-03 發行         │ 2024-08 發行         │            │
│   └──────────────────────┴──────────────────────┘            │
│                                                                │
│   切換到舊版可能導致:                                         │
│   • 部分新版 .nef 模型無法載入                                 │
│   • 推論效能與穩定性下降                                       │
│   • 切換過程中拔除裝置可能導致裝置損毀                         │
│                                                                │
│   預估時間:約 30 秒                                           │
│                                                                │
│   為確認你了解風險請輸入「DOWNGRADE」                      │
│   ┌──────────────────────────────────────────┐                │
│   │                                          │                │
│   └──────────────────────────────────────────┘                │
│   (大小寫需完全相同)                                           │
│                                                                │
│                          [ 取消 ]   [ 確認切換 ]              │
│                                                                │
└────────────────────────────────────────────────────────────────┘

規格

  • Modal 寬度560px
  • 標題:「⚠ 確認切換到舊版韌體KDP1 目標時改為「⚠ 確認切換到 KDP1
  • 比較表格:兩欄、表頭 color.muted 背景、表身 padding space.3
  • 風險列表:用 <ul>、12px / color.foreground、無 icon避免過載
  • 「DOWNGRADE」輸入
    • <input type="text" autocomplete="off" spellcheck="false">
    • placeholder: 輸入 DOWNGRADE 確認i18n key 換對應 EN: Type DOWNGRADE to confirm
    • 輸入框邊框:未輸入 / 輸入錯誤時 color.warning;輸入正確時 color.success
    • 輸入正確時:邊框變綠 + 右側顯示 icon16×16、color.success
  • 「確認切換」按鈕:
    • variant: destructive
    • disabled 條件input 值不等於字面 DOWNGRADE
    • 大小:md
  • 「取消」按鈕:ghost md
  • 可點外部關閉嗎?不能(捕獲事件、抖動 200ms 提示「請使用『取消』按鈕關閉」ESC 可關閉與外部點擊行為不同——ESC 是鍵盤使用者的明確意圖、外部點擊較可能誤觸)

6.2 切換到 KDP1 的額外警告

當目標版本是 KDP1legacy風險列表多加一條

• KDP1 不支援多模型載入,部分 visionA-local 功能將無法使用

並在表格上方加紅色 banner

┌──────────────────────────────────────────────────┐
│ 🚫 KDP1 是已棄用的舊版韌體,建議僅用於           │
│    與第三方工具相容性測試。                       │
└──────────────────────────────────────────────────┘
  • banner 背景 color.destructive/10、邊框 color.destructive/30、icon color.destructive
  • 文字 13px / SemiBold / color.destructive

6.3 切換進行中 Modal

確認後 modal 不關閉、直接切換為進度狀態(與 §5.2 升級進度同設計、但有差異):

┌─ 切換韌體 ──────────────────────────────────────┐
│                                                   │
│   切換 KL520 #1 至 KDP2 v2.1.0                    │
│                                                   │
│   ████████████░░░░░░░░░░░░░░░  45%                │
│                                                   │
│   階段 3 / 5寫入韌體                            │
│                                                   │
│   ⚠ 請勿拔除裝置、請勿關閉應用程式                │
│      切換韌體不可中斷,中斷可能導致裝置永久損毀。 │
│                                                   │
│                                                   │
└───────────────────────────────────────────────────┘

與升級進度的差異

  • 警告語更強(「永久損毀」用詞)
  • 警告區域更大、紅色背景(不只是紅字)
  • 仍然沒有取消按鈕

全螢幕 hover 攔截:當切換進行中時、視窗任何地方(除了 modal 內)的點擊都被攔截、滑鼠 cursor 變 not-allowed、確保使用者不會誤關視窗。

6.4 切換成功

切換成功後與升級成功類似toast

┌──────────────────────────────────────────┐
│ ✓  KL520 #1 韌體已切換到 KDP2 v2.1.0      │
│    (耗時 32 秒、可能需要重新插拔裝置)   │
└──────────────────────────────────────────┘

variant: success、停留 8 秒(含「可能需要重新插拔」提示,使用者要讀完)。


7. 失敗復原 UX升級 / 切換共用)

依 architect 42 §5.5 失敗類型分類。

7.1 失敗類型對應

UI 失敗分類以 stage§5.3 / §8 狀態機)為主軸、加上 timeout / disconnect 兩個橫切性失敗,共 7 種使用者面友善訊息。對應 backend FirmwareProgress.Reason 的細分原因見 TDD §3.4Architect TDD v2.2 新增的 stage→errorCode→reason 對應表)。

失敗 stage / 類型 對應 backend stage 使用者面友善訊息 建議動作
preparing 找不到裝置scan_not_found preparing 找不到裝置,可能已斷開。 [ 重新插拔後重試 ]
preparing 連接失敗connect_failed preparing 無法連接裝置,請確認 USB 連接後重試。 [ 重試 ]
loading 引導程式寫入失敗loader_write_failed loading 引導程式載入失敗。請拔除裝置後重新插入並重試。 [ 拔插後重試 ]
flashing 寫入失敗upgrade_mid_failed flashing 韌體寫入失敗。可能是裝置硬體異常,請聯絡技術支援。 [ 複製錯誤訊息 ] [ 取得協助 ]
verifying 失敗verify_mismatch verifying 韌體已寫入但驗證未通過。請拔除裝置後重新插入並到「硬體」分頁重新掃描。 [ 拔插後重新掃描 ]
Timeout>60s 任一 stage、reason=timeout 操作超時。可能成功也可能未完成,請拔除裝置後重新掃描以確認狀態。 [ 拔插後重新掃描 ]
Disconnect during op 任一 stage、reason=disconnect_during_op 裝置在操作過程中斷開,狀態未知。請拔除後重新插入裝置。 [ 重新插拔後重試 ]

Reason 欄位對應Frontend 收到 WebSocket error event 時、依 FirmwareProgress.Stage + FirmwareProgress.Reason 兩欄位查表決定顯示哪條 friendly message。完整 backend reason 列舉與 errorCode 對應見 TDD §3.4。

7.2 失敗 Modal Wireframe

┌─ 升級失敗 / 切換失敗 ────────────────────────────────┐
│                                                       │
│   ⚠  韌體寫入失敗                                     │
│                                                       │
│   {對應友善訊息}                                      │
│                                                       │
│   錯誤代碼fw_loading_loader_write_failed_E102        │
│                                                       │
│   ─ 技術資訊 ▾ ─                                      │
│   ┌──────────────────────────────────────────┐       │
│   │ stage: loading                           │       │
│   │ reason: loader_write_failed              │       │
│   │ device: KL520 port 1                     │       │
│   │ before: KDP1                             │       │
│   │ raw_error: kp_update_kdp_firmware...     │       │
│   │ duration_ms: 18203                       │       │
│   └──────────────────────────────────────────┘       │
│                                                       │
│              [ 複製錯誤訊息 ]                          │
│                                                       │
│      [ 關閉 ]   [ 對應的建議動作按鈕 ]                 │
│                                                       │
└───────────────────────────────────────────────────────┘

規格

  • 寬度 560px
  • icon 24×24、color.destructive
  • 標題 18px / SemiBold / color.destructive
  • 友善訊息 14px / regular / color.foreground、最多 3 行
  • 錯誤代碼12px / mono / color.muted-foreground(給技術支援辨識用)
  • 「技術資訊」collapsible、預設收合
  • 展開內容用 font.family.mono 12px、color.surface-1 背景、padding 12、圓角 radius.md、可選取複製
  • 「複製錯誤訊息」:複製整段技術資訊到剪貼簿、複製後按鈕短暫變「已複製 ✓」2 秒
  • modal 不自動關閉(讓使用者讀完訊息)

7.3 部分成功(罕見但需處理)

若後端回傳 verify 階段失敗、但韌體已寫入before/after 版本不同UX 邏輯:

  • 視為「升級可能成功、但驗證未確認」
  • toast 提示為 warning非 destructive「韌體可能已升級但無法驗證請重新插拔裝置後到『硬體』分頁重新掃描。」
  • 裝置卡片暫時隱藏 FW badge顯示「狀態未知」灰色 badge、直到使用者重新掃描

8. 狀態機(裝置卡片 + Modal 整合)

[idle]
   │ 使用者點「升級」/「版本切換 → 切換到此版本」
   ▼
[confirming]  ── 使用者點「取消」 / ESC ──▶ [idle]
   │
   │ 使用者點「開始升級」 / 輸入 DOWNGRADE + 確認
   ▼
[preparing]   ← 後端 FirmwareProgress.Stage = "preparing"(涵蓋偵測 + 連接)
   │
   ▼
[loading]     ← 後端 FirmwareProgress.Stage = "loading"(僅 KDP1→KDP2 路徑)
   │
   ▼
[flashing]    ← 後端 FirmwareProgress.Stage = "flashing"
   │
   ▼
[verifying]   ← 後端 FirmwareProgress.Stage = "verifying"
   │
   ├── 成功 ──▶ [success_toast] ──▶ rescan ──▶ [idle]badge 更新)
   │
   └── 失敗 ──▶ [error_modal] ── 使用者點「重試」──▶ [preparing]
                              │
                              └── 使用者點「關閉」──▶ [idle](裝置卡 badge 維持原狀或變灰)

狀態 → UI 對應

狀態 卡片視覺 Modal 視覺
idle 正常 不顯示
confirming 卡片變灰、按鈕 disabled 確認 modal 顯示
preparing / loading / flashing / verifying 卡片變灰、按鈕 disabled、有 inline progress bar修可選、與 modal 重複) 進度 modal 顯示,進度條對應 stage
success_toast 短暫高亮(綠 ring 1s後復原 關閉、toast 出現
error_modal 卡片變灰 失敗 modal 顯示

9. i18n keys 清單namespace: settings.firmware

依 architect 42 §5.6 估算 46 keys、實際定版 51 keysv2.2 對齊修正後、含 settings 分頁 label 與 Devices 頁 badge tooltip對齊細節見本節末尾備註

9.1 頁面結構

Key zh-TW en
settings.tabs.firmware 韌體 Firmware
settings.firmware.title 韌體管理 Firmware Management
settings.firmware.description 管理已連接 Kneron 裝置的韌體版本。 Manage firmware versions for connected Kneron devices.
settings.firmware.empty.title 尚未偵測到 Kneron 裝置 No Kneron device detected
settings.firmware.empty.description 插上 USB 裝置後,到「硬體」分頁點擊「重新掃描」便會出現在這裡。 Plug in a USB device and click "Rescan" on the Hardware tab to see it here.
settings.firmware.empty.cta 前往硬體分頁 Go to Hardware
settings.firmware.helpText 沒看到裝置?檢查 USB 連接後到「硬體」分頁重新掃描。 Don't see your device? Check USB connection then rescan on the Hardware tab.

9.2 裝置卡片

Key zh-TW en
settings.firmware.card.label.knNumber kn_number kn_number
settings.firmware.card.label.currentVersion 當前版本 Current version
settings.firmware.card.label.latestVersion 最新版本 Latest version
settings.firmware.card.tag.current (current) (current)
settings.firmware.card.tag.latest (建議) (recommended)
settings.firmware.card.tag.legacy (legacy) (legacy)
settings.firmware.card.status.legacy KDP1 (legacy) — 建議升級到 KDP2 KDP1 (legacy) — Upgrade to KDP2 recommended
settings.firmware.card.status.older 有可用較新版本 Newer version available
settings.firmware.card.status.current 裝置使用最新韌體 Device is up to date
settings.firmware.card.action.upgrade 升級到 {version} Upgrade to {version}
settings.firmware.card.action.switchVersion 版本切換 Switch version

9.3 版本切換 accordion

Key zh-TW en
settings.firmware.switch.warningTitle 切換到舊版可能導致: Switching to an older version may cause:
settings.firmware.switch.risk.modelIncompat 部分新版 .nef 模型無法載入 Some newer .nef models may not load
settings.firmware.switch.risk.perfDegrade 推論效能與穩定性下降 Reduced inference performance and stability
settings.firmware.switch.risk.kdp1Limit KDP1 無法執行多模型載入 KDP1 does not support multi-model loading
settings.firmware.switch.duration 切換過程約需 {duration},切勿拔除裝置。 Switching takes ~{duration}. Do not unplug the device.
settings.firmware.switch.availableVersions 可用版本: Available versions:
settings.firmware.switch.versionNote.releasedOn 發布於 {date} Released {date}
settings.firmware.switch.versionNote.compatibleWithOld 與舊模型相容 Compatible with older models
settings.firmware.switch.versionNote.thirdPartyOnly 僅供 third-party 工具相容測試 For third-party tool compatibility testing only
settings.firmware.switch.action.cancel 取消 Cancel
settings.firmware.switch.action.switchToThis 切換到此版本 Switch to this version

9.4 升級確認 modal

Key zh-TW en
settings.firmware.upgradeModal.title 升級韌體 Upgrade firmware
settings.firmware.upgradeModal.heading 升級 {deviceName} 的韌體 Upgrade firmware on {deviceName}
settings.firmware.upgradeModal.from 當前版本 Current version
settings.firmware.upgradeModal.to 升級到 Upgrading to
settings.firmware.upgradeModal.warning 升級過程約需 {duration},期間切勿拔除裝置或關閉應用程式。完成後裝置會自動重新識別。 Upgrade takes ~{duration}. Do not unplug the device or close the application. The device will be re-detected automatically when done.
settings.firmware.upgradeModal.action.start 開始升級 Start upgrade

9.5 降版二次確認 modal

Key zh-TW en
settings.firmware.downgradeModal.title 切換到 {version} Switch to {version}
settings.firmware.downgradeModal.heading ⚠ 確認切換到舊版韌體? ⚠ Confirm switching to an older firmware?
settings.firmware.downgradeModal.headingKdp1 ⚠ 確認切換到 KDP1 ⚠ Confirm switching to KDP1?
settings.firmware.downgradeModal.intro 你正在將 {deviceName} 的韌體切換到較舊的版本。 You are about to switch the firmware on {deviceName} to an older version.
settings.firmware.downgradeModal.kdp1Banner KDP1 是已棄用的舊版韌體,建議僅用於與第三方工具相容性測試。 KDP1 is a deprecated legacy firmware. Recommended only for third-party tool compatibility testing.
settings.firmware.downgradeModal.compareHeader.from 當前版本 Current version
settings.firmware.downgradeModal.compareHeader.to 將切換到 Switching to
settings.firmware.downgradeModal.risk.brick 切換過程中拔除裝置可能導致裝置損毀 Unplugging the device during the process may damage it
settings.firmware.downgradeModal.duration 預估時間:約 {duration} Estimated time: ~{duration}
settings.firmware.downgradeModal.confirmPrompt 為確認你了解風險請輸入「DOWNGRADE」 To confirm you understand the risks, type "DOWNGRADE":
settings.firmware.downgradeModal.confirmPlaceholder 輸入 DOWNGRADE 確認 Type DOWNGRADE to confirm
settings.firmware.downgradeModal.confirmHelpText (大小寫需完全相同) (case-sensitive)
settings.firmware.downgradeModal.action.confirm 確認切換 Confirm switch
settings.firmware.downgradeModal.escAttemptHint 請使用「取消」按鈕關閉 Use the "Cancel" button to close

9.6 進度 modal

Key zh-TW en
settings.firmware.progress.upgradeTitle 升級韌體 Upgrading firmware
settings.firmware.progress.switchTitle 切換韌體 Switching firmware
settings.firmware.progress.deviceHeading.upgrade 升級 {deviceName} 的韌體 Upgrading firmware on {deviceName}
settings.firmware.progress.deviceHeading.switch 切換 {deviceName} 至 {version} Switching {deviceName} to {version}
settings.firmware.progress.stage.preparing 階段 {n} / {total}:準備(偵測 + 連接裝置) Stage {n} / {total}: Preparing
settings.firmware.progress.stage.loading 階段 {n} / {total}:載入引導程式 Stage {n} / {total}: Loading bootloader
settings.firmware.progress.stage.flashing 階段 {n} / {total}:寫入韌體 Stage {n} / {total}: Flashing firmware
settings.firmware.progress.stage.verifying 階段 {n} / {total}:驗證完成 Stage {n} / {total}: Verifying
settings.firmware.progress.warning.upgrade ⚠ 請勿拔除裝置 ⚠ Do not unplug the device
settings.firmware.progress.warning.switch ⚠ 請勿拔除裝置、請勿關閉應用程式。切換韌體不可中斷,中斷可能導致裝置永久損毀。 ⚠ Do not unplug the device or close the application. Firmware switching cannot be interrupted; interruption may permanently damage the device.
settings.firmware.progress.estimatedRemaining 預估剩餘 {seconds} 秒 ~{seconds}s remaining

9.7 成功 toast

Key zh-TW en
settings.firmware.success.upgrade {deviceName} 升級成功 {deviceName} upgrade succeeded
settings.firmware.success.upgradeDetail 從 {from} 升級到 {to}(耗時 {duration} From {from} to {to} (took {duration})
settings.firmware.success.switch {deviceName} 韌體已切換到 {version} {deviceName} firmware switched to {version}
settings.firmware.success.switchDetail (耗時 {duration}、可能需要重新插拔裝置) (took {duration}, may need to unplug and reconnect)
settings.firmware.partialSuccess.toast 韌體可能已升級但無法驗證,請重新插拔裝置後到「硬體」分頁重新掃描。 Firmware may have been written but verification failed. Please unplug, reconnect, and rescan on the Hardware tab.

9.8 失敗訊息

Key zh-TW en
settings.firmware.error.modalTitle 韌體操作失敗 Firmware operation failed
settings.firmware.error.message.preparing.scanNotFound 找不到裝置,可能已斷開。 Device not found, possibly disconnected.
settings.firmware.error.message.preparing.connectFailed 無法連接裝置,請確認 USB 連接後重試。 Cannot connect to device. Please check the USB connection and retry.
settings.firmware.error.message.loading 引導程式載入失敗。請拔除裝置後重新插入並重試。 Bootloader load failed. Please unplug, reconnect, and retry.
settings.firmware.error.message.flashing 韌體寫入失敗。可能是裝置硬體異常,請聯絡技術支援。 Firmware write failed. Possible hardware issue, please contact technical support.
settings.firmware.error.message.verifying 韌體已寫入但驗證未通過。請拔除裝置後重新插入並到「硬體」分頁重新掃描。 Firmware was written but verification failed. Please unplug, reconnect, and rescan on the Hardware tab.
settings.firmware.error.message.timeout 操作超時。可能成功也可能未完成,請拔除裝置後重新掃描以確認狀態。 Operation timed out. The operation may or may not have completed. Please unplug, reconnect, and rescan to confirm.
settings.firmware.error.message.disconnect 裝置在操作過程中斷開,狀態未知。請拔除後重新插入裝置。 Device disconnected during operation. State unknown. Please unplug and reconnect.
settings.firmware.error.errorCode 錯誤代碼:{code} Error code: {code}
settings.firmware.error.technicalInfo 技術資訊 Technical info
settings.firmware.error.copyError 複製錯誤訊息 Copy error info
settings.firmware.error.copied 已複製 ✓ Copied ✓
settings.firmware.error.action.close 關閉 Close
settings.firmware.error.action.retry 重試 Retry
settings.firmware.error.action.replugRetry 重新插拔後重試 Unplug and retry
settings.firmware.error.action.rescan 拔插後重新掃描 Unplug and rescan
settings.firmware.error.action.getHelp 取得協助 Get help

9.9 Devices 頁 FW badge tooltip

Key zh-TW en
devices.card.fwBadge.tooltipCurrent 韌體為最新版本({version})。 Firmware is up to date ({version}).
devices.card.fwBadge.tooltipOlder 韌體版本較舊,建議升級。點擊前往韌體管理 → Firmware is older. Click to manage firmware →
devices.card.fwBadge.tooltipLegacy 此韌體為舊版 KDP1建議升級到 KDP2 以支援完整功能。點擊前往韌體管理 → Legacy KDP1 firmware. Upgrade to KDP2 for full feature support. Click to manage firmware →
devices.card.fwBadge.deepLinkA11y 前往韌體管理 — {deviceName} Go to firmware management — {deviceName}

合計新增 i18n keys51 個zh-TW 與 en 各一套)。

v2.2 對齊修正:原稿標 52、本輪因 stage 命名統一§5.3 / §8將 §9.6 從 5 個 stage key 減為 4 個(preparing/loading/flashing/verifying),同時 §9.8 將 preparing 拆為 scanNotFound / connectFailed 兩個 sub-key總數不變


10. 無障礙考量A11y

項目 設計
Settings 分頁切換 沿用既有 Tabs 元件,role="tablist" / role="tab" / role="tabpanel" 切換 tab
裝置卡片結構 <section aria-labelledby="fw-device-{id}">、標題用 <h3 id="fw-device-{id}">{deviceName}</h3>
FW 狀態圓點 不單靠顏色傳達——圓點旁同時有文字標籤(KDP1 (legacy) 等);圓點本身加 aria-hidden="true" 避免重複朗讀
版本 radio 每個 radio 用 <label> 包住 visible 文字、fieldset + legend 包整組(<legend> 用 sr-only class 隱藏視覺、保留 screen reader
「切換到此版本」disabled 狀態 aria-describedby="hint-fw-{id}"、hint 用 sr-only 寫「請先選擇與當前不同的版本」
Upgrade modal role="dialog" aria-modal="true" aria-labelledby="..." aria-describedby="..."、focus trap、ESC 可關
Downgrade modal 同上 + 額外 aria-describedby 指向風險列表 <ul> 的 idscreen reader 先讀標題、再讀風險)
DOWNGRADE 輸入 <input aria-label="輸入 DOWNGRADE 確認" aria-describedby="downgrade-hint">、hint 「大小寫需完全相同」、輸入正確時 aria-invalid="false"、錯誤時 aria-invalid="true"
進度 modal <div role="status" aria-live="polite"> 包進度文字(不用 aria-live="assertive"、避免每秒朗讀)
進度條 <div role="progressbar" aria-valuenow={percent} aria-valuemin="0" aria-valuemax="100" aria-valuetext="階段 {n}/{total}">
失敗 modal role="alertdialog"(比 dialog 更強的語意、screen reader 會主動朗讀)
鍵盤導航 Tab 順序:分頁切換 → 第 1 張卡片的升級按鈕 → 第 1 張卡片的版本切換按鈕 → 第 2 張卡片…
Focus ring 沿用 ring.2 · color.ring、2px outline-offset
色彩對比 FW badge 紅 / 黃 / 綠對白色文字皆 ≥ 4.5:1critical 信號不妥協)
觸控目標 升級按鈕、版本切換按鈕、⚙ icon 全部 ≥ 44×44px tap area即使視覺更小、padding 補足)
Reduced motion prefers-reduced-motion: reduce → 進度條改靜態顯示百分比文字、modal 動畫 0ms、卡片高亮 1s 改為直接最終色(不淡入淡出)

11. Design Tokens 沿用 / 新增

11.1 沿用既有 tokensspec/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:1WCAG 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.5Design 自提使用者輸入「downgrade」小寫繞過

依 §6.1input 嚴格 case-sensitive 比對字面 DOWNGRADE、小寫 / 全形 / 半形 / 空白都不接受。 Frontend 實作提示:用 event.target.value === 'DOWNGRADE'(嚴格相等)、不要用 .toUpperCase() 後比對。

從 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 panelINFO / WARN / ERROR
  • log 等級依 architect 30 §M9-3 設計、Design 不重複定

13.4 與 spec/08-states.md(全域錯誤分級)的銜接

韌體升級 / 切換失敗的 嚴重級別屬於 Error08 表的 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 §文件結構 表格、加一行:

| **v2.7** | **韌體管理**v2.2 新增) | **`v2/firmware-management.md`** | **Kneron dongle FW 升級 + 版本切換完整規格Settings 新分頁、Devices 頁 FW badge、二次確認流程、51 個 i18n keys、R-FW-11 設計緩解** |

14.2 版本標頭變更

  • 版本:v2.1v2.2
  • 子標題增補「v2.22026-05-24 補丁)」吸收 R5-Q9 翻案 + B2 階段降版面向一般使用者的設計規格

14.3 「v2 → v2.2 差異總覽」表格新增段

## v2.1 → v2.2 差異總覽2026-05-24 補丁)

v2.2 是吸收 R5-Q9 翻案後的補丁,新增 FW 管理面向一般使用者的設計規格。

| 面向 | v2.1 | v2.22026-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 的問題(懸而未決)」新增

**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 stagepreparing / 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 / verifyingDesign §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.mdi18n 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/verifyingA-MISMATCH-1(2) §7.1 失敗類型對齊 backend FirmwareProgress.Reason 細分原因A-MID-3(3) §11.2 token 對比實測責任明示歸 M9-12 FrontendA-MID-2(4) §14.4 第 6 點 graceful shutdown 標已解、UI 落地至 v2/control-panel.mdA-MID-1(5) §9 i18n keys 51 個(原 52 減 1(6) §15.3 互審回合預期改為 v2.2 收斂狀態表 Design Agent