依 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>
240 lines
13 KiB
Markdown
240 lines
13 KiB
Markdown
# 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)<br>路徑:<br>• macOS `~/Library/Application Support/visiona-local/preferences.json`<br>• Windows `%APPDATA%\visiona-local\preferences.json`<br>• Linux `~/.local/share/visiona-local/preferences.json` |
|
||
| 儲存機制 | **Go server 端負責讀寫**(`visiona-local/preferences.go`,非 Wails 內建機制 — Wails v2 沒有 settings store)<br>JSON 格式:`{"openBrowserOnStart": true}`<br>原子寫入:**write-rename pattern**(`os.WriteFile(path+".tmp", ...)` → `os.Rename(path+".tmp", path)`),POSIX / Windows 均原子 |
|
||
| 讀取失敗 fallback | 呼叫 `DefaultPreferences()`,依 `runtime.GOOS` 回傳平台預設:<br>`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 | (若存在於 Devices 頁面的 Mock 標籤)
|
||
| `dashboard.tryMockHint` | 或切換到 Mock 模式試用 | (若 Dashboard 空狀態有這句)
|
||
|
||
### 5.3 type 檔同步
|
||
|
||
`frontend/src/lib/i18n/types.ts` 對應 interface 欄位全砍,確保 TypeScript 編譯不留 dangling reference。
|
||
|
||
---
|
||
|
||
## 6. 清理殘留的 Mock 程式碼
|
||
|
||
Settings 改完後,前後端其他地方可能仍有 Mock 殘留:
|
||
|
||
### 6.1 前端
|
||
- `frontend/src/stores/` 任何 `mock` state / action
|
||
- `frontend/src/components/` 任何 `Mock` badge / pill
|
||
- `frontend/src/app/devices/` 頁面右上的「真實 / Mock」切換(v1 `design-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 流程**:
|
||
|
||
1. 檢查 `<dataDir>/preferences.json` 是否存在
|
||
2. **不存在** → 呼叫 `DefaultPreferences()`(依 `runtime.GOOS` 回傳平台預設:macOS/Windows `OpenBrowserOnStart=true`,Linux `OpenBrowserOnStart=false`)
|
||
3. **存在但解析失敗**(JSON 毀損等)→ 同樣 fallback 到 `DefaultPreferences()`,並發 log WARN(不擋啟動)
|
||
4. **存在且解析成功** → 使用使用者設定
|
||
5. 使用者在 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 的提醒
|
||
|
||
1. ~~**R5-4 的 label 字面歧義**~~ → **已於 R5-D3 定案**(每次啟動都開,label 去掉「首次」)
|
||
2. **後端 Mock 清理**不在 Design scope,需轉給 Architect / Backend Agent
|
||
3. **Devices 頁面的 Mock pill**(v1 `design-spec.md` 第三輪修訂 §4)要一併砍,此變更未在本文件細寫,但屬 R5-5a 範圍
|
||
4. **Linux 預設 OFF 對 E2E 測試的影響**:testing Agent 在 Linux CI 上跑自動化時要注意,啟動後不會 auto-open,需手動模擬點擊「在瀏覽器開啟」或在測試前將 `preferences.json` 改為 `{"openBrowserOnStart": true}`
|
||
|
||
---
|
||
|
||
**下一步**:交 Frontend Agent 更新 Settings 頁面。
|