local-tool/: visionA-local desktop app
- M1: Wails shell + Go server + Next.js UI + Mock mode (macOS dmg ready)
- M2: i18n (zh-TW/en) + Settings 4-tab refactor
- M3: Embedded Python 3.12 runtime (python-build-standalone) + KneronPLUS wheels
- M4: Windows Inno Setup script (build on Windows runner)
- M5: Linux AppImage script + udev rule (build on Linux runner)
- M6: ffmpeg (GPL, pending legal review) + yt-dlp bundled
- Lifecycle: watchServer health check, fatal native dialog,
Wails IPC raise endpoint, stale process cleanup
.autoflow/: full PRD / Design Spec / Architecture / Testing docs
(4 rounds tri-party discussion + cross review)
.github/workflows/: macOS / Windows / Linux build CI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
296 lines
17 KiB
Markdown
296 lines
17 KiB
Markdown
# 5. 使用者流程
|
||
|
||
本章節描述三個關鍵使用者流程:**首次安裝 → First-Run → 日常使用**。每個流程都標注對應的 User Story 與驗收標準。
|
||
|
||
## 5.1 首次安裝流程(對應 US-1)
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ 1. 使用者從內部 Gitea Releases 下載安裝檔 │
|
||
│ macOS → .dmg │
|
||
│ Windows → .exe(Inno Setup) │
|
||
│ Ubuntu → .AppImage │
|
||
└────────────┬────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────┐
|
||
│ 2. 雙擊安裝檔 │
|
||
│ macOS: .dmg mount → 拖拉到 Applications │
|
||
│ 首次開啟跳 Gatekeeper 警告 │
|
||
│ → 右鍵 → 開啟(安裝頁文件說明) │
|
||
│ Win: .exe 安裝精靈(Inno Setup 預設流程) │
|
||
│ SmartScreen 警告 → 仍要執行 │
|
||
│ Linux: 給 .AppImage chmod +x → 雙擊 │
|
||
└────────────┬────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────┐
|
||
│ 3. Wails 殼啟動 → 偵測是否首次執行 │
|
||
│ 首次:開啟安裝精靈(沿用原 installer UI) │
|
||
│ 後續:跳過,直接進主畫面 │
|
||
└────────────┬────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────┐
|
||
│ 4. 安裝精靈執行以下步驟(有進度條): │
|
||
│ a. 解壓 payload 到應用資料目錄 │
|
||
│ (mac: ~/Library/Application Support/ │
|
||
│ visiona-local/;Win/Linux 依慣例) │
|
||
│ b. 建立 Python venv(優先用內嵌 Python) │
|
||
│ c. pip install --no-index wheels/ │
|
||
│ (numpy / opencv / pyusb / KneronPLUS)│
|
||
│ d. 解壓 ffmpeg binary │
|
||
│ e. 解壓預置 .nef 模型 │
|
||
│ f. 平台特定步驟: │
|
||
│ - Win: 裝 WinUSB driver(跳 UAC) │
|
||
│ - Linux: 寫入 udev rules(跳 sudo) │
|
||
│ - Mac: ad-hoc codesign dylib │
|
||
│ g. 啟動 edge-ai-server 子行程 │
|
||
│ h. 等待 server ready(http://127.0.0.1:3721)│
|
||
└────────────┬────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────┐
|
||
│ 5. 進入 First-Run 歡迎流程(見 5.2) │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
**關鍵驗收點:**
|
||
- 第 4 步 a-h 全部自動化,使用者無需任何 CLI 操作
|
||
- 若 Python fallback 失敗(系統無 Python),明確告知使用者到哪下載
|
||
- 若 Windows 拒絕 UAC,提供「手動安裝 driver」的指引
|
||
- 整個流程目標 ≤ 3 分鐘 / **上限 ≤ 5 分鐘**(一般硬體 + SSD)— 第四輪 R4-4 決策
|
||
|
||
## 5.2 First-Run 歡迎流程(對應 US-2)
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ Step 1 — 歡迎畫面 │
|
||
│ ┌─────────────────────────────────────┐ │
|
||
│ │ [visionA-local Logo(沿用 EAP)] │ │
|
||
│ │ │ │
|
||
│ │ 「邊緣 AI 推論,裝起來就能跑」 │ │
|
||
│ │ │ │
|
||
│ │ [開始使用] [稍後再說] │ │
|
||
│ └─────────────────────────────────────┘ │
|
||
└────────────┬────────────────────────────┘
|
||
│(點擊「開始使用」)
|
||
▼
|
||
┌─────────────────────────────────────────┐
|
||
│ Step 2 — 執行模式選擇 │
|
||
│ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │ 🟢 真實硬體 │ │ 🟡 Mock 模式 │ │
|
||
│ │ │ │(先看看) │ │
|
||
│ │ 需要 Kneron │ │ 無需硬體 │ │
|
||
│ │ KL720/KL730 │ │ 假裝置 + 假推論│ │
|
||
│ │ USB 裝置 │ │ │ │
|
||
│ │ │ │ │ │
|
||
│ │ [選擇] │ │ [選擇] │ │
|
||
│ └──────────────┘ └──────────────┘ │
|
||
│ │
|
||
│ 預設:真實硬體(依據 Q8) │
|
||
└────────────┬────────────────────────────┘
|
||
│
|
||
├─── 選真實硬體 ───▶ Step 3a(硬體偵測)
|
||
│
|
||
└─── 選 Mock ──────▶ Step 3b(Mock 準備)
|
||
|
||
┌─────────────────────────────────────────┐
|
||
│ Step 3a — 硬體偵測(真實模式) │
|
||
│ 「請插上 Kneron 裝置…」 │
|
||
│ [自動掃描 USB,持續 10 秒] │
|
||
│ ├ 成功:顯示偵測到的裝置卡片 │
|
||
│ │ [前往 Workspace] │
|
||
│ └ 失敗:顯示排錯清單 │
|
||
│ 1. 確認 USB 已插好 │
|
||
│ 2. 試試 USB 3.0 埠 │
|
||
│ 3. 重插一次 │
|
||
│ 4. 檢查驅動是否安裝 │
|
||
│ [重試] [切換 Mock 模式] │
|
||
└─────────────────────────────────────────┘
|
||
|
||
┌─────────────────────────────────────────┐
|
||
│ Step 3b — Mock 模式準備 │
|
||
│ 「已進入 Mock 模式,您將看到 3 個假裝置」 │
|
||
│ [進入 Dashboard] │
|
||
└─────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────────┐
|
||
│ 完成 → 進入 Dashboard │
|
||
│ 右上角顯示目前模式(真實 / Mock) │
|
||
│ 主視窗標題列 + sidebar 底部狀態列同步顯示模式│
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
**關鍵驗收點:**
|
||
- AC-2.1:Mock 模式是一鍵選項(非預設)
|
||
- AC-2.2:進入 Mock 後 ≤ 30 秒看到假推論(首次)/ ≤ 15 秒(回訪)— 第四輪 R4-7 拆兩級
|
||
- AC-2.3:Mock 模式有明確視覺標記(主視窗標題列 + 首頁徽章 + sidebar 底部狀態列)
|
||
- AC-2.4:Mock 模式**不 spawn Python sidecar**,純前端 state + Go server(對應 nonfunctional §6.1 的 Mock idle RAM ≤ 600MB 預算)
|
||
- 三步都可「稍後再說」跳過,直接進 Dashboard
|
||
|
||
## 5.3 日常使用流程
|
||
|
||
### 5.3.1 典型使用會話(FAE 在客戶現場)
|
||
|
||
```
|
||
1. 使用者從 app 目錄或桌面捷徑開啟 visionA-local
|
||
↓
|
||
2. Wails 殼啟動 → 跳過 First-Run(已完成)
|
||
↓
|
||
3. 啟動 edge-ai-server 子行程(< 2 秒)
|
||
↓
|
||
4. 主視窗開啟 → Dashboard
|
||
↓
|
||
5. 使用者插上 Kneron USB
|
||
↓
|
||
6. Devices 頁自動顯示新裝置(WebSocket push)
|
||
↓
|
||
7. 使用者點「Connect」→ 進入 Workspace
|
||
↓
|
||
8. 選 webcam + 選模型 → 點 Start
|
||
↓
|
||
9. 看到 MJPEG 串流 + 推論 overlay
|
||
↓
|
||
10. demo 完畢 → 點 Stop → 關閉主視窗 → 程式退出(Q7 傳統式)
|
||
```
|
||
|
||
**關鍵驗收點:**
|
||
- 步驟 3 到步驟 9 整段 ≤ 30 秒
|
||
- 步驟 5 到步驟 6(USB 偵測)≤ 3 秒
|
||
- 步驟 7 到步驟 9(connect 到第一幀)≤ 10 秒
|
||
|
||
### 5.3.2 跨會話狀態持久化
|
||
|
||
> **路徑說明(第三輪 Q-E1 + 第四輪 R4-5)**:資料目錄名統一全小寫為 `visiona-local`(對齊 Bundle ID `com.innovedus.visiona-local` 與 Linux 檔案系統慣例)。macOS 採 OS 慣例路徑 `~/Library/Application Support/visiona-local/`;Windows 預期為 `%APPDATA%\visiona-local\`;Linux 預期為 `~/.local/share/visiona-local/` 或 `$XDG_DATA_HOME/visiona-local/`。以下以 `<APPDATA>` 表示該目錄。
|
||
|
||
| 狀態 | 儲存位置 | 是否跨會話保留 |
|
||
|------|---------|----------------|
|
||
| 上次選的模型 | `<APPDATA>/config.json` | ✅ 是 |
|
||
| 上次選的 webcam | `<APPDATA>/config.json` | ✅ 是 |
|
||
| 上次的模式(真實 / Mock) | `<APPDATA>/config.json` | ✅ 是 |
|
||
| 上傳的自訂模型 | `<APPDATA>/models/` | ✅ 是 |
|
||
| 推論歷史 / 日誌 | `<APPDATA>/logs/` | ✅ 是(滾動保留) |
|
||
| 語言偏好 | `<APPDATA>/config.json` | ✅ 是 |
|
||
| 深色模式 | N/A | 跟隨系統,無覆寫 |
|
||
|
||
### 5.3.3 快速操作流程(原 Tray 流程 — 已砍)
|
||
|
||
> **第三輪 Q-A 決策**:系統列 tray 已砍掉。原本透過 tray 提供的快速操作(顯示主視窗、Server 狀態、快速動作、模式切換、結束)改由以下方式提供:
|
||
>
|
||
> | 原 Tray 項目 | 新的入口 |
|
||
> |-------------|---------|
|
||
> | 顯示主視窗 | 桌面 / Dock / 工作列 icon(OS 原生行為) |
|
||
> | Server 狀態 | Dashboard 的 Server 狀態卡片 + sidebar 底部狀態列 |
|
||
> | 快速動作(新增裝置 / 上傳模型 / 開啟工作區)| 原生 menu bar:`File → New Device / Upload Model / Open Workspace` |
|
||
> | 模式切換(真實 / Mock)| Settings 一般分頁;或 Dashboard 右上角的模式指示器 |
|
||
> | 關於 | 原生 menu bar:`Help → About` |
|
||
> | 結束(⌘Q)| 原生 menu bar + OS 標準快捷鍵 |
|
||
>
|
||
> Q7 已決定「關閉視窗 = 結束程式」,搭配 tray 被砍,整體生命週期就是「打開 = 跑、關閉 = 結束」的傳統桌面 app 模式。
|
||
|
||
## 5.4 錯誤處理流程
|
||
|
||
### 5.4.1 Port 3721 被占用
|
||
|
||
```
|
||
Server 啟動失敗 → 顯示錯誤對話框:
|
||
「連接埠 3721 已被其他程式占用。
|
||
請關閉占用該埠的程式,或在 Settings 中變更 server 埠號。」
|
||
[設定埠號] [結束]
|
||
```
|
||
|
||
### 5.4.2 Python venv 建立失敗
|
||
|
||
```
|
||
First-Run 步驟 4b 失敗 → 顯示錯誤對話框:
|
||
「無法建立 Python 執行環境。
|
||
可能原因:
|
||
- 系統 Python 版本不符(需要 3.10+)
|
||
- 磁碟空間不足(需要 ~500MB)
|
||
- 權限不足
|
||
[檢視日誌] [重試] [結束]」
|
||
```
|
||
|
||
### 5.4.3 KneronPLUS wheel 安裝失敗
|
||
|
||
```
|
||
First-Run 步驟 4c 失敗 → 顯示錯誤對話框:
|
||
「KneronPLUS SDK 安裝失敗。
|
||
請確認:
|
||
- 已允許 UAC 提權(Windows)
|
||
- 已安裝 libusb(Linux:sudo apt install libusb-1.0-0)
|
||
[檢視日誌] [重試] [結束]」
|
||
```
|
||
|
||
### 5.4.4 Mac Gatekeeper 警告
|
||
|
||
```
|
||
首次開啟 → Mac 跳出「無法開啟,因為來自未識別的開發者」
|
||
→ First-Run 歡迎頁提供說明:
|
||
「第一次開啟時,請在 Finder 中對 visionA-local 按右鍵,
|
||
選擇『開啟』,然後確認警告。
|
||
這是因為 visionA-local 未購買 Apple notarization。」
|
||
```
|
||
|
||
### 5.4.5 Windows SmartScreen 警告
|
||
|
||
```
|
||
首次下載執行 → SmartScreen 跳出警告
|
||
→ 發佈說明頁提供引導:
|
||
「點選『更多資訊』→『仍要執行』。
|
||
這是因為 visionA-local 未購買 Windows 程式碼簽章。」
|
||
```
|
||
|
||
## 5.5 Single-instance 行為與第二次雙擊 UX(第四輪補)
|
||
|
||
**背景**:visionA-local 以 single-instance 模式運作(單一程式實例),避免多個 Wails 殼搶 Go server 的 127.0.0.1:3721 port。實作細節請參考 Architect 的 `04-architecture/lifecycle.md`(single-instance lock 章節)。
|
||
|
||
**PRD 層級要求的 UX 行為**:
|
||
|
||
| 情境 | 預期行為 | 驗收點 |
|
||
|------|---------|--------|
|
||
| 第一次雙擊 icon(無已開啟的 visionA-local) | 正常啟動,走 First-Run 或直達 Dashboard | 與 5.1 / 5.2 流程一致 |
|
||
| **第二次雙擊 icon(已有 visionA-local 在前景)** | **把既有視窗帶到前景 + focus**,**不開第二個視窗**、**不顯示錯誤** | 無閃爍、無崩潰 |
|
||
| **第二次雙擊 icon(已有 visionA-local 但視窗最小化 / 隱藏)** | **把既有視窗還原並帶到前景 + focus** | 使用者不會以為「怎麼沒反應」 |
|
||
| **第二次雙擊 icon(已有 visionA-local 但 Go server 已 crash)** | 第二個實例偵測到 lock 殘留但 server 不在,清理 lock 後正常啟動 | 不該無限卡住 |
|
||
|
||
**快捷鍵相關**:
|
||
- 原生 menu bar `File → 重啟 Server` 的快捷鍵為 **⌘Shift+R**(macOS)/ **Ctrl+Shift+R**(Win/Linux)— 第四輪 R4-6 決策:從原 `⌘R` 改為 `⌘Shift+R`,避免與瀏覽器 reload 的肌肉記憶衝突
|
||
- 原本規畫的 `⌘Shift+W` 取消(⌘W / ⌘4 已可關閉視窗)— 第四輪 R4-6 決策
|
||
- 其餘快捷鍵維持:`⌘Q` 結束、`⌘W` 關閉視窗(= 結束,Q7 傳統式)、`⌘,` 開 Settings、`⌘1-⌘4` 切換主導航
|
||
|
||
**第二次雙擊的具體 Design 規格待 Design Agent 在 `03-design/spec/` 補齊**(動畫時間、focus ring 表現、Dock icon bounce 等細節)。PRD 層級只定義行為意圖,不定義視覺細節。
|
||
|
||
## 5.6 OS 通知策略(第四輪 R4-8 決策)
|
||
|
||
visionA-local 採**分層通知策略**,不是所有事件都走原生 OS 通知,避免噪音與跨平台一致性問題。
|
||
|
||
| 事件 | 通知管道 | 理由 |
|
||
|------|---------|------|
|
||
| 裝置連線成功(USB 插入 + connect OK) | **App 內 toast**(右下角,auto-dismiss 3 秒)| 使用者 app 已在前景,OS 通知是多餘噪音;跨平台一致 |
|
||
| 裝置斷線(USB 拔出 / connect 失敗) | **App 內 toast**(右下角,auto-dismiss 5 秒 + 錯誤色)| 同上 |
|
||
| 模型上傳完成 | **App 內 toast** | 同上 |
|
||
| 推論開始 / 停止 | **狀態列更新 + 無 toast**(過於頻繁,改用持續性狀態指示) | 避免噪音 |
|
||
| First-Run 步驟完成 | **步驟條更新 + 無 toast** | First-Run 本身就是向導,不需額外通知 |
|
||
| **Server 崩潰**(Go server 意外退出)| **shell out 原生 OS 通知**(`osascript` on macOS / PowerShell `New-BurntToastNotification` 或 WinRT on Windows / `notify-send` on Linux)+ app 內錯誤對話框 | 重大錯誤,使用者可能切到其他視窗,必須確保看到 |
|
||
| **Python sidecar 崩潰**(推論 backend 掛了)| **shell out 原生 OS 通知** + app 內錯誤對話框 | 同上 |
|
||
| **致命錯誤**(無法啟動、依賴缺失)| **app 啟動對話框**(blocking) | 無 app 可用,必須擋住使用者 |
|
||
|
||
### 實作要求
|
||
|
||
- **App 內 toast** 沿用原 edge-ai-platform 的 `sonner` 或 shadcn toast 元件
|
||
- **原生 OS 通知** 採 shell out 策略(不引入 go-toast 等第三方 binding,避免增加依賴與打包複雜度)
|
||
- macOS:`osascript -e 'display notification "..." with title "visionA-local"'`
|
||
- Windows:PowerShell `New-BurntToastNotification` 或直接用 Wails 提供的 `runtime.MessageDialog`(如支援)
|
||
- Linux:`notify-send "visionA-local" "..."`
|
||
- 若 shell out 失敗(工具不存在),靜默 fallback 到 app 內錯誤對話框
|
||
- **權限要求**:macOS 首次顯示原生通知時會觸發系統通知權限請求,First-Run 需在文案裡提及「本 app 在出現嚴重錯誤時會通知你」
|
||
|
||
### 驗收點
|
||
|
||
- AC-7.1(新增):裝置連/斷僅以 app 內 toast 呈現,不觸發系統通知
|
||
- AC-7.2(新增):Go server 或 Python sidecar 崩潰時,使用者就算切到其他視窗也能透過系統通知得知
|
||
- AC-7.3(新增):macOS 的通知權限請求時機在 First-Run 或首次崩潰時才觸發,不在 app 啟動時無緣無故詢問
|