jim800121chen fb7da5d180 chore(autoflow): migrate .autoflow/ 共享層文件至 docs/autoflow/
依 autoflow-agent workspace v2 設計把 PRD / 設計 / 架構 / 交付類
共享文件從個人層 .autoflow/(ignored)搬到 docs/autoflow/(進 git),
讓團隊可共享產品與架構文件,個人層只留 progress / review / testing 等
per-branch 筆記。

- 02-prd/        21 個檔(PRD、features、market-analysis 等)
- 03-design/     18 個檔(design-spec、wireframes、flows 等)
- 04-architecture/ 31 個檔(TDD、design-doc、ADR×14、API 規格等)
- 07-delivery/   3 個檔(project-summary、phase-0.6-handover、stage-deployment-setup)

合計 73 檔。原檔已從 .autoflow/ 移除(migration 工具執行 git mv,
但因 .autoflow/ 在 .gitignore 中、git 將此操作視為新增、無 rename history)。
2026-05-04 16:55:55 +08:00

12 KiB
Raw Blame History

API — Conversion轉檔功能Phase 0.8

base URLhttps://stage-9527.innovedus.com:9527/stage / http://localhost:3721dev AuthOIDC cookie sessionvisiona_session),參見 oidc-tdd.md 同層api/api-spec.md(總覽)、conversion.md(內部設計)、adr/adr-014-conversion-integration.md 角色:給 visionA-frontend 實作時的 API 契約


通用約定

項目
通用回應格式 { "success": true, "data": {...} } / { "success": false, "error": {code, message, details?} }
Auth 走 cookiefrontend 用 credentials: "include"
Request ID header X-Request-IdvisionA-backend 沒收到會自動產生)
Content-Type initmultipart/form-data 外,其他 JSON

1. POST /api/conversion/init

啟動轉檔 job — 把 multipart body streaming proxy 到 converter。

Request

POST /api/conversion/init HTTP/1.1
Cookie: visiona_session=...
Content-Type: multipart/form-data; boundary=----xyz

multipart fields注意:不要帶 user_idbackend 會從 cookie 灌

Field Type 必填 說明
model file .onnx / .tflite,≤ 500MB
ref_images[] file × N 可 0100 張,每張 ≤ 10MB
model_id text 165535使用者自訂編號converter 要求)
version text v1.0.0
platform text 520 / 720
enable_evaluate text true/false,預設 false
enable_sim_fp text 同上
enable_sim_fixed text 同上
enable_sim_hw text 同上

Response 200

{
  "success": true,
  "data": {
    "job_id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "running",
    "stage": "onnx",
    "progress": 0,
    "stage_progress": 0,
    "created_at": "2026-04-30T12:00:00Z",
    "expires_at": "2026-05-07T12:00:00Z"
  }
}

expires_at = created_at + 7dconverter 7 天 GC 截止時間。frontend 用於顯示倒數與切「已過期」狀態。詳見 conversion.md §2.6.2。

錯誤

HTTP code 來源 處理建議
400 validation_failed converter 顯示 details.fields
401 unauthorized visionA redirect /login
409 active_job_exists visionA pre-check / converter 顯示「你已有進行中任務」+ details.job
413 payload_too_large converter 提示檔案大小限制
502 converter_unavailable visionA 提示「轉檔服務暫時無法使用」+ 重試按鈕
503 idp_unavailable / service_busy visionA / converter 提示稍後重試

2. GET /api/conversion/{job_id}

查 job 狀態。Frontend 用 polling建議間隔 2 秒。

Response 200

{
  "success": true,
  "data": {
    "job_id": "550e8400-...",
    "status": "running",
    "stage": "bie",
    "progress": 45,
    "stage_progress": 60,
    "created_at": "2026-04-30T12:00:00Z",
    "updated_at": "2026-04-30T12:05:30Z",
    "expires_at": "2026-05-07T12:00:00Z",
    "source_filename": "yolov5s.onnx",
    "target_chip": "720",
    "error_code": null,
    "error_message": null
  }
}

status enumcreated / running / completed / failed stage enumonnx / bie / nef

欄位 用途
expires_at created_at + 7dfrontend 顯示倒數
source_filename 原始檔名(顯示用,例 wireframe success card 「yolov5s.onnx → yolov5s_kl720.nef」
target_chip 從 init 時的 platform 欄回傳(520 / 720 / 630 / 730

錯誤

HTTP code 處理
403 forbidden job 不屬於當前 user
404 not_found job_id 不存在 / 已過期
502 converter_unavailable 持續失敗 → 提示重試

Polling 建議

  • Frontend 收到 status=running → 2s 後再 poll
  • status=completed / failed → 停止 polling
  • 連續 5 次 5xx → 停止 polling 並顯示錯誤

3. POST /api/conversion/{job_id}/promote-to-models

「加到模型庫」 — 完整流程promote → FAA pull → 寫進 visionA model store。

Request

POST /api/conversion/{job_id}/promote-to-models
Content-Type: application/json

{
  "name": "yolov5s_kl720"
}
Field 必填 說明
name 在 model 庫顯示的名字。Design Phase 0.8 wireframe §7.1 要求此欄位,預設 {job.source_filename_stem}_{target_chip.lower()}
description Phase 0.8 不送,留 Phase 1— backend 接受但忽略Phase 1 開放

與 Design 對齊(議題 #4Phase 0.8 wireframe §7.1 的 import Dialog 只有名稱欄位不含描述backend Phase 0.8 也只用 namedescription 雖在 schema 內但不顯示給使用者填寫。Phase 1 Design 開放描述欄位時 backend 已 ready無需改 API。

Response 201

{
  "success": true,
  "data": {
    "model_id": "abc-123",
    "source": "converted",
    "source_job_id": "550e8400-...",
    "name": "YOLOv5 Face KL520",
    "target_chip": "kl520",
    "file_size": 12345678,
    "status": "ready",
    "created_at": "2026-04-30T12:30:00Z"
  }
}

格式註記:這個 response 是既有 internal/model.Model schema沿用target_chip"kl520" 小寫格式。 跟 §2 / §5 conversion job 的 target_chip"720"converter platform enum不同欄位、不同來源

  • conversion job來自 converter scheduler 的 platform 欄位("520" / "630" / "720" / "730"
  • model.target_chipvisionA 既有 model schema"kl520" / "kl720" / etc

visionA-frontend 統一 normalize 成 UI 內部形式 KL520 / KL720 顯示(見 lib/api/conversion.ts normalizeTargetChip)。 Phase 1 評估是否值得在 backend 把兩邊統一(可能影響既有 model store 多處 caller動範圍大

錯誤

HTTP code 處理
403 forbidden 不是該 user 的 job
404 not_found job_id 不存在
409 job_not_completed job 還沒 completed不能 promote
502 converter_unavailable promote 失敗,可重試
502 faa_unavailable FAA pull 失敗,可重試

冪等性:對同一 job_id 重複呼叫;若已建過 model record回 200 + 既有 model 詳情(不重新建)。


4. GET /api/conversion/{job_id}/download

「下載」 — visionA-backend server-side HTTP 302 redirect 到 FAA delegated URL。Token 永遠不過 frontend JS

仿 FAA TestSite DownloadFileDirectFileAccessAgent.TestSite/Controllers/HomeController.cs:255-282pattern。

Request

GET /api/conversion/{job_id}/download HTTP/1.1
Cookie: visiona_session=...

無 query string、無 body。

Response 302成功

HTTP/1.1 302 Found
Location: http://192.168.0.130:5081/files/jobs/550e8400-.../result.nef?access_token=opaque-token-xxx
Cache-Control: no-store, no-cache, must-revalidate, max-age=0
Pragma: no-cache

browser 自動 follow Location直連 FAA 下載 NEF。

Frontend 使用方式

<!-- 推薦anchor tagbrowser 原生處理 -->
<a href={`/api/conversion/${jobId}/download`} download>下載</a>

或:

// 程式化觸發
window.location.href = `/api/conversion/${jobId}/download`;

Frontend 不需要也看不到 download URL / token / object_key — 全在 server-side + browser navigation 中流轉。

為什麼不需要 FAA CORSbrowser navigation request包含 <a href> click 與 window.location.href)不適用 CORSCORS 只管 JS 發起的 fetch / XHR。Server-side 302 redirect + 同源 endpoint 完全在 CORS 範圍外。

錯誤(不 redirect依 Accept header 回 JSON 或 HTML 錯誤頁)

HTTP code 處理
401 unauthorized 沒登入redirect /login前端攔截
403 forbidden 不是該 user 的 job
404 not_found job_id 不存在 / 已過期
409 job_not_completed job 還沒 completed不能下載
502 converter_unavailable promote 失敗(首次下載且尚未 promote 過時可能發生)
502 mc_token_unavailable / download_token_failed MC 換 delegated token 失敗,提示重試

錯誤回應格式:依 Accept header

  • Accept: application/json{success:false, error:{code, message}}
  • Accept: text/html(一般 anchor 觸發) → HTML 錯誤頁browser 直接顯示

注意

  • 每次「下載」按鈕都直接打 /download endpoint不要前端 cache 任何中間狀態
  • Token TTL 短5 分鐘預設),不過反正 frontend 也碰不到 token
  • 不會與 promote-to-models 衝突;兩者內部都會 ensurePromoted冪等兩條路徑都拿同一個 target_object_key

5. GET /api/conversion/active

查當前 user 是否有 active job — 給 frontend 在跳出「上傳」UI 前 pre-check。

Response 200有 active

{
  "success": true,
  "data": {
    "has_active": true,
    "job": {
      "job_id": "550e8400-...",
      "status": "running",
      "stage": "bie",
      "progress": 45,
      "created_at": "2026-04-30T12:00:00Z",
      "expires_at": "2026-05-07T12:00:00Z",
      "source_filename": "yolov5s.onnx",
      "target_chip": "720"
    }
  }
}

此 endpoint 與 GET /api/conversion/{job_id} 回傳同一個 Job shapewireframe §3.3、flow-conversion.md §5.1 依賴此 shape 做「進入頁面就直接落 processing 畫面」的恢復邏輯。

重啟恢復行為Phase 0.8 強化):當 visionA-backend 重啟導致 in-memory ownership 丟失時,此 endpoint 會 fallback 對 converter 查 GET /api/v1/jobs?user_id=<sub>&status=in_progress 並重建 ownershiplazy rebuild。對 frontend 完全透明(同樣 endpoint、同樣 response shape。詳見 conversion.md §2.6.1。

Response 200無 active

{
  "success": true,
  "data": {
    "has_active": false,
    "job": null
  }
}

用法

Frontend 在「轉檔」入口的 /conversion 頁載入時打這個 endpoint

  • has_active=true → 顯示「你目前有進行中的任務」+ 跳轉到該 job 的進度頁
  • has_active=false → 顯示上傳表單

錯誤碼總覽

對齊 conversion.md §6。前端 i18n key 統一 conversion.error.<short-name>

code HTTP i18n key 預設訊息zh-TW
validation_failed 400 conversion.error.validation 上傳的內容不符合要求
unauthorized 401 common.error.unauthorized 請先登入
forbidden 403 conversion.error.forbidden 你無權存取此任務
not_found 404 conversion.error.not_found 任務不存在
active_job_exists 409 conversion.error.active_job 你目前已有進行中的轉檔任務
job_not_completed 409 conversion.error.not_completed 任務尚未完成(promote-to-modelsdownload 共用)
payload_too_large 413 conversion.error.too_large 檔案超過大小限制
converter_unavailable 502 conversion.error.converter_down 轉檔服務暫時無法使用
faa_unavailable 502 conversion.error.faa_down 檔案存取服務暫時無法使用
download_token_failed 502 conversion.error.token_failed 無法取得下載授權MC 4xx
mc_token_unavailable 502 conversion.error.token_failed 無法取得下載授權MC 5xx / 持續失敗)
idp_unavailable 503 conversion.error.idp_down 認證服務暫時無法使用
service_busy 503 conversion.error.busy 系統繁忙,請稍後再試

版本記錄

日期 版本 變更
2026-04-30 0.1 初稿Phase 0.8 MVP 範圍)
2026-04-30 0.2 §4 download endpoint 從 POST /{job}/download-token(回 JSON {download_url, expires_at})改為 GET /{job}/downloadHTTP 302 redirect仿 FAA TestSite DownloadFileDirect patterntoken 不過 frontend JS、不需 FAA CORSjob_not_completed HTTP code 從 400 改為 409 + 補 mc_token_unavailable
2026-04-30 0.3 Phase 0.8 三方交叉審閱回饋整合Job response shape 補 expires_at / source_filename / target_chip(議題 #7/api/conversion/active 行為文件化 lazy rebuild 機制(議題 #2 重啟恢復);promote-to-models request body 對齊 Design 單欄位(議題 #4description 留 Phase 1