visionA 雲端版前端 — 沿用 local-tool 既有 UI(原則 4:先抄 local-tool)+
新增雲端特有的登入 / 配對 / 設定流程,含以下整合階段:
- Phase 0:13 頁 + 30+ 元件 + 雛形 banner
- dashboard / devices / models / workspace / clusters / settings 等頁
- AppShell + Sidebar + Header + tokens + i18n(中英雙語 96 keys)
- API client + 5 stores + 3 hooks
- Phase 0.6:OIDC redirect 改造
- login 頁改為 OIDC redirect(`window.location.href = /api/auth/login`)
- register 改說明頁、account 改唯讀(user 資料來源是 MC)
- api client 改 cookie session(credentials: include)+ 完全清掉 localStorage
- Phase 0.7:stage 部署 + nil guard
- getApiBaseUrl() 修:browser 環境視為 same-origin(與 login 頁一致)
- login 頁加「已登入 → router.replace('/')」effect
- User type email/name 改 optional(MC id_token 不一定回 email/name claim)
- header.tsx UserMenu displayName 4 層 fallback:name → email → id → i18n
- 雛形 banner 文案更新(已接 Innovedus 帳號中心)+ 版號 Phase 0.7
驗證:pnpm lint / test (125/125) / build 全綠
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
visionA Cloud Frontend
visionA Cloud 前端 Web 應用(Next.js 16 + React 19 + Tailwind 4)。
目的:將
local-tool/的使用體驗延伸到雲端,讓使用者透過瀏覽器操作由 local agent 連入的邊緣裝置(Kneron KL520/KL720 等)。
🚧 Phase 0 雛形 — 任何功能皆以 UI 走通為目標,不做真實身分驗證、OAuth、WebSocket 即時推送、MJPEG 串流。完整功能清單見下方「雛形範圍與限制」。
規劃中的正式版請見
.autoflow/02-prd/PRD.md,架構決策見.autoflow/04-architecture/design-doc.md。
技術堆疊
| 層級 | 技術 | 版本 |
|---|---|---|
| 框架 | Next.js(App Router) | 16.1.6 |
| UI 函式庫 | React / React DOM | 19.2.3 |
| 語言 | TypeScript | ^5 |
| 樣式 | Tailwind CSS(含 @tailwindcss/postcss) |
^4 |
| 元件 primitive | Radix UI | ^1.4.3 |
| 元件規範 | shadcn new-york style(components.json) |
— |
| 圖示 | lucide-react | ^0.575.0 |
| 狀態管理 | Zustand | ^5.0.11 |
| 主題 | next-themes | ^0.4.6 |
| Toast | sonner | ^2.0.7 |
| Class 工具 | clsx + tailwind-merge + class-variance-authority | — |
| 測試 | Vitest + @testing-library/react + jsdom | ^4 / ^16 / ^28 |
| Lint | ESLint + eslint-config-next | ^9 / 16.1.6 |
版本與 local-tool/frontend/ 對齊,確保「雲端版 / 離線版同一套前端」的架構決策可執行。
前置需求
- Node.js ≥ 20
- pnpm ≥ 10
- 依賴: 需同時運行
visionA-backend(Go)。前端所有 API 呼叫會指向NEXT_PUBLIC_API_BASE,後端未啟動時功能會顯示錯誤但 UI 仍可瀏覽(多數頁面對 501 / 連線錯誤已做 graceful fallback)。
快速啟動
# 1. 安裝依賴
cd visionA-frontend
pnpm install
# 2. 設定環境變數
cp .env.local.example .env.local
# 檢查 NEXT_PUBLIC_API_BASE 是否指到正確後端位址
# 3. 啟動後端(另一個 terminal)
cd ../visionA-backend
make run # 或參考 visionA-backend/README.md
# 4. 啟動前端
cd ../visionA-frontend
pnpm dev # http://localhost:3000
進入後任何 email + 任何密碼都可登入(Phase 0 的 StaticAuthProvider)。
可用腳本
| 指令 | 說明 |
|---|---|
pnpm dev |
開發模式(Turbopack / HMR) |
pnpm build |
產線打包(output: "standalone",便於 Docker 部署) |
pnpm start |
啟動 production build |
pnpm lint |
執行 ESLint |
pnpm test |
執行 Vitest(一次性) |
pnpm test:watch |
執行 Vitest(watch mode) |
專案結構
visionA-frontend/
├── src/
│ ├── app/ # Next.js App Router 路由
│ │ ├── layout.tsx # Root layout(Theme / Locale / AppShell)
│ │ ├── page.tsx # / Dashboard
│ │ ├── login/ # /login
│ │ ├── register/ # /register(Phase 0 Coming Soon)
│ │ ├── account/ # /account 帳號設定 stub
│ │ ├── devices/ # /devices, /devices/[id], /devices/pair
│ │ ├── models/ # /models, /models/[id]
│ │ ├── workspace/ # /workspace, /workspace/[deviceId]
│ │ ├── clusters/ # /clusters(Phase 0 預告頁)
│ │ └── settings/ # /settings
│ ├── components/
│ │ ├── ui/ # Shadcn primitive(Button / Card / Input ...)
│ │ ├── layout/ # Sidebar / Header / PrototypeBanner / AppShell
│ │ ├── dashboard/ # StatCard / ActivityTimeline / ConnectedDevicesList
│ │ ├── devices/ # DeviceCard 相關
│ │ ├── models/ # ModelCard / ModelUploadDialog
│ │ ├── cloud/ # RemoteDeviceBadge
│ │ └── pairing/ # PairingTokenCard / PairingCountdown
│ ├── hooks/ # useFetch / useWebsocket / useTunnelStatus
│ ├── lib/
│ │ ├── api.ts # 統一 API client(envelope / 401 / 501 / timeout)
│ │ ├── utils.ts # cn() 等
│ │ └── i18n/ # zh-Hant / en 字典 + Context
│ ├── stores/ # Zustand stores(auth / session / device / model / activity / pairing)
│ ├── tests/ # Vitest setup
│ └── types/ # 共用型別(api / user / pairing ...)
├── public/ # 靜態資源
├── components.json # Shadcn CLI 設定
├── next.config.ts # output: standalone
├── tsconfig.json # @/* → ./src/*
└── package.json
主要頁面清單
| 路徑 | Phase 0 狀態 | 說明 |
|---|---|---|
/login |
✅ 可用 | 任意帳密皆通過(StaticAuth) |
/register |
⚠️ Coming Soon | 引導回 /login;Phase 1 才實作 |
/ Dashboard |
✅ 可用 | StatCard × 4、近期活動、快速操作;無裝置時顯示空狀態引導 /devices/pair |
/devices |
✅ 可用 | 裝置列表;RemoteDeviceBadge 顯示遠端連線狀態 |
/devices/[id] |
✅ 可用 | 裝置詳細、離線 banner |
/devices/pair |
✅ 可用(核心) | 三步配對流程:產生 Pairing Token → 15 分鐘倒數 → 輪詢 3 分鐘 |
/models |
✅ 可用 | 模型列表 + 上傳 Dialog(XHR 進度) |
/models/[id] |
✅ 可用 | 模型詳細、部署到裝置 |
/workspace |
✅ 可用 | 選擇線上裝置 |
/workspace/[deviceId] |
⚠️ Camera placeholder | 推論 Start/Stop 可按;MJPEG stream Phase 1 接上 |
/clusters |
⚠️ Phase 1 預告 | POC 有完整實作,雛形後端是 stub |
/account |
✅ 可用 stub | 顯示使用者 + 登出;其他操作是 toast 提醒 |
/settings |
✅ 可用 | 語言 / 主題 / API 端點切換 |
環境變數
| 變數 | 說明 | 預設值 | 必要 |
|---|---|---|---|
NEXT_PUBLIC_API_BASE |
雲端 API Server 位址(無尾斜線) | http://localhost:3721 |
是 |
NEXT_PUBLIC_WS_BASE |
WebSocket 位址;留空則從 API 推導 | 從 API base 推導 | 否 |
所有 runtime 變數都以 NEXT_PUBLIC_ 開頭(Next.js 要求前端可讀),不要放真正機密的值——這類值應走後端。
Phase 0 雛形範圍與限制
✅ 可做到的
- 完整 UI 骨架(Sidebar / Header / 全域雛形 Banner / Sonner toast)
- i18n(zh-Hant / en)可即時切換,key 集合兩語系強制同步
- Light / Dark / System 主題切換
- 裝置 / 模型 / 活動 三個 store 的 CRUD UI(對齊 api-spec)
- Pairing 流程:產 token → 視覺切兩行顯示(複製永遠是完整 36 字元)→ 15 分鐘倒數(3 色階段)→ 輪詢連線狀態 → 成功 toast + 跳轉
- 離線降級:
RemoteDeviceBadge+ 頁面離線 Banner + Workspace 遮罩 - 模型上傳:XHR progress + presigned URL 直送 storage
❌ Phase 0 刻意不做(Phase 1 接手)
- 任何帳密可登入 — 後端
StaticAuthProvider回demo-user;重啟後端後前端 localStorage 的 token 雖然還在,但伺服器上沒有任何 session 資料 - OAuth / 2FA / 密碼重設 — 全部 Phase 1
- 註冊功能 — 顯示 Coming Soon 頁面
- 重啟後端 → 裝置 / 模型資料消失 — 後端目前是 InMemoryRepository
- WebSocket 即時推送 — 事件 / 推論結果 / 配對狀態的 WS endpoint 目前回 501,前端改用 3 秒輪詢(pairing 頁)
- Camera / MJPEG 串流 —
/workspace/[deviceId]的 Camera tab 顯示 placeholder,Image / Video / Batch tabs disabled - Cluster CRUD —
/clusters顯示 Phase 1 預告頁 - Account CRUD — 變更個人資料 / 刪除帳號都是 toast stub
- 真實 SHA-256 checksum — 模型上傳用
placeholder:{size}:{nameLen}(詳見model-upload-dialog.tsx§placeholderChecksum)
前端安全債詳見 .autoflow/04-architecture/security.md §14(localStorage token / WS querystring / CSP / CSRF 等 6 項,每項有 Phase 1 計畫)。
效能預算(Phase 1 開始嚴格執行)
| 資源 | 預算 |
|---|---|
| JavaScript(首次載入,壓縮後) | < 200 KB |
| CSS(壓縮後) | < 50 KB |
| 首次載入總大小 | < 500 KB |
| Core Web Vitals | LCP < 2.5s、INP < 200ms、CLS < 0.1 |
雛形(Phase 0)階段僅確保 pnpm build 成功;CI 中加入 bundle 檢查由 DevOps 任務處理。
無障礙規範
目標 WCAG 2.2 AA(詳見 .autoflow/03-design/design-spec.md §8):
- 色彩對比:一般文字 ≥ 4.5:1、大文字 ≥ 3:1
- 鍵盤可操作所有核心流程(Tab / Enter / Escape)
- Focus ring 可見(shadcn 預設
ring-2 ring-ring) - 語意化 HTML(
<nav>、<main>、<aside>、<header>) - 動態內容
aria-live - Pairing token 顯示:
role="text"+ 完整 token 於aria-label(避免 SR 一字一念) - Status card:成功 / 失敗用
role="status"/role="alert"+aria-live
測試
- 策略:Unit ~60% / Integration ~25% / Visual ~10% / E2E ~5%(E2E 交給 Testing Agent)
- 工具:Vitest + React Testing Library + jsdom
- 當前:15 個測試檔、94 個 test 全綠
- 強制一致:
i18n.test.ts驗 zh-Hant / en 兩份字典 key 集合完全一致且無空字串
pnpm test # 一次跑完
pnpm test:watch # watch mode
部署
next.config.ts已設output: "standalone",方便未來 Docker 化- Dockerfile / docker-compose / Helm chart 由 DevOps Agent 規劃(Phase 1)
相關文件
- PRD:
.autoflow/02-prd/PRD.md - 設計規格索引:
.autoflow/03-design/design-spec.md - Design Tokens:
.autoflow/03-design/design-tokens.md - Pairing 流程:
.autoflow/03-design/flows/flow-pairing.md - Auth 流程:
.autoflow/03-design/flows/flow-auth.md - TDD §10 前端章節:
.autoflow/04-architecture/TDD.md - API Spec:
.autoflow/04-architecture/api/api-spec.md - 前端安全債:
.autoflow/04-architecture/security.md§14 - 整體進度:
.autoflow/progress.md