|
|
53e8ab4ae1
|
feat(visionA-frontend): Phase 0.9 模型庫下載 — 前端對接 FAA delegated download
對齊 ADR-017 v1.2 決策 2:model-card 下載按鈕 → 打 visionA endpoint 拿 url+token
→ fetch 跨 origin 直連 FAA + Authorization Bearer → blob 觸發下載(不經 visionA、不經 AWS)。
- src/lib/api/model-download.ts: getModelDownload(打 GET /api/models/:id/download)+
downloadModelFile(fetch + Bearer header + blob,credentials:"omit" 不帶 visionA cookie)+
triggerBlobDownload(延遲 revoke + finally 釋放)+ deriveDownloadFilename + ModelDownloadError
- model-store: downloadingId 互斥(同時只一個下載、finally 必清)+ downloadModel action +
isModelDownloadable(source==converted && status==ready)
- model-card: 下載按鈕(converted+ready 才顯示、上傳類隱藏;preventDefault+stopPropagation
防觸發外層 Link 導航;loading;toast 錯誤)
- i18n zh/en: models.action.download.* / models.download.*(各 error code 對應訊息)
關鍵差異:模型庫下載跨 origin + 需 Bearer header,不能用 <a href> navigation(無法帶 header),
必須 fetch+blob。與既有 conversion download(同 origin navigation)分流。
測試: 43 unit + 互動 test(mock fetch / 按鈕互動 / 顯示條件 / error 分流);tsc/lint/build 全綠。
Reviewer: 0 Critical / 0 Major / 3 Minor / 4 Suggestion,通過(ADR 決策 2 規格 7/7 符合)。
待 stage 實測: FAA 端須設 CORS(允許 visionA origin + preflight Allow-Headers: Authorization),
撞到會落 network_error。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-06-07 04:50:17 +08:00 |
|
|
|
78c1343e9a
|
fix(visionA-frontend): conversion init multipart 對齊 converter 規格 — ref_images + model_id
Phase 0.8b stage e2e 連環 2 個跨層 schema mismatch(5/2 寫 frontend 時對 converter spec 沒驗、5/16 stage e2e 第一次跑通才暴露)。
Bug #5 ref_images field name PHP-style 不對齊
- 現象:converter multer LIMIT_UNEXPECTED_FILE、visionA 透傳 → 400 validation_failed
- 原因:frontend `form.append('ref_images[]', img)`、converter `uploader.fields([{name:'ref_images',...}])`(Express/multer 標準、無 [])
- 修法:frontend `form.append('ref_images', img)`(FormData 多筆同 key、multer 自動收成陣列)
Bug #6 model_id 用 taskName 當值、converter 要 integer
- 現象(修完 Bug #5 後暴露):converter validator → 400 validation_error 「model_id 必須為非負整數」
- 原因:frontend `args.taskName ?? args.file.name` → 字串 "input" / "yolov5s_test";
converter validator (`createJob.js:153-164`) 規定 integer 1-65535(KTC tool 內部 model 編號)
- 修法:新增 `generateConverterModelId()` helper(Math.random 1-65535)、每次 init 自動生成;
taskName 留給 visionA UX(promote 後 model store 的 name),與 converter model_id 解耦
驗證:
- pnpm test src/lib/api/conversion.test 22/22 pass
- pnpm build 通過
- stage redeploy 兩次(commit ce6a657 後跑出 Bug #5、fix Bug #5 deploy 後跑出 Bug #6、fix Bug #6 已 deploy)
剩餘 e2e 待 user browser 真實上傳 ONNX file 驗證。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 11:21:23 +08:00 |
|
|
|
9ebf46112b
|
feat(visionA-frontend): AuthGuard — 未登入自動導 /login + 記住原本 path
需求:
使用者未登入訪 protected route(如 /conversion、/devices)→ 卡在空 UI、無 redirect。
使用者反映「希望未登入直接跳登入頁、登入完跳回原本要去的頁」。
實作:
- 新增 src/components/auth-guard.tsx:
* public routes allowlist:/login, /register
* protected route + user=null + hydrate 完成 → router.replace('/login?next=<path>')
* hydrate 進行中 → render null(避免閃過 protected UI)
* buildNextParam helper:排除 public routes 和純 / 路徑
- 改 src/app/layout.tsx:
* 用 <Suspense fallback={null}> 包 AuthGuard(next/navigation useSearchParams 規範)
* AuthGuard 包 AppShell
- 改 src/app/login/page.tsx:
* buildLoginUrl 接受 returnTo param、組進 backend `/api/auth/login?return_to=<path>`
* sanitizeNext helper:對齊 backend oidc_auth.go:382 sanitizeReturnTo("/" 開頭、無 "//"、無 "://")
* 已登入 redirect:從 query ?next= 跳該 path(不再固定 /)
- 改 src/app/login/login.test.tsx:
* mock 補 useSearchParams(next/navigation mock 既有只 mock useRouter)
- backend oidc_auth.go:88 sanitizeReturnTo 已支援 return_to query param、無需改 backend code
驗證:
- tsc --noEmit 0 errors
- pnpm lint 0 errors
- pnpm build 通過(13 pages prerendered)
- login.test.tsx 12/12 pass
- stage deploy verify:SSR HTML 含 AuthGuard component bundle
不在本 commit 範圍:
- .env.stage CORS fix(VISIONA_CORS_ALLOWED_ORIGINS、stage host .env 直接改、不進 git)
- 5/16 deploy script typo fix(已在 commit fad17dd)
- converter multipart field mismatch(converter scheduler 跨 repo 處理)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 10:38:16 +08:00 |
|
|
|
700b7b08ba
|
chore(stage): 新增 v2 deploy 流程(remote build via DOCKER_HOST)
v1 (deploy-stage.sh) 走 docker save | gzip | docker load 模式,需要把 81MB
tarball 一次性 POST 到 stage docker daemon /images/load API。5/4 / 5/9 兩次
驗證 VPN 下 docker daemon 對單一大 POST hang(卡 30+ 分鐘 / i/o timeout),
公司網段直連才可靠。
v2 仿 edge-ai-platform/scripts/deploy-docker.sh 改用 DOCKER_HOST=stage
docker build — multi-stage build 完全在 stage daemon 上執行:
- 跨網路只傳 build context(~44 MB streaming,VPN 友善)
- alpine base / nodejs / go mod / pnpm install 都由 stage daemon 自己 pull
- layer cache 留在 stage daemon,後續 incremental build 更快
- 5/9 VPN 下實測 work:first build ~3min、redeploy(layer cache) ~10s
連帶修:
- pnpm-workspace.yaml: 加 onlyBuiltDependencies (sharp / unrs-resolver /
@tailwindcss/oxide / esbuild) — pnpm 10 預設拒跑依賴 build script、
乾淨環境第一次 install 撞 ERR_PNPM_IGNORED_BUILDS
- package.json: 加 packageManager: pnpm@10.30.1 — 鎖 pnpm 版本,corepack
在 stage daemon 第一次跑時不會拉到最新 pnpm 11(行為差異)
- Dockerfile.stage: COPY pnpm-workspace.yaml 進 builder context、否則
容器內 install 看不到 trust list
v1 (deploy-stage.sh) 保留作為公司網段直連備援;v2 是 VPN / 預設模式。
|
2026-05-11 10:35:21 +08:00 |
|
|
|
e02059eff2
|
feat(visionA-frontend): Phase 0.8 conversion UI — sidebar tab + 6 view + 5 e2e flow tests
Phase 0.8 對應後端轉檔功能的 frontend UI。完整 state machine(idle / uploading /
queued / running / succeeded / failed / expired)+ XHR upload progress + polling +
half-auto result handling(加到模型庫 / 下載)。
新增 src/app/conversion/(11 元件 + 12 test files,~5,000 行 prod+test,310/310 tests 全綠):
- page.tsx:state router(mount → bootstrap → 依 store.uiState 切換 view)+ toast on
store.error(aborted / active_job_exists 不 toast,避免雙重提示)
- IdleForm.tsx + FileDropzone.tsx + ChipSelector.tsx:上傳表單(拖放 + .onnx/.tflite
format 驗證 + 500MB 大小限制 + KL520/630/720/730 chip 選擇 + ref images ≤100×10MB)
- UploadingView.tsx:XHR upload progress 0-100% + EWMA ETA(alpha=0.3 平滑,<5s 顯示
「即將完成」避抖動)+ beforeunload warning + AlertDialog 取消
- ProcessingView.tsx:StageIndicator 三段式(解析模型 → 量化編譯 → 編譯 NEF)+
Progress bar 三模式(queued / determinate / indeterminate)+ tab title `(轉檔中)` 防疊加 +
409 active_job_exists banner(switchedFromActiveJob flag)
- SuccessView.tsx + PromoteDialog.tsx:兩按鈕(加到模型庫 / 下載)視覺平衡不暗示預設答案 +
7 天 expires_at 倒數(mount 時 setTimeout 鎖過期那刻 + 60s tick)+ PromoteDialog 單欄位
name 驗證(≤100 字元 / 無 /\\)+ spinner-during-close 阻擋 + 409 already_imported 特殊
訊息 + toast.success router.push 跳模型清單
- FailedView.tsx:5 個 known error code 翻譯(UNSUPPORTED_FORMAT / INVALID_CHECKSUM /
QUANTIZATION_FAILED / MODEL_TOO_LARGE / QUOTA_EXCEEDED)+ unknown fallback +
3 個建議解決方法 + Job ID 前 8 字元(供回報)+ 「重新開始」
- ExpiredView.tsx:橘色 hero(過期不 alarming)+ source/chip 摘要 + 「重新轉檔」→
store.reset()
新增 src/stores/conversion-store.ts(Zustand store + 29 tests):
- 7 個 UI state machine(不允許跳階段)
- recursive setTimeout polling(running 5s / queued 10s / 5xx 指數退避 cap 30s)+
visibilitychange 暫停/恢復
- 不持久化 jobId(純靠 backend getActiveConversion() lazy rebuild ownership)
- AbortController 防 stale request + 取消上傳
- switchedFromActiveJob flag(409 自動切到既存 job + UI 顯示 banner)
- formDraft(chip / taskName 提到 store,failed→idle 後保留設定,file picker 重選;
File 物件不能序列化只留 local)
新增 src/lib/api/conversion.ts + types/conversion.ts(5 client 函式 + 22 tests):
- initConversion:XHR multipart + onUploadProgress + AbortSignal
- getActiveConversion / getConversion / promoteConversionToModels:標準 fetch
- getConversionDownloadURL:純函式,回 `/api/conversion/{job_id}/download` 給 anchor
download 觸發(server-side 302 → FAA,token 不過 frontend JS)
- ConversionAPIError(status, code, message, requestId?),code 統一全小寫對齊
conversion.error.<code> i18n key 命名
新增 src/lib/utils/eta.ts(EWMA 演算法純函式 + 19 tests):抽出 smoothSpeed /
estimateRemainingSeconds / instantSpeedBytesPerSec / computeEtaUpdate(test 友善)。
新增 src/app/conversion/e2e-conversion-flow.test.tsx(5 e2e flow tests):
- happy path .onnx + KL720 + 0 ref images(idle → upload → polling → succeeded → 加到模型庫)
- variant 5 ref images
- upload fail → retry(form 設定保留)
- polling 5xx 指數退避 → 恢復繼續
- expired job → ExpiredView → 重新轉檔
修改 sidebar.tsx:左側 nav 新增「轉檔」tab(Wand2 icon,模型庫之後)。
修改 i18n 字典:新增 ~150 個 conversion.* keys(中英雙語對齊)。
PRD §9 14 條功能驗收條件全達成(4 條整合驗收等 stage 部署)。
驗證:pnpm lint / test (310/310) / build 全綠。
對齊文件:
- .autoflow/02-prd/features/feature-converter-integration.md
- .autoflow/03-design/wireframes/wireframe-conversion.md
- .autoflow/03-design/flows/flow-conversion.md
- .autoflow/04-architecture/api/api-conversion.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-04 13:56:54 +08:00 |
|
|
|
99dea42239
|
feat(visionA-frontend): Phase 0 → 0.7 雲端前端(Next.js + OIDC redirect 流程)
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>
|
2026-05-01 11:21:36 +08:00 |
|