# 頁面結構規格 — visionA Cloud > 本文件逐頁列出所有頁面的版型、主要區塊、互動重點與雲端版改動。 > > - **沿用頁面**:版型與行為 100% 沿用 local-tool,只改 API base URL 與新增遠端狀態顯示 > - **雲端新增 stub**:Phase 0 雛形只做低保真骨架,Phase 1 完整化 > - **雲端新增完整**:本次完整設計,工程師可直接實作 --- ## 頁面總覽 | 路由 | 類型 | 主要元件 | Phase 0 狀態 | |------|------|---------|-------------| | `/` | 沿用 | Dashboard(Stats + Activity + Devices) | 沿用 + 小調整 | | `/login` | 新增 stub | 登入表單 | Stub(簡化) | | `/register` | 新增 stub | 註冊表單 | Stub(簡化) | | `/account` | 新增 stub | 帳號設定 | Stub(單頁) | | `/devices` | 沿用 | 裝置列表 | 沿用 + 改造 | | `/devices/pair` | 新增 | Pairing 流程 | **完整設計** | | `/devices/[id]` | 沿用 | 裝置詳情 | 沿用 + 遠端狀態 | | `/models` | 沿用 | 模型庫 | 沿用 | | `/models/[id]` | 沿用 | 模型詳情 | 沿用 | | `/clusters` | 從 POC 搬 | 叢集列表 | 沿用 POC 設計 | | `/workspace` | 沿用 | 工作區選擇 | 沿用 + 遠端狀態 | | `/workspace/[deviceId]` | 沿用 | 推論操作 | 沿用 + 掉線降級 | | `/settings` | 沿用 | 設定 | 沿用 + 小調整 | --- ## 1. `/` — Dashboard(儀表板) **類型**:沿用 + 小調整 ### 1.1 既有版型(不變) ``` ┌─────────────────────────────────────────────────────────┐ │ 標題 + 副標題 │ ├─────────────────────────────────────────────────────────┤ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ StatCard │ │ StatCard │ │ StatCard │ │ StatCard │ │ │ │ 模型數 │ │ 裝置數 │ │ 已連線 │ │ 燒錄次數 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ ├─────────────────────────────────────────────────────────┤ │ ┌──────────────────────┐ ┌──────────────────────┐ │ │ │ ConnectedDevicesList │ │ ActivityTimeline │ │ │ │(已連線裝置) │ │(近期活動) │ │ │ └──────────────────────┘ └──────────────────────┘ │ ├─────────────────────────────────────────────────────────┤ │ Quick Actions │ │ [瀏覽模型] [管理裝置] [上傳模型] │ └─────────────────────────────────────────────────────────┘ ``` ### 1.2 雲端版調整 | 項目 | 改動 | |------|------| | 標題 | `visionA Local` → `visionA Cloud` | | StatCard「已連線」 | 指「線上遠端裝置」,不再是 USB 連接狀態 | | ConnectedDevicesList | 每個項目右側新增 `RemoteDeviceBadge`(離線 / 最後心跳)| | OnboardingDialog | Phase 0 暫時移除(或改為「去配對裝置」CTA) | | Quick Actions | 新增「配對裝置(Pair Device)」按鈕,導向 `/devices/pair` | ### 1.3 空狀態 當使用者是第一次進入(沒有裝置、沒有活動): ``` ┌─────────────────────────────────────────────────────────┐ │ 🔗 │ │ 還沒有任何裝置 │ │ 配對你的第一台 Kneron 裝置,開始雲端推論之旅 │ │ │ │ [配對裝置] │ └─────────────────────────────────────────────────────────┘ ``` 使用 `EmptyState` 元件,Icon=Lucide `Link2`,action=跳 `/devices/pair`。 ### 1.4 互動重點 - StatCard 點擊 → 跳對應列表頁 - ConnectedDevicesList 點擊裝置 → 跳 `/workspace/[deviceId]` - ActivityTimeline 自動 polling / WebSocket 更新(每 5 秒 or 即時) --- ## 2. `/login` — 登入(新增 stub) **類型**:新增 stub(Phase 0 簡化,Phase 1 完整化) ### 2.1 Phase 0 版型 ``` ┌─────────────────────────────────────────────────────────┐ │ │ │ │ │ [Logo] visionA Cloud │ │ Edge AI Platform │ │ │ │ ┌────────────────────────────────┐ │ │ │ Email │ │ │ │ ┌────────────────────────┐ │ │ │ │ │ you@example.com │ │ │ │ │ └────────────────────────┘ │ │ │ │ │ │ │ │ Password │ │ │ │ ┌────────────────────────┐ │ │ │ │ │ •••••••• │ │ │ │ │ └────────────────────────┘ │ │ │ │ │ │ │ │ [ 登入 ] │ │ │ │ │ │ │ │ ────── 還沒有帳號? ────── │ │ │ │ [ 建立新帳號 ] │ │ │ └────────────────────────────────┘ │ │ │ │ 忘記密碼? | 語言切換:繁中 ▾ │ │ │ └─────────────────────────────────────────────────────────┘ ``` ### 2.2 規格 - **Layout**:無 Sidebar / Header 的獨立版型(`app/(auth)/layout.tsx`) - **容器**:`max-w-md` 置中,背景 `bg-background` - **Logo**:與 Sidebar 同一個(`/visiona-logo.png`) - **表單**:`Card` 包起來,內含 Label + Input + Button - **登入按鈕**:`variant=default` `size=default` 撐滿寬度(`w-full`) - **註冊連結**:`variant=outline` 撐滿寬度 - **底部**:忘記密碼連結 + 語言切換(小型 Select) ### 2.3 Phase 0 雛形簡化 - 送出表單**不接後端**:直接 `router.push('/')` - 表單驗證:只有「必填」(HTML5 `required`),無格式驗證 - 「忘記密碼」:灰色 disabled - 「建立新帳號」:跳 `/register` - 登入 error 狀態:不做 ### 2.4 Phase 1 待辦 - OAuth(Google / GitHub) - 密碼強度驗證、Email 格式驗證 - 「記住我」Checkbox - Email 驗證流程 - 登入失敗的明確錯誤訊息(密碼錯 / 帳號不存在 / 被鎖) - Rate limit 提示 - 雙因素驗證(2FA) ### 2.5 響應式 - Desktop / Tablet / Mobile 都單欄置中,自然 responsive - Mobile:表單寬度自適應 `w-full` + padding `px-4` ### 2.6 i18n key(新增) ``` auth.login.title → 登入 / Sign in auth.login.subtitle → 歡迎回到 visionA Cloud auth.login.email → Email auth.login.password → 密碼 / Password auth.login.submit → 登入 auth.login.forgotPassword → 忘記密碼? auth.login.noAccount → 還沒有帳號? auth.login.createAccount → 建立新帳號 ``` ### 2.7 無障礙 - 表單 Label 與 Input `htmlFor` / `id` 對應 - Email input `type="email" autoComplete="email"` - Password input `type="password" autoComplete="current-password"` - 提交按鈕在 Input 聚焦時 Enter 可觸發 - Tab 順序:Email → Password → 登入 → 建立新帳號 → 忘記密碼 → 語言 --- ## 3. `/register` — 註冊(新增 stub) **類型**:新增 stub ### 3.1 Phase 0 版型 與 `/login` 類似,差異: ``` 標題:建立帳號 表單欄位: - Email(必填) - 密碼(必填) - 確認密碼(必填,與密碼相同) 按鈕:[建立帳號] → 成功後跳 /devices/pair(引導第一次配對) 返回連結:已有帳號? [登入] ``` ### 3.2 雛形簡化 - 送出不接 API,直接 `router.push('/devices/pair')`(引導第一次 Pairing) - 密碼確認檢查:用 client-side 即時比對(失焦驗證) - 無 ToS / Privacy Policy 勾選(Phase 1 補) ### 3.3 Phase 1 待辦 - Email 驗證流程 - 密碼強度指示器 - ToS / Privacy Policy 勾選 - 防機器人(reCAPTCHA / Turnstile) - 重複 Email 檢查 --- ## 4. `/account` — 帳號設定(新增 stub) **類型**:新增 stub(Phase 0 單頁,Phase 1 拆成多頁) ### 4.1 Phase 0 版型 ``` ┌─────────────────────────────────────────────────────────┐ │ 帳號設定 │ │ 管理你的個人資料與偏好 │ ├─────────────────────────────────────────────────────────┤ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 個人資料 │ │ │ │ Email jim@example.com(不可編輯) │ │ │ │ 顯示名稱 [Jim Chen____________] [儲存] │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 已配對的裝置 │ │ │ │ • KL520 (192.168.1.23) 配對於 04/18 [解除配對] │ │ │ │ • KL720 (office-mac) 配對於 04/21 [解除配對] │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 危險區(Danger Zone) │ │ │ │ 刪除帳號 [刪除帳號] │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` ### 4.2 規格 - 使用既有 `Tabs` or 單頁 `Card` 多區塊(雛形選單頁) - 每個區塊 `Card`,內含 Header + Content - 危險區使用 `destructive` 變體 ### 4.3 雛形簡化 - 所有操作不接 API,按鈕點擊只顯示 toast「此功能開發中」 - 資料顯示為假資料(mock) - 「刪除帳號」按下後只顯示 AlertDialog,確認後也不真執行 ### 4.4 Phase 1 TODO - 拆成子路由 `/account/profile`、`/account/devices`、`/account/api-keys`、`/account/sessions` - 頭像上傳 - 密碼變更 - API Keys 管理 - Session 管理(顯示登入過的裝置 / 瀏覽器) - Billing 頁面 - 團隊 / 組織切換 --- ## 5. `/devices` — 裝置列表(沿用 + 改造) **類型**:沿用版型,改造行為 ### 5.1 既有版型 ``` ┌─────────────────────────────────────────────────────────┐ │ 裝置 [安裝 USB Driver] [掃描] │ │ 管理你的 Edge AI 裝置 │ ├─────────────────────────────────────────────────────────┤ │ [⚠ udev hint banner,需要時顯示] │ ├─────────────────────────────────────────────────────────┤ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Device │ │ Device │ │ Device │ │ │ │ Card │ │ Card │ │ Card │ │ │ └──────────┘ └──────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────┘ ``` ### 5.2 雲端版改造 | 項目 | 改動 | |------|------| | 右上按鈕 | **移除**「安裝 USB Driver」「掃描」(local-tool 限定);**新增** `[配對新裝置]` → 導向 `/devices/pair` | | udev hint banner | **移除**(雲端版不需要)| | DeviceCard | 右上角狀態從 `DeviceStatusBadge` 改為 `RemoteDeviceBadge`;顯示「最後心跳」 | | 空狀態 | 無裝置時顯示:「還沒有配對的裝置,[配對第一台裝置] →」| | 排序 / 篩選 | Phase 0 維持原樣(按建立時間排序);Phase 1 加篩選「在線 / 全部」 | ### 5.3 空狀態設計 ``` ┌─────────────────────────────────────────────────────────┐ │ 🔗 │ │ 還沒有配對的裝置 │ │ 在你的電腦上執行 local agent 並完成配對, │ │ 就能從任何地方存取你的 Kneron 裝置 │ │ │ │ [配對第一台裝置] [查看配對說明] │ └─────────────────────────────────────────────────────────┘ ``` --- ## 6. `/devices/pair` — Pairing 流程(新增 — 完整設計) **類型**:新增,雲端版核心流程。 **完整設計見** [`flows/flow-pairing.md`](flows/flow-pairing.md) 與 [`wireframes/wf-pairing.md`](wireframes/wf-pairing.md)。 ### 6.1 簡要概念 三步式 Stepper: ``` [1] 取得 Token → [2] 下載 / 設定 local agent → [3] 確認連線 ``` - 第 1 步:`PairingTokenCard`(見 `components.md` 10.2) - 第 2 步:平台選擇(Mac / Windows / Linux)→ 顯示下載連結 + 一行設定指令 - 第 3 步:即時狀態(polling `/api/pairing/status?token=...`)→ 成功後自動跳 `/devices` --- ## 7. `/devices/[id]` — 裝置詳情(沿用 + 遠端狀態) **類型**:沿用版型 + 小擴充 ### 7.1 既有版型 ``` ┌─────────────────────────────────────────────────────────┐ │ ← 返回 │ │ [裝置名稱] (alias) │ │ [原始名稱] │ │ [DeviceStatusBadge] [燒錄] [開啟工作區] [中斷] │ ├─────────────────────────────────────────────────────────┤ │ ┌──────────────────────┐ ┌──────────────────────┐ │ │ │ 裝置資訊 │ │ 模型狀態 │ │ │ │ ID / 類型 / 韌體 / Port│ │ 已燒錄模型 / 準備狀態 │ │ │ └──────────────────────┘ └──────────────────────┘ │ │ ┌──────────────────────┐ ┌──────────────────────┐ │ │ │ DeviceHealthCard │ │ DeviceConnectionLog │ │ │ └──────────────────────┘ └──────────────────────┘ │ │ DeviceSettingsCard(alias / notes) │ └─────────────────────────────────────────────────────────┘ ``` ### 7.2 雲端版擴充 | 項目 | 改動 | |------|------| | 標題區狀態 | `DeviceStatusBadge` → `RemoteDeviceBadge`(顯示最後心跳時間)| | DeviceHealthCard | 新增 `Pairing Token`(遮罩顯示後 4 碼)、`配對時間`、`所在電腦 hostname`(local agent 提供)| | DeviceConnectionLog | 新增 `tunnel reconnect` 事件 | | DeviceSettingsCard | 新增「解除配對」按鈕(destructive)| ### 7.3 掉線降級 當裝置 `RemoteDeviceBadge.status === 'offline'`: - 大型警告橫幅:「此裝置目前離線,部分操作無法使用」 - 「燒錄」「開啟工作區」按鈕 disabled - 顯示最後已知狀態(韌體版本、已燒錄模型等,讀自 cache) - 「解除配對」仍可用 --- ## 8. `/models`、`/models/[id]`、`/workspace`、`/settings`(沿用) ### 8.1 `/models` — 模型庫 - 版型完全沿用(`ModelGrid` + `ModelFilters` + `ModelUploadDialog` + 比較模式) - 雲端版差異:上傳 `.nef` 走雲端儲存(S3-compat),UI 不變 - 空狀態使用既有 `EmptyState` ### 8.2 `/models/[id]` — 模型詳情 - 完全沿用 - 「部署至裝置」的 FlashDialog 會列出**使用者所有在線遠端裝置** ### 8.3 `/workspace` — 工作區選擇 - 版型沿用(卡片網格,每個是可開啟工作區的裝置) - 雲端版:卡片上顯示 `RemoteDeviceBadge`;離線裝置卡片 `opacity-50` 且 disabled 無法點擊 - 空狀態保持:「沒有已連線的裝置,前往裝置管理」 ### 8.4 `/workspace/[deviceId]` — 推論操作介面 - 版型完全沿用(左側 CameraInferenceView + 右側 InferencePanel) - **新增掉線降級**: - 頂部新增 `RemoteDeviceBadge`,顯著顯示狀態 - 裝置掉線時: - 停止推論(前端主動呼叫 stop) - 顯示全頁遮罩:「裝置已離線,請稍候或返回裝置列表」+ 兩個按鈕 `[返回]` `[重試]` - Camera stream 暫停,顯示「連線中斷」占位圖 ### 8.5 `/settings` — 設定 - 版型沿用 Tabs(一般 / 硬體 / 模型 / 進階) - 雲端版調整: - **「硬體」分頁**:Phase 0 暫時隱藏或改名(雲端版使用者看不到自己電腦的 Python runtime);Phase 1 改為「Local Agent 設定」 - **「進階」分頁**:`ServerStatusDashboard` / `ServerLogViewer` 暫時隱藏;`Backend URL` 可改為「雲端 API Endpoint」(開發者可切 staging / production) - 「一般」分頁不變 --- ## 9. `/clusters` — 叢集列表(從 POC 搬) **類型**:從 `edge-ai-platform` POC 搬,視覺對齊既有版型 ### 9.1 版型(已在 POC 存在) ``` ┌─────────────────────────────────────────────────────────┐ │ 叢集 [建立叢集] │ │ 管理你的多裝置推論叢集 │ ├─────────────────────────────────────────────────────────┤ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Cluster │ │ Cluster │ │ Cluster │ │ │ │ Card │ │ Card │ │ Card │ │ │ └──────────┘ └──────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────┘ ``` 每個 `ClusterCard`(見 POC `cluster-card.tsx`): - 叢集名稱 + 狀態 Badge(idle / inferencing / degraded) - 裝置數量、模型 - 裝置列表(每個顯示 deviceName + type + weight) - 操作:[開啟工作區] / [刪除] ### 9.2 雲端版調整 | 項目 | 改動 | |------|------| | 裝置列表顯示 | 每個裝置項目新增 `RemoteDeviceBadge`(顯示在線狀態)| | degraded 狀態 | Badge 旁新增 tooltip 說明「某裝置離線,已自動降級」| | 建立叢集 Dialog | Device 選擇只列出「在線」裝置 | ### 9.3 空狀態 ``` 還沒有叢集 叢集讓你把多台 Kneron 裝置組合起來做平行推論 [建立第一個叢集](disabled 當沒有任何裝置時) ``` ### 9.4 `/workspace/cluster/[clusterId]` — 叢集工作區 - 從 POC 搬(`workspace/cluster/[clusterId]/cluster-workspace-client.tsx`) - 視覺對齊單裝置 Workspace,版型相似 - 裝置狀態列顯示所有叢集成員的 `RemoteDeviceBadge` - 任一裝置離線 → 狀態列顯示「降級執行中(X/Y 裝置在線)」 --- ## 10. 頁面互動總表 | 頁面 | 主要互動 | 資料載入方式 | |------|---------|-------------| | `/` | 讀取 stats、裝置、活動 | useEffect + polling / WS | | `/login` | 提交登入 | form submit | | `/register` | 提交註冊 | form submit | | `/account` | 編輯個人資料 | form submit | | `/devices` | 列表、配對 CTA | useEffect + WS | | `/devices/pair` | 產 token、複製、輪詢 | polling(`/api/pairing/status`) | | `/devices/[id]` | CRUD 裝置設定、燒錄、開工作區 | useEffect + WS | | `/models` | 篩選、上傳、比較 | useEffect | | `/models/[id]` | 檢視、部署、刪除 | useEffect | | `/clusters` | 建立、開啟工作區、刪除 | useEffect | | `/workspace` | 選擇裝置 | useEffect | | `/workspace/[deviceId]` | 推論控制(start/stop/source) | useEffect + WS | | `/workspace/cluster/[id]` | 叢集推論 | useEffect + WS | | `/settings` | 切語言、主題、重置 | localStorage | --- ## 11. 響應式表現(逐頁) | 頁面 | Mobile (< 640px) | Tablet (640–1024) | Desktop (≥ 1024) | |------|-----------------|-------------------|-----------------| | `/` | 降級(單欄)| 單欄 | 4 欄 Stats + 2 欄主內容 | | `/login` / `/register` | 可用 | 可用 | 可用 | | `/devices` / `/models` / `/clusters` | 單欄卡片 | 2 欄 | 3 欄 | | `/devices/pair` | 可用(步驟堆疊)| 可用 | 可用(步驟橫排)| | `/workspace/[deviceId]` | **不支援**(顯示提示「請用桌面版」)| 簡化(上下排)| 左右分欄 | | `/settings` | 單欄 Tab | 單欄 | 單欄(Tab 橫排)| **雛形 Mobile 策略**: - Sidebar 改 Sheet(drawer),漢堡選單觸發 - 非關鍵頁面能用,但不保證完整體驗 - `/workspace/[deviceId]` 這類需要大畫面的,顯示:「建議使用桌面版以獲得最佳體驗」 --- ## 12. 頁面載入策略 所有頁面: | 載入階段 | 顯示 | |---------|------| | 0–200ms | 什麼都不顯示(避免閃爍) | | 200ms–資料回傳 | Skeleton(灰色塊,shimmer 動畫可選)| | 資料回傳 | 內容顯示 | | 資料錯誤 | 錯誤狀態 + 重試按鈕 | | 資料為空 | EmptyState | Skeleton 使用 shadcn 慣例 `bg-muted animate-pulse`,已在 `device-detail-client.tsx` 示範。