# v2.1 — Wails Server Control Panel 設計規格 > 本章對應 R5-1 / R5-2 / R5-3 / R5-4 / R5-5 / R5-5a / **R5-D1 / R5-D3 / R5-E**(v2.1 補丁) > 上層索引:`../design-spec-v2.md` > 版本:**v2.1** · 更新日期:2026-04-14 > 相關:`v2/startup-progress.md`(R5-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 | `` | 40×40 px,左側 padding 16 | static | 沿用 `frontend/icon.png` | | Product name | `

` | 16 px / SemiBold | static | 文字:`visionA-local` | | Version tag | `` | 12 px / muted-foreground | static | 文字:`v{major}.{minor}.{patch}`,右上角 | | Status indicator | `` + `` | 圓點 8 px | 見 §5 狀態機 | 顏色綁 semantic tokens | | Status text | `` | 14 px / Medium | 見 §5 | 例:`Running · Browser opened` | | Server meta | `
` | 12 px / muted | 6 個欄位 | Port / Uptime / PID(Uptime 每秒刷新) | ### 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 server`、`Restart 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` | `` | ✅ ON | 使用者往上捲動時**自動關閉**,捲到最底自動重啟。附提示 `Jump to latest` pill | | `Show timestamps` | `` | ✅ ON | 關閉後 log 行去掉時間戳 | | `Filter` | `` | 空 | 即時字串過濾,無 regex;`⌘F` / `Ctrl+F` 聚焦 | ### 4.4 Log panel(高度剩餘 flex-grow) | 屬性 | 值 | |------|---| | 字體 | `font.mono`(SF Mono / Consolas / Menlo) | | 字級 | `12 px` | | 行高 | `1.5` | | 背景 | `color.surface-1`(Light:`oklch(0.99 0 0)`;Dark:`oklch(0.18 0 0)`) | | 選取背景 | `color.primary/20` | | **最大行數** | **2000**(ring buffer,超過舊的 drop;對齊 TDD v2 Go server 常數,~400KB 記憶體可忽略) | | 寫檔 | **無**(TDD v2 採 in-memory ring buffer,log 不落地;使用者若需保存用 `Export log` 手動匯出) | | 滑入動畫 | 60 ms fade-in(`prefers-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` 保留,指向 `/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} / 2000`,12px muted | | 關閉提示 | 右 | `⚠ Closing this window will stop the server.`,12px muted | **持久提示為什麼不彈 modal**(R5-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` 綠 | — | `Running` 或 `Running · Browser opened`(Toggle ON 首次顯示 10 秒) | 啟動進度面板 fade-out;Open 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 banner**,log 面板不消失。 ### 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 容器 | `
` | 背景 `color.destructive/10`,邊框 1px `color.destructive/30`,圓角 `radius.md`,padding 16 | | 警告 icon | `` | 20×20,`color.destructive` | | 標題 | `` | 14 px SemiBold,`color.destructive` | | 說明 | `

` | 13 px,`color.foreground`,最多 2 行,溢出 `…` | | `Restart Server` | Button `primary` `sm` | 點擊 → 呼叫內部 restart,banner 轉為 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 banner(`role="alert"` 由 Wails WebView 內部顯示)**另外發送一次 OS 原生 non-blocking 通知**。這是 R5-D1 使用者決策:控制台可能被最小化、或在另一個桌面 / 虛擬桌面,使用者不一定會看到 banner,OS 通知作為次要冗餘提醒仍有價值。 | 平台 | 通知機制 | 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 為 ON(macOS/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 一個 ✓ icon(`color.success`) - Text 改為 `Running · Browser opened` - 10 秒後 ✓ icon 淡出,text 縮為 `Running` ### 7.3 例外情境 | 情境 | 控制台行為 | |------|----------| | Server `Starting` 超過 5 秒 | 進入 Error state(見 §6),**不開瀏覽器** | | Port 3721 被佔 | Server fallback 到 3722 / 3723,Header 顯示 `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 新增 key(zh-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.primary`,2 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 ``;Error banner `

`;log panel ``(新行 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. 與 v1(`design-analysis-round2-refactor.md`)的差異 | 面向 | v1 分析稿 | v2 正式規格 | |------|----------|------------| | 視窗職責 | 三方尚在討論 | 確定為雙 UI(R5-1) | | 關閉行為 | 待 D1 決策 | **關閉 = 結束 server**,footer 持久提示(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 Diff(2026-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 只有 spinner,1-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.md`(R5-E 階段化啟動進度面板) | R5-E | --- **下一步**:交 M8-5 Frontend Agent 實作(Wails 控制台 + 啟動進度面板),交 Reviewer 審查 control-panel.md + startup-progress.md 整體一致性。