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

331 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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.

# 8. 介面契約Interface Contracts — visionA Cloud
> 父文件:[PRD.md](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-user`email: `demo@visiona.cloud`
- **Register**Phase 0 可回 `ErrNotImplemented` 或直接回 demo-userArchitect 決定)
- **Phase 1 方法**RefreshToken / RequestPasswordReset / ConfirmPasswordReset / Deletestub直接回 `ErrNotImplemented`
這個設計讓前端登入流程能跑通任何帳密都能登入但不涉及真實會員資料。Phase 1 換成 `JWTAuthProvider`(綁 DB + JWT 簽章)時,所有業務邏輯不用動。
### 錯誤類型
必須定義:`ErrUserNotFound``ErrInvalidCredentials``ErrTokenExpired``ErrTokenInvalid``ErrUserAlreadyExists``ErrNotImplemented`Phase 0 stub 用)。
### 使用方式
api-server 啟動時透過 DI 注入 `AuthProvider` 實作:
```go
// Phase 0
authProvider := stub.NewStaticAuthProvider()
// Phase 1
authProvider := jwt.NewJWTAuthProvider(db, jwtSecret)
router := api.NewRouter(authProvider, ...)
```
**Middleware 設計**
```go
router.Use(auth.RequireAuth(authProvider)) // 需登入的路由
```
### 詳細介面定義
見 [features/feature-auth.md § 技術細節](features/feature-auth.md#技術細節給-architect-參考)。
---
## 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 / HTTP**remote-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](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 spec`feature-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](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
```
---
## 連結
- 上一章:[非功能性需求](nonfunctional.md)
- 下一章:[成功指標](success-metrics.md)
- 跳回:[PRD 索引](PRD.md)