jim800121chen 8cd5751ce3 feat(local-tool): M8 重構 — Wails 控制台 + 瀏覽器 Web UI(R5 決策)
依 R5 五輪決策把 visionA-local 從「Wails 內嵌 Next.js」重構為「Wails
本機伺服器控制台 + 瀏覽器 Web UI」模式(類比 Docker Desktop / Ollama)。

程式碼變動
  - M8-1 砍 yt-dlp 全套(後端 resolver / URL handler / 前端 URL tab /
    Makefile vendor / installer / bootstrap / CI workflow,-555 行)
  - M8-2 砍 Mock 模式全套(driver/mock、mock_camera、Settings runtimeMode、
    VISIONA_MOCK 環境變數,-528 行)
  - M8-3 ffmpeg 從 GPL 切換到 LGPL 混合方案:Windows/Linux 用 BtbN 現成
    LGPL binary,macOS 自 build minimal decoder-only 進 git
    (vendor/ffmpeg/macos/ffmpeg 5.7MB + ffprobe 5.6MB,比 GPL 版省 85% 空間)
  - M8-4 Wails Server Controller:state machine、log ring buffer 2000 行、
    preferences.json atomic write、boot-id、Gin SkipPaths、shutdown 7+1 秒、
    notify_*.go 三平台 OS 通知、watchServer 改 Error state 不 os.Exit
  - M8-4b 啟動階段管線 R5-E:6 階段進度 event、20s soft / 60s hard timeout、
    stage 5/6 skip 規則、sentinel file、RestartStartupSequence 5 步驟
  - M8-5 Wails 控制台 vanilla HTML/JS/CSS(9 檔 ~2012 行)取代 M7-B splash:
    state 視覺、log panel、startup progress panel、Stage 6 manual CTA
    pulse、shutdown modal、Settings、Dark Mode、i18n 中英雙語
  - M8-6 上傳影片副檔名擴充(mp4/avi/mov/mpeg/mpg)
  - M8-7 Web UI Server Offline Overlay(role=alertdialog + focus trap +
    wsEverConnected 容錯 + Page Visibility)
  - M8-8 CORS middleware(127.0.0.1/localhost only + suffix attack 防護)+
    ws/origin.go 獨立 WebSocket CheckOrigin 避 package cycle
  - MAJ-4 server:shutdown-imminent WebSocket broadcast 機制
    (/ws/system endpoint + notifyShutdownImminent helper)
  - M8-9 Boot-ID + 瀏覽器 tab 自動重連(sessionStorage loop guard)

品質
  - ~105+ 新 unit test + race detector (-count=2) 全綠
  - 10 個 milestone 全部通過 Reviewer 審查
  - 三方 v2 + v2.1 文件(PRD / Design Spec / TDD)+ 交叉互審紀錄
    收錄在 .autoflow/

交付前待處理(M8-10)
  - 重跑 make payload-macos 把舊 GPL 77MB binary 換成新 LGPL
  - 三平台 end-to-end build 驗證

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 17:57:54 +08:00

28 KiB
Raw Permalink Blame History

v2.1 — Wails Server Control Panel 設計規格

本章對應 R5-1 / R5-2 / R5-3 / R5-4 / R5-5 / R5-5a / R5-D1 / R5-D3 / R5-Ev2.1 補丁) 上層索引:../design-spec-v2.md 版本:v2.1 · 更新日期2026-04-14 相關:v2/startup-progress.mdR5-E 階段化啟動進度面板Starting state 時顯示)


1. 定位與職責

Wails Server Control Panel以下稱「控制台」是 visionA-local 雙擊開啟後看到的第一個畫面,也是使用者唯一可以關 server 的地方。它的職責:

  • Server lifecycle 管理Start / Stop / Restart
  • 即時 log 顯示、過濾、複製、匯出
  • 一鍵開啟瀏覽器 Web UI
  • 顯示 server 狀態port、PID、uptime、version
  • 錯誤狀態的視覺呈現與自助排除入口

控制台不做的事(與 v1 清單一致、R5 複核):

  • 不管 device、model、inference那是 Web UI 的事)
  • 不顯示 Mock 模式切換R5-5拿掉 Mock 切換)
  • 不提供語言切換(跟隨系統 locale見 §9
  • 不提供 Dark Mode 切換(跟隨系統)

2. 視窗規格

項目 說明
預設寬度 720 px log 一行約 90-100 字元可顯示
預設高度 560 px log 區塊可顯示 18-20 行
最小寬度 560 px 防止 primary controls 擠壞
最小高度 420 px log 區最少 6 行
可調整大小 拖角落縮放
最大化 保留
最小化 保留
置頂
Title bar 原生 不做自訂 title bar
視窗標題 visionA-local · Server Control
視窗 icon 沿用 frontend/icon.png
初始位置 螢幕中央(首次)/上次位置(後續) 記憶寫到 ~/Library/Application Support/visiona-local/control-panel.json

3. 佈局 Wireframe最終版

┌───────────────────────────────────────────────────────────────────┐
│ ● visionA-local · Server Control                     [  ][ □ ][ × ]│ ← Title bar原生
├───────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌────┐  visionA-local                              v0.1.0          │
│  │LOGO│  ● Running · Browser opened                                 │ ← Header
│  └────┘  Port: 3721    Uptime: 00:12:43    PID: 45821              │
│                                                                     │
├───────────────────────────────────────────────────────────────────┤
│                                                                     │
│   [ 🌐 Open in Browser ]   [ Start ]   [ ⋯ Manage ▾ ]              │ ← Primary controls
│                                                                     │
│   ☑ Follow tail    ☑ Show timestamps    🔍 [ Filter ...      ]     │ ← Log controls
│                                                                     │
├───────────────────────────────────────────────────────────────────┤
│ 10:23:41 INFO  HTTP server listening on 127.0.0.1:3721              │
│ 10:23:41 INFO  wails ipc ready                                      │
│ 10:23:42 INFO  device scan: found 1 Kneron KL520                    │
│ 10:23:43 INFO  GET /api/devices 200 (4ms)                           │ ← Log panel
│ 10:23:45 INFO  GET /api/models 200 (2ms)                            │   (等寬字體
│ 10:23:58 WARN  python sidecar restart (attempt 1)                   │    可捲動
│ 10:23:59 INFO  python sidecar ready                                 │    等級著色)
│ 10:24:12 INFO  inference session start: classification              │
│ ...                                                                 │
│                                                                     │
│                                                                     │
├───────────────────────────────────────────────────────────────────┤
│ [ Clear ] [ Copy ] [ Export log ] [ Open log folder ]               │ ← Log actions
│                                                                     │
│ Lines: 142 / 2000                  ⚠ Closing this window will stop  │ ← Footer
│                                      the server.                    │
└───────────────────────────────────────────────────────────────────┘

和 v1 分析稿(design-analysis-round2-refactor.md §B2的差異

  • 拿掉 log 控制列上方「Mock 模式切換」區v1 分析稿其實沒有這個,只是 controlPanelSection 清單有——R5-5a 確認砍)
  • Primary controls 從 4 顆精簡為 3 顆(Start / Stop / Restart 三顆合併為 Start + overflow menu
  • Header 狀態列文字擴充,加入 "Browser opened"(首次 auto-open 後的視覺回饋,見 §5
  • Footer 新增「關閉視窗會停止 server」持久提示R5-2 明確決策,用持久文字取代每次彈對話框)

4. 元件清單

4.1 Header高度 80 px

元素 類型 尺寸 / 位置 狀態 備註
Brand logo <img> 40×40 px左側 padding 16 static 沿用 frontend/icon.png
Product name <h1> 16 px / SemiBold static 文字:visionA-local
Version tag <span> 12 px / muted-foreground static 文字:v{major}.{minor}.{patch},右上角
Status indicator <span> + <svg> 圓點 8 px 見 §5 狀態機 顏色綁 semantic tokens
Status text <span> 14 px / Medium 見 §5 例:Running · Browser opened
Server meta <dl> 12 px / muted 6 個欄位 Port / Uptime / PIDUptime 每秒刷新)

4.2 Primary controls高度 48 px

按鈕 變體 大小 啟用條件 備註
Open in Browser primary filled md Running 最左、最顯眼,附 🌐 icon
Start outline md Stopped / Error 附 ▶ icon
Manage ▾ outline + dropdown md Running 展開後包含 Stop serverRestart server

Manage overflow menu 內容

┌──────────────────────────┐
│ Stop server              │  ← destructive 色彩提示
│ Restart server           │  ← 普通
├──────────────────────────┤
│ Open log folder          │  ← 重複項(方便直接存取)
└──────────────────────────┘

為什麼 Primary CTA 是 "Open in Browser"Design Rationale

  • R5-4 決定首次啟動會自動開瀏覽器一次
  • 使用者後續可能關 browser tab環境整理、記憶體、誤關
  • 「關了想重開」是日常第二高頻操作(第一高頻是雙擊 app 本身,已被 auto-open 覆蓋)
  • Start/Stop/Restart 只在出事時才點
  • 結論:Open in Browser 保留為 primary(沿用第一輪 B3 提案)

Stop 放進 overflow 的原因

  • 避免誤按導致 server 中斷 + Web UI 爆掉
  • Stop 放在 dropdown 多一個「點擊 > 選擇」保護,等效輕度確認
  • 不做「你確定要 Stop」modal減少 UX 摩擦

4.3 Log controls高度 40 px

元素 類型 預設 行為
Follow tail <checkbox> ON 使用者往上捲動時自動關閉,捲到最底自動重啟。附提示 Jump to latest pill
Show timestamps <checkbox> ON 關閉後 log 行去掉時間戳
Filter <input type="search"> 即時字串過濾,無 regex⌘F / Ctrl+F 聚焦

4.4 Log panel高度剩餘 flex-grow

屬性
字體 font.monoSF Mono / Consolas / Menlo
字級 12 px
行高 1.5
背景 color.surface-1Lightoklch(0.99 0 0)Darkoklch(0.18 0 0)
選取背景 color.primary/20
最大行數 2000ring buffer超過舊的 drop對齊 TDD v2 Go server 常數,~400KB 記憶體可忽略)
寫檔 TDD v2 採 in-memory ring bufferlog 不落地;使用者若需保存用 Export log 手動匯出)
滑入動畫 60 ms fade-inprefers-reduced-motion 時關閉)
選取冰結 使用者拖選文字時自動暫停 auto-scroll

為什麼取消落地寫檔與 rotate

  • TDD v2 決定 Go server 採 in-memory ring buffer容量 2000 行)統一管理 log不落地滾動檔案
  • rotate 7 天 / 10MB 需要 lumberjack.v2 或自刻定時掃描 + size 比較,非 M8 scope 且會增加技術債
  • 使用者如需保存 log → Export log 按鈕§4.5)原生 save dialog 匯出當下 buffer 內容
  • 使用者如需檢視/清理 → Open log folder 保留,指向 <dataDir>/logs/(若未來重新啟用落地再用;目前該資料夾可能為空)
  • 未來若有落地需求 → 放 M9+ 迭代,不影響 v2.1 交付

等級著色(和 Web UI semantic token 一致):

Level Token Light 範例 Dark 範例
DEBUG color.muted-foreground #6b7280 #9ca3af
INFO color.foreground #111827 #e5e7eb
WARN color.warning #b45309 #fbbf24
ERROR color.destructive #b91c1c #f87171

4.5 Log actions高度 40 px

按鈕 類型 功能
Clear ghost small 清空畫面 log不動檔案二次確認toast「Log cleared」5 秒內可 undo
Copy ghost small 複製全部可見 log 到剪貼簿首次點擊時提示「Log 可能包含檔名與裝置資訊」一次
Export log ghost small 原生 save dialog預設檔名 visiona-local-{yyyyMMdd-HHmmss}.log
Open log folder ghost small 呼叫 OS 開 ~/Library/Application Support/visiona-local/logs/

4.6 Footer高度 32 px

元素 位置 文字 / 樣式
行數統計 Lines: {current} / 200012px muted
關閉提示 ⚠ Closing this window will stop the server.12px muted

持久提示為什麼不彈 modalR5-2 解釋):

  • 使用者已明確決策「關閉 = 結束 server」
  • 每次關都彈 modal 只會煩,且使用者按過幾次就會盲目點「確定」失去意義
  • 持久 footer 文字是「被動告知」而非「主動打斷」,符合 Jakob Nielsen 錯誤預防原則
  • 使用者如果真的不想關,看到 footer 提示就會改按最小化
  • 若使用者仍誤關,下次開啟 (R5-4 自動起 server + 自動開瀏覽器) 只需 3-5 秒就回到原狀,損失可控

5. Server 狀態機(五態視覺化)

5.1 狀態定義v2.1 修訂)

State 觸發條件 持續時間
Starting 控制台剛開啟 / 使用者按 Start / Restart 過程中 通常 4-15 秒,上限 60 秒R5-E1
Running 6 階段全部完成(含 WebSocket 連上R5-E6 主要 state
Stopping 使用者按 Stop / 視窗關閉中 通常 <2 秒
Stopped Stop 完成、尚未 Restart 空 state
Error 啟動階段:任一階段超時 20 秒進 Retry 提示;總計超過 60 秒R5-E4仍未就緒 → Error
運行階段/api/health 連續失敗達閾值 / sidecar crash 超過 auto-restart 上限
停留直到使用者介入

5.2 視覺對照表v2.1 修訂)

State 圓點顏色 Icon Status text 範例 附加元素
Starting color.warning 琥珀 旋轉 spinner Starting · Stage {n}/6 log panel 上方浮出「啟動進度面板」(見 v2/startup-progress.md
Primary controls 全部 disabled
Running color.success RunningRunning · Browser openedToggle ON 首次顯示 10 秒) 啟動進度面板 fade-outOpen in Browser enabled
Running自動開瀏覽器瞬間 color.success → 淡入 ✓ icon 2 秒 → fade out Running · Browser opened 持續 10 秒後自動變回 Running
Stopping color.warning 琥珀 旋轉 spinner Stopping... 所有 primary controls disabled
Stopped color.muted-foreground Stopped 只有 Start 按鈕可按
Error color.destructive Error: {簡短原因} 見 §6 錯誤面板;若從啟動階段進入 Error啟動進度面板切換為 Error 狀態(見 startup-progress.md §5

5.3 狀態轉場動畫

  • 圓點顏色過渡300 ms ease-out
  • Spinner 旋轉1 s linear infinite
  • Running · Browser opened 出現fade + slide-in-left 200 ms停留 10 秒fade-out 200 ms
  • prefers-reduced-motion: reduce → 全部動畫降為 0 ms 跳變

6. Error State 面板R5 共識)

當 Server 進入 Error 時,控制台 log panel 上方(介於 log controls 和 log panel 中間)浮出一個 error bannerlog 面板不消失。

6.1 Wireframe

├───────────────────────────────────────────────────────────────────┤
│   ☑ Follow tail   ☑ Show timestamps   🔍 [ Filter ...          ]  │
├───────────────────────────────────────────────────────────────────┤
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ ⚠  Server failed to start                                     │ │
│ │                                                                │ │
│ │    Python sidecar exited with code 1 after 3 retries.         │ │
│ │    Last error: ModuleNotFoundError: kneron_plus               │ │
│ │                                                                │ │
│ │    [ Restart Server ]  [ View log details ↓ ]  [ Report... ]  │ │
│ └───────────────────────────────────────────────────────────────┘ │
├───────────────────────────────────────────────────────────────────┤
│ 10:24:12 ERROR python sidecar exited code=1                       │ ← Log panel 照常顯示
│ 10:24:13 ERROR ...                                                │
│ ...                                                                │
├───────────────────────────────────────────────────────────────────┤

6.2 元件

元素 類型 細節
Banner 容器 <div role="alert"> 背景 color.destructive/10,邊框 1px color.destructive/30,圓角 radius.mdpadding 16
警告 icon <svg> 20×20color.destructive
標題 <strong> 14 px SemiBoldcolor.destructive
說明 <p> 13 pxcolor.foreground,最多 2 行,溢出
Restart Server Button primary sm 點擊 → 呼叫內部 restartbanner 轉為 Starting state
View log details ↓ Button ghost sm 點擊 → 自動捲動 log panel 到最後一條 ERROR 行並 flash 2 次
Report... Button ghost sm 【hold】 現階段先不實作。待 PM 提供 GitHub Issue repo URL 後再恢復。Design 原意:開預設瀏覽器到 GitHub Issue 新增頁面,預填錯誤摘要 + 環境資訊version、OS、最後 20 行 log不含檔名 / 裝置 serial

R5-D1 落地OS 原生通知並存)

Error state 進入時,除了控制台 log panel 上方的 Error bannerrole="alert" 由 Wails WebView 內部顯示)另外發送一次 OS 原生 non-blocking 通知。這是 R5-D1 使用者決策:控制台可能被最小化、或在另一個桌面 / 虛擬桌面,使用者不一定會看到 bannerOS 通知作為次要冗餘提醒仍有價值。

平台 通知機制 Fallback
macOS osascript -e 'display notification "..." with title "visionA-local"'toast 非 dialog
Windows wailsRuntime.SendNotification(優先) msg * 命令列
Linux notify-send zenity --notification

行為細節

  • 通知內容:標題 = visionA-local Server Error / 內文 = {error.title}: {error.description 前 60 字}
  • non-blocking:不阻塞 UI不彈 modal與先前 v1 的 showNativeError()(給 startup 致命錯誤用的 modal dialog區分
  • 不重複發:同一次 Error state 只發一次通知,使用者按 Restart Server 或 State 變回 Starting 後才重置「本次已發」flag
  • 技術實作:新增 Go 檔案 visiona-local/notify.go,函式 sendCrashNotification(title, body string) error;對應 TDD v2 control-panel.md §4.7

6.3 Dismiss 條件

Banner 不可手動關閉(避免使用者忽略問題)。只有下列條件自動消失:

  • 使用者按 Restart Server 且 server 成功進入 Running
  • 使用者手動修復環境後按 Start 成功

7. 啟動行為(對應 R5-4 / R5-D3 / R5-E

7.1 預設流程v2.1 修訂)

v2.1 重要變更Starting 狀態下控制台顯示階段化啟動進度面板(見 v2/startup-progress.md),不是只有一顆 spinner。下述「step」對應進度面板的 6 個階段。

1. 使用者雙擊 visionA-local.app
        ↓
2. 控制台視窗開(螢幕中央 / 上次位置)
        ↓
3. 控制台進入 Starting 狀態log panel 上方顯示「啟動進度面板」
   → 階段 1初始化控制台
   → 階段 2檢查 Python runtime 與驅動
   → 階段 3啟動本機伺服器等 /api/health 200
   → 階段 4偵測 Kneron 裝置
        ↓
4. Server ready階段 3 完成訊號 = /api/health 200
        ↓
5. 【每次 / Settings 為 ONmacOS/Windows 預設Linux 預設 OFF】
   階段 5「開啟瀏覽器」觸發 OS open browser
   - macOS: `open http://127.0.0.1:3721/`
   - Windows: `start http://127.0.0.1:3721/`
   - Linux: `xdg-open http://127.0.0.1:3721/`
   【Toggle OFF 時】階段 5 標記為「跳過(依偏好設定)」,不執行 OS open但仍推進
        ↓
6. 階段 6等待 Web UI 連線
   (等 WebSocket hub 收到第一個 client 連線R5-E6 決策)
   【Toggle OFF 時】此階段改為「等待使用者手動點擊『在瀏覽器開啟』」
        ↓
7. 所有 6 階段完成
   → 啟動進度面板淡出fade-out 200 ms
   → Status: Running
   → Status text 顯示 `Running · Browser opened` 10 秒Toggle ON 時)
     或純 `Running`Toggle OFF 時,使用者尚未手動 Open
   控制台留在背景(不最小化、不關閉)
        ↓
8. 瀏覽器 tab 進入 Next.js First-Run wizard見 v2.4

R5-D3 重點每次啟動(每次 Wails App process 新啟動)都會跑完整 6 階段流程並觸發 OS open不是只有首次。Restart Server(同一個 Wails process 內重啟 server不會重開瀏覽器 tab — 由 Offline Overlay 的自動重連處理(見 v2/server-offline-overlay.md)。

7.2 視覺回饋

第 6 步的 Running · Browser opened 是使用者看到控制台第一個確認 server 就緒的訊號。具體視覺:

  • Status dot 綠色
  • Status text 後方 fade-in 一個 ✓ iconcolor.success
  • Text 改為 Running · Browser opened
  • 10 秒後 ✓ icon 淡出text 縮為 Running

7.3 例外情境

情境 控制台行為
Server Starting 超過 5 秒 進入 Error state見 §6不開瀏覽器
Port 3721 被佔 Server fallback 到 3722 / 3723Header 顯示 Port: 3722 (default 3721 in use),瀏覽器開的 URL 同步換
Settings「自動開瀏覽器」= OFF Server Running 後不做 auto-open使用者需手動點 Open in Browser

8. 深色模式處理

控制台深色模式與 Web UI 同步,機制:

  • 讀取 OS 偏好:控制台是 Wails WebView直接用 CSS prefers-color-scheme
  • CSS 變數切換:和 frontend/src/app/globals.css 用一樣的 :root / [data-theme='dark'] block
  • 不提供手動切換v1 決策延續)

Dark 下額外考量

  • Log panel 背景 oklch(0.18 0 0)(比 surface 再暗 5%,模仿 terminal
  • ERROR 紅色在 dark 下用 oklch(0.72 0.19 25)(避免過亮刺眼)
  • 圓點狀態色全部用 dark variant確保 4.5:1 對比R4-3 降為盡力而為,但狀態色這種 critical 信號仍維持嚴格)

9. i18n key 清單(新元件)

控制台文字走 desktop-control namespace獨立於 Next.js Web UI 的 i18n 檔(但抽自同一份辭典,避免兩處維護)。

9.1 新增 keyzh-TW / en

Key zh-TW en
control.title visionA-local · 伺服器控制台 visionA-local · Server Control
control.status.starting 啟動中... Starting...
control.status.running 執行中 Running
control.status.runningBrowserOpened 執行中 · 已開啟瀏覽器 Running · Browser opened
control.status.stopping 停止中... Stopping...
control.status.stopped 已停止 Stopped
control.status.error 錯誤:{reason} Error: {reason}
control.meta.port 連接埠 Port
control.meta.portFallback 連接埠:{port}(預設 {default} 被佔用) Port: {port} (default {default} in use)
control.meta.uptime 執行時間 Uptime
control.meta.pid 程序 ID PID
control.meta.version 版本 Version
control.action.openBrowser 在瀏覽器開啟 Open in Browser
control.action.start 啟動 Start
control.action.manage 管理 Manage
control.action.stopServer 停止伺服器 Stop server
control.action.restartServer 重新啟動伺服器 Restart server
control.log.followTail 自動跟隨最新 Follow tail
control.log.showTimestamps 顯示時間戳 Show timestamps
control.log.filterPlaceholder 過濾 log... Filter...
control.log.jumpToLatest 跳到最新 Jump to latest
control.log.clear 清空 Clear
control.log.clearToast 已清空 log可復原 Log cleared (undo)
control.log.copy 複製 Copy
control.log.copyPrivacyHint Log 可能包含檔名與裝置資訊,請注意分享對象 Log may contain filenames and device info. Share with care.
control.log.export 匯出 log Export log
control.log.openFolder 開啟 log 資料夾 Open log folder
control.log.lines 行數:{current} / {max} Lines: {current} / {max}
control.footer.closeWarning ⚠ 關閉此視窗會停止伺服器 ⚠ Closing this window will stop the server
control.error.title 伺服器無法啟動 Server failed to start
control.error.description {具體原因} {reason}
control.error.restartButton 重新啟動伺服器 Restart Server
control.error.viewLogDetails 檢視 log 詳情 View log details
control.error.reportButton 回報問題... Report...

9.2 刪除 key從現有 Next.js i18n 砍)

v2/source-selector-update.md §3.2


10. 無障礙考量

項目 設計
Keyboard navigation 所有 interactive 元素 tabindex 合理序列Open in Browser → Start/Manage → Follow tail → Show timestamps → Filter → (log panel 可選取) → Clear → Copy → Export → Open folder
Focus ring 沿用 Web UI token ring.2 · color.primary2 px outline-offset
Keyboard shortcut ⌘F / Ctrl+F 聚焦 filter⌘C / Ctrl+C 複製選取 log⌘W / Ctrl+W 關視窗R5-2結束 server
⌘Q macOS 原生結束 app停 server + quit
Screen reader Status indicator <span role="status" aria-live="polite">Error banner <div role="alert">log panel <output aria-live="polite" aria-atomic="false">(新行 append
ARIA label 所有 icon button 有 aria-label(例如 Follow tail checkbox 的 trailing spinner 有 aria-label="Auto-scrolling enabled"
色彩對比 Status dot / ERROR level log / Error banner 強制 ≥ 4.5:1即使 A11y 整體降級為「盡力而為」critical 信號不妥協)
Reduced motion prefers-reduced-motion: reduce → 關閉 spinner 旋轉(改為靜態點)、關閉 log 滑入動畫、關閉 Browser opened fade
字級可縮放 使用 rem 而非 px 定義字級,支援 OS 字級偏好

11. 與 v1design-analysis-round2-refactor.md)的差異

面向 v1 分析稿 v2 正式規格
視窗職責 三方尚在討論 確定為雙 UIR5-1
關閉行為 待 D1 決策 關閉 = 結束 serverfooter 持久提示R5-2
Tray 建議復活 tray 不做R5-3
首次啟動 建議自動開瀏覽器 採納自動開瀏覽器R5-4
Primary controls 4 顆 3 顆Stop/Restart 併入 Manage 下拉)
Header 狀態列 固定 Running 首次啟動後動態 Running · Browser opened 10 秒
Error 狀態視覺 未設計 新增 Error banner§6
Mock 切換 未納入 scope 明確砍除R5-5a
Log 上限 1000 行 1000 行(維持)
Log 寫檔 7 天 / 10MB rotate 維持
語系 跟隨系統 跟隨系統(維持)

12. v2 → v2.1 Diff2026-04-14

# 位置 v2 v2.1 來源
1 §4.4 Log panel 最大行數 1000 行 2000 行(對齊 TDD v2 ring buffer Architect Review Minor m-1
2 §4.4 Log 寫檔 rotate 7 天 / 10 MB 無落地寫檔in-memory ring buffer使用者透過 Export log 手動匯出) Architect Review Minor m-12
3 §4.6 Footer 行數顯示 Lines: {current} / 1000 Lines: {current} / 2000 Architect Review Minor m-1
4 §5 狀態機 Starting 只有 spinner1-5 秒 Starting 顯示階段化啟動進度面板4-15 秒(上限 60 秒R5-E1 R5-E
5 §6.2 Error banner Report... 正常按鈕 【hold】 待 PM 提供 GitHub Issue repo URL 後再恢復 Architect Review Minor m-11 / G-3
6 §6.2 新增 R5-D1 OS 原生通知並存Error state 發 non-blocking toast notification不是 modal R5-D1 / Architect Review Minor m-4
7 §7.1 第 5 步 「首次 / Settings 為 ON」 「每次 / Settings 為 ON」,新增 Linux 預設 OFF 說明,流程改為 6 階段化 R5-D3 + R5-E
8 §7.1 新增 引用新檔 v2/startup-progress.mdR5-E 階段化啟動進度面板) R5-E

下一步:交 M8-5 Frontend Agent 實作Wails 控制台 + 啟動進度面板),交 Reviewer 審查 control-panel.md + startup-progress.md 整體一致性。