jim800121chen cff9236699 docs: migrate Autoflow shared documents to docs/autoflow/
Move PRD, design specs, architecture docs, and TDD from .autoflow/
(personal/per-branch layer) to docs/autoflow/ (shared layer that
goes into git) per the new Autoflow workspace layout.

Files moved:
- 02-prd/PRD.md
- 03-design/design-review.md
- 03-design/user-flow-cross-system.md
- 04-architecture/TDD.md
- 04-architecture/design-doc.md
- 04-architecture/security.md

The originals were never tracked, so git mv reduced to a filesystem
rename with no history to preserve. .autoflow/ remains for personal
notes (progress.md, review reports, testing logs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 10:59:21 +08:00

461 lines
28 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Design Review — API 對外開放 L 級功能
> **審查範圍**2026-04-25 的 L 級新功能「開放 Kneron Model Converter 轉檔能力為對外 REST API 供 VisionA 使用」。
>
> **審查者**Design AgentAutoflow
>
> **審查時機**:三方聯合討論階段(與 PM Agent / Architect Agent 同步作業)
>
> **特別聲明**:這次任務的直接產出物是 **後端 API 介面**,不是新 UI 畫面。本次 Review 的焦點為:
> 1. 對既有 Web UI 使用者體驗的間接影響
> 2. API 設計對下游消費者visionA-backend能做出什麼樣的終端 UX 的限制
> 3. 從 UX 觀點給 PM / Architect 的建議
>
> **不在本次範圍**:新 UI 畫面設計、Wireframe、Prototype、Design Tokens 調整。這些本次都不需要做。
## 變更歷程
| 日期 | 變更內容 |
|------|---------|
| 2026-04-25 | 原始模型上傳路徑改為 visionA-backend → Converter multipart 直連(不經過 File Access Agent。同步更新1錯誤情境表移除「原始模型在 FAA 找不到 `input_object_not_found`」,改為 multipart 相關錯誤 `invalid_multipart` / `file_too_large`2相依圖中 Converter 對 FAA 的依賴只保留 promote PUT移除讀原始模型的箭頭3衝突 response 範例保持不變(不受上傳路徑影響)。|
---
## 1. 摘要
### 1.1 整體評估結論
**Phase 1 對既有 Web UI 使用者體驗的影響:幾乎無感(✅ 優秀)**
- 既有 Web UI 走的 API 路徑(`/jobs``/jobs/:id``/jobs/:id/events``/jobs/:id/download/:filename`**不改動**
- 對外 API 走全新路徑 `/api/v1/*`,兩套並存
- 既有 Web UI 使用者繼續以 multipart 上傳、SSE 追蹤、GET 下載,**流程零改動**
**主要 UX 風險:集中在「我們給 visionA 前端團隊的操作彈性」上(⚠️ 要注意)**
我們不實作 VisionA 的 UI**我們的 API 設計會限制他們能做出什麼樣的體驗**。如果 API 設計得太死板visionA 前端團隊就算想做更好的 UX 也做不到。本次 Review 會針對這點給 Architect 一份「API 設計的 UX 彈性需求」清單。
### 1.2 Phase 1 vs Phase 2 對使用者體驗的差異
| 情境 | Phase 1 體驗 | Phase 2 體驗 | UX 差距 |
|------|------------|------------|---------|
| VisionA 使用者上傳模型並轉檔 | ✅ 在 VisionA 平台內完成 | ✅ 同 Phase 1 | 無差 |
| VisionA 使用者把轉檔結果加進模型庫 | ✅ 按一下按鈕即完成 | ✅ 同 Phase 1 | 無差 |
| VisionA 使用者下載已轉檔的模型 | ⚠️ **阻塞 / 折衷方案** — VisionA 前端目前能做的:(a) 顯示「下載功能即將上線」占位;(b) 從 VisionA backend proxy 下載(違反原架構);(c) 導向舊的 Kneron Converter Web UI 下載(會混亂) | ✅ 瀏覽器直連 File Access Agent速度快、省流量 | **中等** — 這是 UX 上的明顯缺口,必須在 Phase 1 上線時和 VisionA 產品團隊協調 messaging |
**Design Agent 的強烈建議**Phase 1 上線時必須有「使用者下載 messaging 策略」不能讓使用者上傳完轉檔後發現東西下載不了UX 上的死胡同)。**這是需要使用者決策的議題 #1,詳見第 6 節。**
---
## 2. 既有 Web UI 影響分析
### 2.1 既有 Web UI 使用者旅程是否改變?
**結論Phase 1 完全不改Web UI 使用者無感。**
| 旅程階段 | 既有行為(會繼續保留)| 是否受影響 |
|---------|----------------------|----------|
| 進入 Web UI 主頁 | 直接打開網頁,不需登入([推測] 現況)| ❌ 不受影響 |
| 上傳模型multipart| 瀏覽器表單 → `POST /jobs` with FormData | ❌ 不受影響 |
| 追蹤進度SSE| 瀏覽器開 SSE 連線 `GET /jobs/:id/events`,自動 fallback 到每 3 秒 polling | ❌ 不受影響 |
| 下載結果 | 直接點 `GET /jobs/:id/download/:filename` | ❌ 不受影響 |
| 任務列表 | `GET /jobs` 列出全部 job | ❌ 不受影響(但查不到 VisionA 使用者透過新 API 建立的 job — **見 2.3**|
**核心設計選擇(已由 PM 決策)**
- 既有 `/jobs` 路徑保留,**不**加 OAuth 驗證
- 對外 API 走新路徑 `/api/v1/*`**獨立**加 OAuth middleware
- 兩套 API 並存,互不影響
**Design Agent 同意此決策**,理由:
1. 避免破壞現有使用者(零 regression 風險)
2. 讓 Web UI 和對外 API 的演進節奏脫鉤Web UI 是內部工具,對外 API 需要穩定性承諾)
3. 未來若要合併,可在 Phase 3 評估,不用現在壓時程決定
### 2.2 既有 Web UI 的 API 呼叫路徑是否受影響?
**結論:不受影響。**
既有 Web UI 呼叫的所有端點(在 `apps/task-scheduler/server.js` 中驗證過):
```
POST /jobs multipart 上傳)
GET /jobs (列表)
GET /jobs/:jobId (查詢單一 job
GET /jobs/:jobId/events SSE
GET /jobs/:jobId/download/:filename (下載)
GET /health
```
這些端點 Phase 1 **保留原樣**。對外 API 是新增,不是取代。
### 2.3 既有 Web UI 要不要也改走新 OAuth 流程?
**Design Agent 建議Phase 1 不改,維持現況。** 但有一個 UX 面的警示要給使用者知道。
#### 建議不改的理由UX 觀點)
1. **內部工具的 UX 定位**:既有 Web UI 的 persona 是 **Kneron 內部 AI 工程師**,在可信網段內使用,不需要 OAuth 這層摩擦
2. **加上 OAuth 等於要加登入流程**:會多出「登入頁 → 選 tenant → 授權」等步驟,對內部工具體驗是倒退
3. **風險可控**Web UI 目前應該是在內網 / VPN 後面運行,不直接暴露公網(這需要由 Architect 與 DevOps 確認,見下方警示)
#### ⚠️ 警示 — 需要使用者與 Architect 釐清
**如果 Web UI 和對外 API 部署在同一個 Task Scheduler instance 上**(例如同一個 Express app 綁兩套 route那麼
- 對外 API 的 public endpoint`/api/v1/*`)會和 Web UI 用的 `/jobs` **共用同一個 TCP port / Nginx vhost**
- 若未來公開 `/api/v1/*` 到公網,`/jobs` 路徑也會曝光
- 有心人可以直接打 `POST /jobs`(不需 OAuth繞過對外 API 的 rate limit / scope 檢查
**緩解方案(建議交給 Architect 評估)**
- 方案 A**部署層級隔離** — Web UI 的 `/jobs` 只綁 internal network interface`/api/v1/*` 綁 public interface
- 方案 B**Nginx 路由控制** — 同一個 Task Scheduler但 public Nginx 只 proxy `/api/v1/*`internal Nginx 才 proxy `/jobs`
- 方案 C**在 `/jobs` 加基本 IP allowlist**(內網 CIDR
### 2.4 既有 SSE (`/jobs/:id/events`) 機制在新架構下是否保留?
**結論:保留,但只給 Web UI 用。對外 API 走 polling不對外開放 SSE。**
#### Design Agent 的觀察
1. **Web UI 繼續用 SSE**:既有 Web UI 的即時性體驗(看到 stage 切換、進度百分比即時跳動)是 UX 亮點,不能砍
2. **對外 API 不做 SSE**PM 已決策polling 已足夠,理由充分:
- 下游消費者是另一個 backend 服務visionA-backendpolling 對它們而言是標準做法
- 不做 Webhook / SSE 能簡化 Phase 1 的 surface area
- visionA-backend 自己再決定要不要把進度以 SSE / WebSocket 推給 VisionA 前端
3. **但要確保 SSE endpoint 不意外被對外 API 消費者呼叫**(沒意義且資源浪費):
- `/jobs/:id/events` 保留在非 OAuth 路徑下visionA-backend 沒有理由呼叫它
- 若要防禦,可以在 Nginx 層封堵 public access 到 `/jobs/*/events`
#### UX 風險監測
visionA-backend 的 polling 策略會直接影響 VisionA 使用者看到的進度「順暢度」。建議 API 規格中明確給出指引(見第 4 節「給 Architect 的建議」):
- 建議的 polling 間隔2-5 秒)
- 鼓勵 `stage_changed` 時立即 poll讓 VisionA 能快速反應階段切換)
- 回應中的 `etag` / `updated_at` 讓消費者知道何時真的有變
---
## 3. 新呼叫方visionA-backend間接影響分析
### 3.1 間接 UX 影響總覽
雖然我們不設計 VisionA 的 UI但以下 API 設計決策會 **直接限制** visionA 前端能做出的體驗:
| Converter API 設計點 | 對 VisionA 終端使用者 UX 的影響 | Design Agent 建議 |
|--------------------|----------------------------|------------------|
| 同使用者同時一個轉檔限制US-11| 使用者想同時轉兩個不同模型會被擋 | 回 409 時附清晰的 `active_job_id` + 人類可讀的訊息,讓 VisionA 能做「你有一個轉檔進行中,要切過去看嗎?」的 UX |
| Polling 模式(不做 Webhook| 進度更新延遲 = polling 間隔 | API 文件明示建議 polling 間隔回應要快p95 < 200ms避免 VisionA 排隊等待 |
| `POST /api/v1/jobs` multipart/form-data原始模型直接上傳| 大檔上傳期間使用者需要可取消 / 可重試的體感 | API 文件建議 visionA-backend 在上傳到 Converter 時使用支援 progress event HTTP client原生 `net/http` + `io.TeeReader` 或等效並在 visionA 前端以 progress bar 呈現上傳百分比建議 Architect TDD 中明確收檔失敗 / 網路中斷時回 4xx/5xx 足以讓 visionA-backend 判斷是否重試不要只 reset connection|
| 原始模型檔案大小上限 500MB | 超過上限的使用者會被擋在建 job | API 413 `file_too_large` 回應中附 `details.limit_bytes` / `details.actual_bytes` visionA 前端能顯示具體原因VisionA 前端可在上傳前做 client-side 大小檢查提前攔截 |
| promote 需要另一個 API 呼叫 | 使用者要按兩次轉完 + 加進模型庫| **建議 visionA 前端把兩步驟做成一次操作**使用者按一次轉檔並加進模型庫」,VisionA backend 內部自動 chain但這是 VisionA 側的決定 |
| Converter Bucket 7 lifecycle | 使用者轉完沒 promote7 天後檔案消失 | API 回應中要暴露 `expires_at` VisionA 能在 UI 顯示檔案將於 X 天後自動清除」|
| Recovery API list 模式 | 使用者離開後回來 VisionA 前端要決定是否自動跳轉到 job | API 要回足夠多資訊job_idstageprogresscreated_at VisionA 前端做智慧決策 |
| Phase 1 沒有 delegated download | 使用者在 VisionA 模型庫看到模型但不能下載 | **嚴重 UX 缺口,見第 6 節議題 #1** |
### 3.2 錯誤情境的 UX 投射
visionA 前端能把 Converter 回的錯誤轉成什麼樣的訊息完全取決於我們回了什麼以下是 Design Agent 建議 API 要清楚區分的錯誤類型
| 情境 | HTTP 狀態 | 錯誤碼建議 | VisionA 能做出的 UX |
|------|---------|----------|------------------|
| token 無效 / 過期 | 401 | `unauthorized` | 背景 refresh token 重試 |
| token 有效但 scope 不足 | 403 | `insufficient_scope` + `required_scope` | 提示 admin Member Center 補授權 |
| 已有 in-progress job | 409 | `user_has_active_job` + `active_job_id` | 你有一個轉檔進行中要切過去看嗎?」 |
| job 狀態不對promote job 還沒 completed| 409 | `job_not_ready_for_promote` + `current_status` | 轉檔還沒完成請等進度條到 100% 再加進模型庫 |
| multipart body 格式錯 / `model` 檔案欄位缺失 / 必填 field 缺失例如 `user_id``model_id`| 400 | `invalid_multipart` + `details.missing_field` `details.reason` | 上傳失敗請確認檔案格式與欄位」+ 具體指出缺哪個欄位 |
| 原始模型超過 500MB 上限 | 413 | `file_too_large` + `details.limit_bytes` + `details.actual_bytes` | 檔案過大限制 500MB請確認上傳的模型大小」|
| 轉檔失敗模型本身的問題| | `job.error.reason` 要人類可讀 | BIE 量化階段失敗[具體原因]建議檢查參考圖片是否足夠 |
| File Access Agent 不可用promote | 502 | `file_gateway_unavailable` | 模型庫服務暫時不可用我們會自動重試」+ 顯示 retry 按鈕 |
| Member Center JWKS 取用失敗 | 503 | `auth_service_unavailable` | 系統層錯誤顯示 maintenance banner |
> **備註**Phase 1 的原始模型改由 visionA-backend 以 multipart 直接上傳到 ConverterConverter 不再從 File Access Agent 拉原始模型,因此原本的 `input_object_not_found`422錯誤碼在 Phase 1 **不會出現**。取而代之的是上傳階段的 `invalid_multipart`400與 `file_too_large`413。File Access Agent 相關錯誤在 Phase 1 只會發生在 promote 階段。
### 3.3 API 設計上要給 visionA 留下哪些彈性?
為了讓 visionA 前端能做出更好的 UXAPI 要預留以下能力即使 Phase 1 可以先不實作 schema 要設計得可擴展
#### 必要Phase 1
1. **狀態細節**不只 `status`要有 `stage` + `progress`0-100
2. **錯誤碼結構化**`error.code` + `error.message` + `error.details`可擴展
3. **時間戳完整**`created_at``updated_at`各階段的 `stage_started_at` / `stage_completed_at`用於 VisionA 做階段耗時顯示
4. **保留欄位**`metadata: {}`讓未來能加欄位不破壞 API 契約
5. **job_id 可識別**使用者若要截圖 / 反映問題能清楚引用 job_id
#### 建議(未必 Phase 1但設計時要預留
6. **ETA 欄位**`estimated_completion_at`Phase 1 可回 null未來再實作
7. **取消能力**即使 Phase 1 不實作API 路徑 `DELETE /api/v1/jobs/:id` 要預留避免 Phase 2 需要時得改契約
8. **Webhook 註冊**同上即使 Phase 1 不實作資料模型要考量未來可擴展
9. **progress 的顆粒度**每個 stage 內部的 progress例如BIE 階段 45%」而不只是整體 33%」)
---
## 4. 建議與風險
### 4.1 給 Architect 的 API 設計建議UX 觀點)
以下建議從下游消費者能做出什麼樣的 UX角度出發 Architect TDD 中採納或說明取捨
#### 4.1.1 Response Schema 建議
**`GET /api/v1/jobs/:id` 回應範例建議**
```json
{
"job_id": "uuid-v4",
"user_id": "visionA-user-id",
"status": "running", // created / running / completed / failed
"stage": "bie", // onnx / bie / nef / null
"progress": 45, // 0-100整體
"stage_progress": 60, // 0-100當前階段內—— 建議有
"created_at": "2026-04-25T12:00:00Z",
"updated_at": "2026-04-25T12:05:30Z",
"stage_timings": { // 建議有,讓 VisionA 能顯示階段耗時
"onnx": {"started_at": "...", "completed_at": "..."},
"bie": {"started_at": "...", "completed_at": null},
"nef": null
},
"estimated_completion_at": null, // Phase 1 可為 null
"result_object_keys": null, // completed 時才有
"expires_at": "2026-05-02T12:00:00Z", // Converter Bucket 7 天後過期
"error": null, // 失敗時結構化錯誤
"metadata": {}
}
```
**`POST /api/v1/jobs` 衝突回應建議**
```json
{
"error": {
"code": "user_has_active_job",
"message": "使用者目前已有進行中的轉檔任務",
"details": {
"active_job_id": "uuid-v4",
"active_job_status": "running",
"active_job_stage": "bie",
"active_job_progress": 45
}
}
}
```
這讓 visionA 前端能直接顯示你有一個轉檔進行中BIE 階段 45%要切過去看嗎?」而不用再多打一次 API 查詳情
#### 4.1.2 Polling 效能考量
- **p95 < 200ms**已在 PRD §9.2.1visionA-backend 可能每 2-5 polling 一次如果 API visionA UI 會跟著卡
- **建議加 `ETag` / `If-None-Match` 支援**visionA-backend 可以在 304 時跳過資料傳輸省流量
- **避免無必要的 DB 查詢**`GET /api/v1/jobs/:id` 應該只讀 Redis不做任何外部 HTTP 呼叫否則 polling × N 個使用者會變擴增 load
#### 4.1.3 promote API 的 UX 考量
**建議 `POST /api/v1/jobs/:id/promote` 是同步呼叫並回等候 result**
- 好處visionA 前端可以直接顯示 loading 成功 / 失敗
- 風險PUT File Access Agent 若慢大檔API block 幾秒p95 < 3s 已在 SLA
- 備案 PUT 超過某個 timeout例如 10sAPI 202 + 新的 `promote_job_id`visionA polling promote 進度
- Architect 決策Phase 1 建議先做同步版本簡單失敗率觀察後再決定是否需要 async 模式
#### 4.1.4 其他
- **版本化**`/api/v1/` 是對的建議 OpenAPI spec 明確標注breaking change 會走 `/api/v2/`
- **error response 統一格式**所有 4xx/5xx 都用同一個 `{error: {code, message, details}}` 結構避免 visionA 要寫多套 parser
- **job_id 格式固定**建議用 UUID v4不要用 snowflake 之類的自訂 IDvisionA 端的 log 比較好看
### 4.2 給 PM 的需求補強建議
PM PRD 已經相當完整以下是 Design Agent UX 觀點發現可以補強的地方
#### 4.2.1 建議新增:使用者下載 messaging 策略§15.1 或 §12.2
Phase 1 上線時 VisionA 使用者會遇到我的模型在模型庫裡但下不下來的情境建議在 PRD 中增加一段
> **Phase 1 使用者下載缺口的 UX 處理方案(待確認)**
> Phase 1 上線時delegated download 尚未可用。VisionA 需在其 UI 中明確告知使用者「下載功能於 Phase 2 上線」,或採 fallback proxy 方案。此取捨由 VisionA 產品團隊主導Kneron Converter 不需額外做事,但雙方需在 Phase 1 上線 kickoff 前對齊 messaging。
#### 4.2.2 建議新增VisionA 前端 UX 對我們 API 的期望§4.4 或新增 §4.5
目前 PRD §4.4 User Story 是從visionA-backend視角寫的建議補一組 **從 VisionA 終端使用者視角** UX acceptance criteria例如
- 轉檔成功後使用者能在 5 秒內看到模型出現在自己的模型庫
- 同使用者同時轉檔限制觸發時使用者能在 2 秒內看到你有一個轉檔進行中的提示並能一鍵跳過去
- 轉檔失敗時使用者能看到具體原因不只是 generic error)」
這些是 UX 標準不是技術標準寫進 PRD 可以讓 Architect 在設計 API 時有依據
#### 4.2.3 建議補強:`[推測]` 標記的清理策略
PRD 中保留了既有的 `[推測]` 標記 §1.2 新增的 Persona C §4.3~4.4 User Stories 沒有 `[推測]` 標記因為是基於本次討論確認的)。建議使用者審閱時
- 新增章節(§1.2 Persona C、§4.3~4.4、§14、§15請使用者確認後正式定案
- 舊章節的 `[推測]` 標記獨立一個工作項逐條請使用者確認或刪除
這不是本次 L 級範圍但建議 PM 在下一版 PRD 中處理
### 4.3 給 Architect 的一般性 UX 風險提醒
#### 4.3.1 Polling 間隔太短可能讓 VisionA UI 卡頓?
**風險等級:低**
- visionA-backend polling 不是 visionA 前端直接 polling Converter所以 Converter 端壓力可控
- 但若有很多 VisionA 使用者同時轉檔visionA-backend 可能每秒對 Converter 打幾十次 `GET /jobs/:id`
- **建議**Architect TDD 中明確給出 rate limit 策略 visionA-backend client_credentials token rate limit並在 API 文件中建議 polling 間隔
#### 4.3.2 同時一個轉檔的限制可能引起使用者困惑
**風險等級:中**
- 我剛剛明明建立了一個 job為什麼再按一次就 409可能讓使用者以為系統壞了
- **建議**429 409 response body 要帶完整的 active job 資訊 4.1.1 visionA 前端能做出你有 X 在轉中要看嗎?」的友善提示
- **護欄指標**PRD §9.2.2 已經設計了同使用者 409 比率 < 5%」的指標追蹤Design Agent 同意這個目標
#### 4.3.3 Converter Bucket 7 天 lifecycle 和使用者期待不符
**風險等級:中**
- 使用者可能誤以為轉完就在那裡了」,7 天後突然不見會很驚訝
- **建議**
1. API 回應明確標注 `expires_at` 4.1.1
2. visionA 前端在轉檔結果頁顯示請於 X 天內加進模型庫否則檔案將被自動清除
3. `POST /promote` 應該是非常顯眼的 primary action但這是 VisionA UI 決定
#### 4.3.4 使用者中途關掉頁面再回來Recovery是否會遺失 SSE
**風險等級:低(已由 PM 決策接受)**
- PRD 已明確 Phase 1 對外 API polling 模式visionA-backend 重新進入頁面時會呼叫 `GET /api/v1/jobs?user_id=...&status=in_progress`
- Converter 本身的 Redis 狀態在這段時間是持續更新的所以 recovery 不會因為瀏覽器關掉而遺失資料
- **風險** Converter 在使用者離開期間 Crash符合設計哲學使用者回來會看不到任何 job
- PRD 已在 US-12 明示這個限制(「Crash Reset不保證跨 Crash recovery
- Design Agent 接受這個設計取捨但建議 API 回應中區分沒有 in-progress jobvsjob 已不存在可能因為 Crash / 過期)」 visionA 能給使用者不同提示
### 4.4 潛在 UX 風險清單(彙整)
| # | 風險 | 嚴重度 | 建議處理 |
|---|------|--------|---------|
| 1 | Phase 1 使用者下載功能缺口 | **高** | VisionA 產品團隊協調 messaging 策略見議題 #1 |
| 2 | Web UI `/jobs` 路徑在公網意外曝露 | | 部署層或 Nginx 層隔離 2.3 警示 |
| 3 | 7 lifecycle 讓使用者驚訝 | | API 要暴露 `expires_at`visionA UI 要顯示 |
| 4 | 同使用者 409 的使用者困惑 | | 回應要帶完整 active job 資訊 |
| 5 | 錯誤訊息不夠人類可讀 | | 結構化 error code + 可讀 message |
| 6 | Polling 效能對 visionA 的影響 | | API p95 < 200ms + 建議 ETag |
| 7 | Crash job 消失 | 已接受| API 能區分 jobvsjob 不存在 |
| 8 | 轉檔階段耗時資訊不足使用者無法預期 | | 回應中帶 `stage_timings`未來可做 ETA |
---
## 5. 其他觀察
### 5.1 既有 Web UI 的非本次議題(延伸觀察,不在本次範圍)
在審查過程中 Design Agent 觀察到既有 Web UI 有以下 UX **不屬於本次 L 級範圍**僅作記錄供未來討論
1. **前後端 API 契約不一致**已在 PRD §7.3 列出Web UI 的單階段表單呼叫的 `/api/onnx/upload` 等端點後端沒實作UX 影響使用者按了按鈕會失敗
2. **無時間預估**使用者只能看到BIE 階段 45%」,不知道總共還要多久
3. **無批次上傳**一次只能轉一個模型
4. **錯誤訊息品質**`job.error.reason` 欄位存在但文字品質未知
5. **無登入系統**內部工具現況但若未來要加 OAuth 要從頭設計登入 UX
### 5.2 Mermaid 相依圖(從 UX 視角)
```mermaid
flowchart LR
subgraph UsersWorld["使用者世界"]
KneronUser["Kneron 內部 AI 工程師<br/>(既有 Web UI 使用者)"]
VisionAUser["VisionA 終端使用者<br/>(新的 間接受益者)"]
end
subgraph InnovedusEcosystem["Innovedus 生態"]
WebUI["Kneron Converter Web UI<br/>(保留不動)"]
VisionAFrontend["VisionA 前端<br/>(另一個團隊實作)"]
VisionABackend["visionA-backend<br/>Persona C"]
MemberCenter["Member Center"]
FileAccessAgent["File Access Agent"]
end
subgraph Converter["Kneron Model Converter本專案"]
OldAPI["舊 API<br/>POST /jobs<br/>GET /jobs/:id<br/>GET /jobs/:id/events (SSE)<br/>不加 OAuth"]
NewAPI["新 API<br/>POST /api/v1/jobs<br/>GET /api/v1/jobs/:id<br/>POST /api/v1/jobs/:id/promote<br/>OAuth2 Bearer"]
end
KneronUser -->|multipart 上傳 / SSE 看進度| WebUI
WebUI -->|保持既有呼叫| OldAPI
VisionAUser -->|平台內操作| VisionAFrontend
VisionAFrontend -->|VisionA 自家協議| VisionABackend
VisionABackend -->|取 service token| MemberCenter
VisionABackend -->|Bearer token + multipart<br/>(含原始模型 + ref_images| NewAPI
NewAPI -.->|promote PUT 結果檔| FileAccessAgent
NewAPI -.->|驗 token / 取 token| MemberCenter
classDef newPath fill:#e1f5ff,stroke:#0288d1,stroke-width:2px
classDef oldPath fill:#fff9c4,stroke:#fbc02d,stroke-width:2px
class NewAPI,VisionAUser,VisionAFrontend,VisionABackend,MemberCenter,FileAccessAgent newPath
class OldAPI,KneronUser,WebUI oldPath
```
**圖例**黃色 = Phase 1 保留不動的既有路徑藍色 = Phase 1 新增 / 整合的部分
---
## 6. 需要使用者決策的 UX 議題
### 議題 #1最重要Phase 1 使用者下載的 messaging 策略
**背景**Phase 1 上線後VisionA 使用者能完成上傳 轉檔 加進模型庫」, **不能下載** 已搬進模型庫的模型檔這是因為 Phase 2 delegated download 阻塞於 Member Center 未實作 `POST /file-access/download-tokens`
**為什麼這是重要 UX 議題**
- 使用者的心智模型會是我的模型在我的模型庫裡 我當然可以下載它
- 上線時如果下載按鈕不能按或按了沒反應會是明顯的 UX 死胡同
- 使用者可能繞道去舊 Kneron Web UI 下載但那邊資料和 VisionA 模型庫不同步混亂
**可選方案**
| 方案 | 做法 | UX 優劣 | 工程成本 |
|------|------|--------|---------|
| A | 隱藏下載按鈕標示下載功能 Phase 2 上線」| UX 誠實但缺口明顯 | VisionA 前端 |
| B | VisionA backend proxy 下載VisionA backend File Access Agent 拉檔再回給瀏覽器| 暫時堪用但違反原架構大檔過 VisionA backend| VisionA backend |
| C | 使用者點下載 跳轉到舊 Kneron Converter Web UI 下載 | 技術最簡單但資料不同步使用者會混亂 | 導流|
| D | Member Center 實作完才上線 Phase 1 | UX 完整但時程被別人卡住 | 阻塞 |
**Design Agent 傾向方案 A**隱藏 + messaging但這需要 **使用者 + VisionA 產品團隊** 一起決定不是 Converter 單方能決定
**建議 Orchestrator 協調**Phase 1 kickoff 前召一次 VisionA 產品團隊 + Kneron Converter PM + Member Center owner 的跨團隊會議明確 messaging 策略與時程
### 議題 #2次要既有 Web UI 的公開曝光風險
**背景**見第 2.3 若未來 `/api/v1/*` 對外公開而 `/jobs` 沒做任何隔離可能被繞過
**需要使用者確認**
1. 本專案部署目標是什麼純內網 / VPN 後面 / 公網
2. Web UI 是否會和對外 API 在同一個 public entry 後面
這個議題交由 Architect Agent TDD 中提出具體部署策略使用者確認即可Design Agent 只提出警示
### 議題 #3低優先既有 PRD 的 `[推測]` 標記清理
4.2.3建議在本次 L 級之後單獨開一個工作項處理不阻塞 Phase 1
---
## 7. 結論
### 7.1 對三方聯合討論的 Design 立場
- **✅ 同意** PM Phase 1 / Phase 2 切分(§15
- **✅ 同意** user_id multipart form field 帶入方式 A而非放 token claim
- **✅ 同意** 原始模型採 multipart 直連上傳visionA-backend Converter不經過 File Access Agent2026-04-25 更新
- **✅ 同意** polling 模式不做 Webhook
- **✅ 同意** Web UI 不改Phase 1 保留既有路徑和 UX
- **✅ 同意** 搬檔做法 2Converter 自己 PUT File Access Agent僅限 promote 階段
- **⚠ 要求補強**Phase 1 使用者下載 messaging 策略議題 #1
- **⚠ 要求補強**API response schema 要符合第 4.1 節的 UX 期望錯誤結構化stage_timingsexpires_at
- **⚠ 新增 UX 關切**multipart 上傳的 progress bar 呈現與 `invalid_multipart` / `file_too_large` 錯誤碼細節結構化 3.13.2
### 7.2 Design Agent 對其他兩方文件的審閱(待三方產出後執行)
- 審閱 PRD 時的重點Persona C 是否清楚描述服務對服務的互動終端使用者的 UX 期望是否納入 acceptance criteria
- 審閱 TDD 時的重點API response schema 是否提供足夠彈性讓 visionA 做好 UX錯誤碼是否結構化polling 效能是否達 SLA
### 7.3 本次 Design Review 的直接產出
1. 本份 `design-review.md`
2. `user-flow-cross-system.md`跨系統使用者流程圖
3. **不產出** WireframePrototypeDesign Tokens本次無新 UI 需求