visionA/docs/autoflow/02-prd/interface-contracts.md
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

11 KiB
Raw Blame History

8. 介面契約Interface Contracts — visionA Cloud

父文件:PRD.md

本章節是 Phase 0 的核心產出之一。Phase 0 有很多 TODO介面契約讓未來能「無痛換實作」。


8.1 為什麼介面這麼重要

Phase 0 是雛形階段,很多子系統用 stub 實作,但:

  • 雛形不實作 ≠ 雛形不設計
  • 介面interface / contract現在就要定義清楚
  • 未來只換實作,不動業務邏輯

五大關鍵介面:

  1. AuthProvider — 會員系統Phase 0 stub → Phase 1 JWT
  2. SessionStore — Tunnel session 狀態Phase 0 in-memory → Phase 1 Redis
  3. ObjectStorage — 模型檔儲存Phase 0 local fs → Phase 1 S3/MinIO
  4. ConverterClient — 轉檔服務Phase 0 stub → Phase 2 真實 API
  5. BillingProvider — 計費Phase 0 / 1 都不做 → Phase 2+

實際 Go interface 定義由 Architect Agent 寫進 TDD。本文件定義的是需求與合約


8.2 AuthProvider 介面

目的

讓 visionA-backend 的所有 Auth 相關功能(登入、註冊、驗 token、登出透過一個 interface 抽象Phase 0 接 stubPhase 1 接真實 Auth。

必須提供的能力

能力 說明 Phase 0 Phase 1
Register 建立新 useremail + password stub僅接受固定 demo-user DB
Login 驗證 user發 session token 接受任何帳密,一律回 demo-user + stub token JWT
ValidateToken 驗證 token回傳 user 查 in-memory map 驗簽 + 查 DB
Logout 撤銷 token 刪 in-memory entry 加 blacklist
GetUser 查 user 資訊 in-memory固定 demo-user DB
— 以下為 Phase 1 才做 —
RefreshToken Refresh token rotation Phase 1
RequestPasswordReset 寄 email 重設 Phase 1
ConfirmPasswordReset 確認重設 Phase 1
Delete 刪除帳號 + 所有相關資源 Phase 1

Phase 0 雛形實作:StaticAuthProvider

Phase 0 不做真實會員系統,改用 StaticAuthProvider

  • Login:不驗證 email/password一律接受並回 demo-user 的 stub token
  • ValidateToken:只認得 StaticAuthProvider 自己發的 stub token驗過回 demo-user
  • Logout:從 in-memory map 刪 token
  • GetUser:固定回 demo-useremail: demo@visiona.cloud
  • RegisterPhase 0 可回 ErrNotImplemented 或直接回 demo-userArchitect 決定)
  • Phase 1 方法RefreshToken / RequestPasswordReset / ConfirmPasswordReset / Deletestub直接回 ErrNotImplemented

這個設計讓前端登入流程能跑通任何帳密都能登入但不涉及真實會員資料。Phase 1 換成 JWTAuthProvider(綁 DB + JWT 簽章)時,所有業務邏輯不用動。

錯誤類型

必須定義:ErrUserNotFoundErrInvalidCredentialsErrTokenExpiredErrTokenInvalidErrUserAlreadyExistsErrNotImplementedPhase 0 stub 用)。

使用方式

api-server 啟動時透過 DI 注入 AuthProvider 實作:

// Phase 0
authProvider := stub.NewStaticAuthProvider()

// Phase 1
authProvider := jwt.NewJWTAuthProvider(db, jwtSecret)

router := api.NewRouter(authProvider, ...)

Middleware 設計

router.Use(auth.RequireAuth(authProvider))  // 需登入的路由

詳細介面定義

features/feature-auth.md § 技術細節


8.3 SessionStore 介面

目的

Tunnel session 狀態管理。api-server 和 remote-proxy 都需要查詢「某 user/pairing token 對應哪個 tunnel session」Phase 0 兩個 binary 共用記憶體(同一個 process 或 shared memoryPhase 1 用 Redis 跨節點共享。

必須提供的能力

能力 說明
CreatePairingToken 建立一次性 pairing token綁 user_id15 min TTL
ConsumePairingToken 驗證並消耗 pairing token回傳對應 user_id
CreateSession 建立 tunnel session發 session token
GetSession 從 session token 查 session回 user_id、device_id、created_at 等)
RevokeSession 撤銷 session登出或使用者要求撤銷
ListSessionsByUser 查使用者所有活躍 session
UpdateSessionHeartbeat 更新 session 最後心跳時間
CleanupExpired 清過期 session

Phase 0 實作:MemorySessionStore

  • 單一 process 內用 sync.Map / mutex
  • api-server 和 remote-proxy 必須跑在同一個 process(用 goroutine 起兩個 serverOR
  • 共享 memory store 透過 gRPC / HTTPremote-proxy 呼叫 api-server 的 internal API 查 session

Architect 需決策Phase 0 的 api-server 和 remote-proxy 是一個 process 還是兩個? 兩個 binary 就是兩個 process不能共享記憶體。 方案 A兩個 process + internal gRPC 同步 session方案 B單 binary 啟動時透過參數選擇角色Phase 0 都跑在一起。 建議 Phase 0 用方案 A(符合最終架構),即便兩個 process 都在本機跑,介面也走 HTTP/gRPC。

Phase 1 實作:RedisSessionStore

  • 所有狀態存 Redis
  • api-server 和 remote-proxy 都連同一個 Redis
  • 支援多節點部署

資料模型(邏輯)

PairingToken:
  - token (string, primary)
  - user_id (string)
  - created_at (timestamp)
  - expires_at (timestamp)
  - consumed (bool)
  - consumed_at (timestamp, nullable)

Session:
  - session_token (string, primary)
  - user_id (string)
  - device_id (string)
  - pairing_token_used (string, FK)
  - created_at (timestamp)
  - last_heartbeat_at (timestamp)
  - revoked (bool)
  - revoked_at (timestamp, nullable)
  - proxy_node_id (string, Phase 1 for routing)

8.4 ObjectStorage 介面

目的

統一模型檔(.nef)、未來使用者上傳檔(影片、圖片)、推論結果等二進位資料的儲存。

必須提供的能力

能力 說明
Upload 上傳檔案到指定 key
Download 下載檔案
Delete 刪除檔案
List 列出某 prefix 下的所有 key
Exists 檢查 key 是否存在
GetSize 取得檔案大小
GetDownloadURL 取得下載 URLPhase 0 走自己的 APIPhase 1 用 presigned
GetUploadURL Phase 1presigned upload URL

Key 規範

採統一的 key schema讓未來換 S3 不需要 migrate

models/{user_id}/{model_id}.nef       ← 使用者上傳
models/system/{model_id}.nef          ← 預設模型(所有 user 共享)
uploads/{user_id}/{upload_id}.{ext}   ← 使用者臨時上傳(影片、圖片等)
converter-inputs/{job_id}/{filename}  ← 轉檔的來源檔(臨時)
converter-outputs/{job_id}/model.nef  ← 轉檔結果

Phase 0 實作:LocalFSStorage

  • 存在 ./data/storage/{key}
  • GetDownloadURL 回傳 /api/storage/download?key=...api-server 自己 stream 出去
  • 需做 key 合法性檢查(不能 path traversal

Phase 1 實作:S3Storage / MinIOStorage

  • 標準 AWS S3 SDK 或 minio-go
  • 原生 presigned URL
  • Bucket 策略:
    • visiona-models:公開讀權限 for system/ prefix其他要 presigned
    • visiona-uploads:全私有

檔案大小限制

  • Phase 0100 MB記憶體限制
  • Phase 1500 MBmodel、5 GBvideo upload

8.5 ConverterClient 介面

目的

呼叫 kneron_model_converter 服務做格式轉檔。Phase 0 / 1 用 stubPhase 2 接真實 API。

介面能力

features/feature-converter-integration.md 的完整 API 合約。

核心能力

  • Submit(ConvertRequest) → ConvertJob
  • GetStatus(jobID) → ConvertJob
  • Download(jobID) → io.ReadCloser
  • Cancel(jobID) → error

現況converter API 尚未存在

visionA-backend 先定義介面,對 converter 團隊提出 spec 需求。流程:

  1. Phase 0visionA-backend 定義 ConverterClient interface + StubConverterClient 實作
  2. Phase 0PM Agent 把 API specfeature-converter-integration.md)正式交付給 converter 團隊
  3. Phase 0-1converter 團隊依 spec 實作 API
  4. Phase 2visionA-backend 實作 HTTPConverterClient,換掉 stub

Stub 行為

StubConverterClient

  • Submit 回 fake job_id + status = queued
  • GetStatus 第一次回 queued第二次回 processing第三次之後回 completed給 fake download URL
  • Download 回一個內建的 fake .nef(就是某個預設模型)
  • 讓前端能跑完整流程 UI 開發

8.6 BillingProvider 介面Phase 2

目的

抽象計費與訂閱管理,方便 Phase 2 接 Stripe / Paddle / 其他。

介面能力

能力 說明
CreateCustomer 建立計費客戶
CreateSubscription 建立訂閱
CancelSubscription 取消訂閱
UpdateSubscription 升降級
ReportUsage 上報使用量usage-based pricing
CreateCheckoutSession 建立結帳 sessionhosted checkout
HandleWebhook 處理 provider webhook付款成功、失敗等
GetInvoices 列出 invoice

Phase 0 / 1 都不做

Phase 0 / 1 visionA-backend 不存在任何 billing 相關程式碼。Phase 2 再從頭加。


8.7 給外部團隊的 API 合約清單

Phase 0 期間,需要對外溝通的契約:

對 kneron_model_converter 團隊

交付文件features/feature-converter-integration.md

對方 Action Items

  • 審閱 API spec
  • 評估實作時程
  • 提供 dev 環境與 test API key
  • 決定 webhook 簽章格式
  • 決定 rate limit 數字

對 local-tool 團隊(同 repo

Phase 0 期間 local-tool 完全不動。Phase 1 才考慮整合:

  • local-tool 新增「配對到 visionA Cloud」功能
  • 要共享哪些 Go 套件tunnel client 可能可共用)

對 Innovedus IT / DevOps

Phase 0 後期,若要部署 staging 環境,需要:

  • 一個子域名(例如 cloud.visiona.dev
  • TLS 憑證Let's Encrypt
  • Docker host 或 AWS account
  • DNS 管理權

8.8 API 版本策略

URL 版本

所有 visionA Cloud API 採 URL 版本策略:

/api/v1/...      ← Phase 0 從 v1 開始
/api/v2/...      ← 未來 breaking change 時

相容性

  • 同一 major version 內必須向後相容
  • 遇到必須 breaking 時開新 major version舊版保留至少 6 個月
  • Phase 0 內部使用,允許 v1 小幅變動(不視為 breaking

WebSocket URL

wss://api.visiona.cloud/api/v1/ws/...
wss://relay.visiona.cloud/v1/tunnel/connect

連結