依 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>
13 KiB
v2.5 — Settings 頁更新
本章對應 R5-4(Settings 新增自動開瀏覽器 toggle)+ R5-5a(砍 Mock 模式相關設定)+ R5-D2(Linux 預設 OFF)+ R5-D3(每次啟動都自動開)+ R5-E(階段化啟動進度)。 上層索引:
../design-spec-v2.md版本:v2.1 · 更新日期:2026-04-14
1. 變更摘要
Settings 維持 v1 的 4 個分頁 結構(R4 第四輪決策確認):
| Tab | v1 內容 | v2 變更 |
|---|---|---|
| 一般 | 語言、深色模式狀態(唯讀) | 新增「首次啟動時自動開啟瀏覽器」toggle |
| 硬體 | 真實 / Mock 切換、裝置掃描策略 | 刪除 Mock 相關,只保留裝置掃描策略 |
| 模型 | 預置模型清單、上傳、自訂 | 不變 |
| 進階 | 資料目錄、Python 雙策略、清 log 等 | 不變 |
2. 「一般」分頁新增項目
2.1 結構
┌─ Settings > 一般 ───────────────────────────────────────────┐
│ │
│ 語言 │
│ ┌───────────────────────────┐ │
│ │ 繁體中文 ▾ │ │
│ └───────────────────────────┘ │
│ │
│ 深色模式 │
│ 跟隨系統(目前:深色) │
│ │
│ ── 啟動行為 ──────────────────────────────────────── │
│ │
│ 首次啟動時自動開啟瀏覽器 [■□] ON │
│ 啟動 visionA-local 時自動在預設瀏覽器開啟 Web UI。 │
│ 關閉此選項後,你需要手動點控制台的「在瀏覽器開啟」按鈕。 │
│ │
└──────────────────────────────────────────────────────────────┘
2.2 Toggle 規格
| 屬性 | 值 |
|---|---|
| 元件類型 | <Switch>(shadcn) |
| 預設值(依平台) | macOS / Windows = ON;Linux = OFF(R5-D2) |
| i18n key | settings.general.autoOpenBrowser.label / settings.general.autoOpenBrowser.description |
| 落地檔案 | preferences.json 位於 <dataDir>/(對齊 TDD v2)路徑: • macOS ~/Library/Application Support/visiona-local/preferences.json• Windows %APPDATA%\visiona-local\preferences.json• Linux ~/.local/share/visiona-local/preferences.json |
| 儲存機制 | Go server 端負責讀寫(visiona-local/preferences.go,非 Wails 內建機制 — Wails v2 沒有 settings store)JSON 格式: {"openBrowserOnStart": true}原子寫入:write-rename pattern( os.WriteFile(path+".tmp", ...) → os.Rename(path+".tmp", path)),POSIX / Windows 均原子 |
| 讀取失敗 fallback | 呼叫 DefaultPreferences(),依 runtime.GOOS 回傳平台預設:Preferences{OpenBrowserOnStart: runtime.GOOS != "linux"} |
| 生效時機 | 立即生效,不需 restart app |
| 影響對象 | 控制台的「每次啟動自動開瀏覽器」邏輯(見 v2/control-panel.md §7) |
Linux 首次使用說明(R5-D2 落地):
Linux 使用者第一次開 Wails 控制台時,Settings > 一般 的「啟動時自動開啟瀏覽器」toggle 預設是關的。原因是 Linux 桌面環境差異大,xdg-open 在無頭環境 / i3 / xmonad / 極簡 WM 下行為可能異常(例如無預設瀏覽器、或開到錯的 DE session)。Linux 使用者若確認自己的環境可以正常 xdg-open,可手動打開此 toggle,下次啟動就會自動開瀏覽器。
關閉此 toggle 時,啟動進度面板仍然會顯示(見 v2/startup-progress.md),只是第 5 階段「開啟瀏覽器」會被標記為 跳過(依偏好設定)/ Skipped (per preference),第 6 階段「等待 Web UI 連線」改為「等待使用者手動點擊『在瀏覽器開啟』」— 視覺上仍會收尾至 Running state,只是由使用者主動觸發第 5 階段(對齊 R5-E 階段化體驗)。
2.3 重要細節(R5-D3 已定案)
這個 toggle 同時影響「首次」和「每次」啟動嗎?
R5-D3 決策:每次啟動(含每次 StartServer 成功後)都會自動開瀏覽器,不是只有首次。R5-4 原字面「首次啟動」已於 R5-D3 修正。精確行為:
- Toggle ON(macOS / Windows 預設):每次雙擊 app 或每次 Start Server 成功後,控制台自動呼叫 OS open browser
- Toggle OFF(Linux 預設):啟動時只開控制台,不開瀏覽器;使用者自行點控制台的「在瀏覽器開啟」按鈕
- Restart Server 情境:因為 Restart 是同一個 Wails App process 內重啟(R5 雙 UI 架構下 Wails 不關),且啟動進度面板只在 Wails 剛啟動時顯示一次;Restart 時瀏覽器 tab 應由 Offline Overlay 自動重連,不會再開新 tab(避免開一堆重複 tab)
Label 定版:「啟動時自動開啟瀏覽器」/ "Auto-open browser on startup"(去掉「首次」二字)
| 版本 | label | description |
|---|---|---|
| 原 R5-4 字面 | 首次啟動時自動開啟瀏覽器 | — |
| 最終採用(R5-D3 定案) | 啟動時自動開啟瀏覽器 | 啟動 visionA-local 時自動在預設瀏覽器開啟 Web UI。關閉此選項後,你需要手動點控制台的「在瀏覽器開啟」按鈕。 |
3. 「硬體」分頁變更
3.1 刪除項目(R5-5a)
所有 Mock 模式相關設定全砍:
| v1 項目 | 說明 | v2 處理 |
|---|---|---|
模式:真實硬體 / Mock radio |
切換整個 app 推論來源 | 刪除 |
Mock 模式描述 說明文字 |
介紹 Mock 用途 | 刪除 |
Mock 模式假資料速率 slider |
調 Mock 輸出速率 | 刪除 |
Mock 模式裝置名稱 input |
自訂假裝置名 | 刪除 |
切換模式會重啟推論 session 警告 |
切換時的提醒 | 刪除 |
3.2 保留項目
| 項目 | 說明 |
|---|---|
| 裝置自動掃描頻率 | 每次啟動時 / 手動 / 關閉 |
| USB 熱插拔偵測 toggle | 自動偵測新裝置插入 |
| Kneron KL520 / KL720 韌體版本顯示 | 唯讀 |
3.3 新增項目
無。R5-5a 砍 Mock 後這個 tab 變得更簡潔。
3.4 Tab 是否保留?
因為「硬體」tab 被清空後仍有內容(掃描頻率、熱插拔、韌體版本),tab 結構保留,不合併也不刪除。
4. 「模型」與「進階」分頁
完全不動。R5 沒有觸及這兩個 tab 的內容。
5. i18n key 異動
5.1 新增 key
| Key | zh-TW | en |
|---|---|---|
settings.general.sectionStartup |
啟動行為 | Startup behavior |
settings.general.autoOpenBrowser.label |
啟動時自動開啟瀏覽器 | Auto-open browser on startup |
settings.general.autoOpenBrowser.description |
啟動 visionA-local 時自動在預設瀏覽器開啟 Web UI。關閉此選項後,你需要手動點控制台的「在瀏覽器開啟」按鈕。 | Automatically open the Web UI in your default browser when visionA-local starts. When off, you need to manually click "Open in Browser" in the Control Panel. |
5.2 刪除 key
執行 grep 找出所有 mock 相關 key:
grep -rE "mock|Mock" frontend/src/lib/i18n/
預期刪除(實際清單以 grep 為準):
| Key | 原值(zh-TW) |
|---|---|
settings.hardware.mode.label |
模式 |
settings.hardware.mode.real |
真實硬體 |
settings.hardware.mode.mock |
Mock |
settings.hardware.mode.description |
選擇 visionA-local 的執行模式 |
settings.hardware.mock.rate.label |
Mock 速率 |
settings.hardware.mock.deviceName.label |
Mock 裝置名稱 |
settings.hardware.modeSwitchWarning |
切換模式會重啟推論 session |
firstRun.mode.* |
全部(見 v2/first-run-update.md §5.2) |
devices.mockBadge |
Mock |
dashboard.tryMockHint |
或切換到 Mock 模式試用 |
5.3 type 檔同步
frontend/src/lib/i18n/types.ts 對應 interface 欄位全砍,確保 TypeScript 編譯不留 dangling reference。
6. 清理殘留的 Mock 程式碼
Settings 改完後,前後端其他地方可能仍有 Mock 殘留:
6.1 前端
frontend/src/stores/任何mockstate / actionfrontend/src/components/任何Mockbadge / pillfrontend/src/app/devices/頁面右上的「真實 / Mock」切換(v1design-spec.md §第三輪修訂後仍待確認 4.提到)
6.2 後端
- Go server 任何 mock handler、假資料 generator
- Python sidecar 的 mock inference path
這部分非 Design 的 scope,但 Design 提醒 Orchestrator:R5-5a 的「完全砍除」不只是 UI 層面,後端也要同步砍。交 Architect Agent 評估實作影響。
7. 遷移策略(Migration)
使用者情境:v1 版本沒有 preferences.json;Mock 模式相關設定(若存在)是記在前端 localStorage 或 v1 舊式 config,不在 Go 端的 preferences 檔裡。v2 改用 Go 端 preferences.json 管理「是否啟動時自動開瀏覽器」,是全新的檔案。
v2 首次讀取 preferences.json 流程:
- 檢查
<dataDir>/preferences.json是否存在 - 不存在 → 呼叫
DefaultPreferences()(依runtime.GOOS回傳平台預設:macOS/WindowsOpenBrowserOnStart=true,LinuxOpenBrowserOnStart=false) - 存在但解析失敗(JSON 毀損等)→ 同樣 fallback 到
DefaultPreferences(),並發 log WARN(不擋啟動) - 存在且解析成功 → 使用使用者設定
- 使用者在 Settings 點擊 toggle → write-rename atomic pattern 寫回
preferences.json
v1 → v2 無 migration 成本:因為 v1 沒有對應檔案,v2 啟動時若 preferences.json 不存在就建立新檔(或延遲到使用者第一次改 toggle 才寫),行為是靜默的,使用者不需要知道。
Mock 模式殘留:v1 localStorage 可能有 mock 相關 key,Frontend 清理見 §6.1;與 preferences.json 無關。
8. 無障礙考量
| 項目 | 設計 |
|---|---|
| Toggle 元件 | 沿用 shadcn <Switch>,已內建 role="switch" / aria-checked |
| Tab 切換 | 沿用現有 Tabs 元件,role="tablist" / role="tab" / role="tabpanel" |
| Keyboard | ← / → 切換 tab、Tab 進入 tab panel 內部 |
| 分區標題 | 「啟動行為」區用 <h3> 讓 screen reader 感知結構 |
9. 與 v1 差異對照
| 面向 | v1 | v2 |
|---|---|---|
| 一般 tab 項目數 | 2(語言、深色模式) | 3(新增 auto-open browser) |
| 硬體 tab 項目數 | 5+(含 Mock 相關) | 3(只剩真實硬體相關) |
| Mock 模式 UI | Settings + Devices pill + First-Run Step | 全砍 |
| 模型 / 進階 tab | — | 不變 |
10. v2 → v2.1 Diff(2026-04-14)
| # | 位置 | v2 | v2.1 | 來源 |
|---|---|---|---|---|
| 1 | §2.2 落地檔案 | settings.json + 「走 Wails 既有 settings store」 |
preferences.json @ <dataDir>/ + Go server 讀寫 + write-rename atomic |
Architect Review Major 1 |
| 2 | §2.2 預設值 | 三平台一致 ON |
macOS/Windows = ON,Linux = OFF(依 DefaultPreferences() 依 runtime.GOOS) |
R5-D2 / Architect Review Major 2 |
| 3 | §2.2 新增 | — | Linux 首次使用說明(toggle 預設關、關閉時啟動進度面板仍顯示、第 5/6 階段跳過) | R5-D2 + R5-E |
| 4 | §2.3 標題 | 「重要細節」待 confirm | 「R5-D3 已定案」每次啟動都開瀏覽器,label 定版 | R5-D3 |
| 5 | §7 遷移策略 | 假設 v1 有 settings.json + mock key 遷移 |
澄清 preferences.json 是全新檔,無 v1 migration 成本 |
Architect Review Major 1 衍生 |
11. 給 Orchestrator 的提醒
R5-4 的 label 字面歧義→ 已於 R5-D3 定案(每次啟動都開,label 去掉「首次」)- 後端 Mock 清理不在 Design scope,需轉給 Architect / Backend Agent
- Devices 頁面的 Mock pill(v1
design-spec.md第三輪修訂 §4)要一併砍,此變更未在本文件細寫,但屬 R5-5a 範圍 - Linux 預設 OFF 對 E2E 測試的影響:testing Agent 在 Linux CI 上跑自動化時要注意,啟動後不會 auto-open,需手動模擬點擊「在瀏覽器開啟」或在測試前將
preferences.json改為{"openBrowserOnStart": true}
下一步:交 Frontend Agent 更新 Settings 頁面。