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

513 lines
25 KiB
Markdown
Raw 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.

# Design Doc — visionA Cloud
## Metadata
- **作者**Architect Agent
- **狀態**Draft待三方交叉審閱
- **最後更新**2026-04-21
- **範圍**visionA-frontend + visionA-backend 的雲端版架構定位為「POC 升格為產品」的雛形骨架
- **相關文件**
- 健檢:`.autoflow/00-onboarding/health-check.md`
- PRD`.autoflow/02-prd/PRD.md`PM 主導,平行產出中)
- 設計規格:`.autoflow/03-design/`Design 主導,平行產出中)
- TDD`.autoflow/04-architecture/TDD.md`(本文檔的姊妹檔,實作細節)
- ADRs`.autoflow/04-architecture/adr/adr-*.md`
---
## 1. 系統總覽High-Level Overview
visionA Cloud 把「使用者的 Kneron 裝置」透過雲端反向代理提供給瀏覽器操作。核心流向:
```
┌────────────────────────────────────────────────────────────────────────┐
│ 使用者瀏覽器 │
│ visionA-frontend (Next.js) │
└─────────────────┬────────────────────────────┬────────────────────────┘
│ HTTPS REST │ WSS (訂閱)
│ │
┌─────────────────▼────────────────┐ ┌─────────▼──────────────────────┐
│ visionA-backend / api-server │ │ visionA-backend / api-server │
│ (無狀態, 水平擴展) │ │ (WebSocket 訂閱, 同 binary) │
└─────────────────┬────────────────┘ └─────────┬──────────────────────┘
│ Session 查詢in-mem 同進程 / Redis 跨進程) │
▼ ▼
┌────────────────────────────────────────────────────────────────────────┐
│ 共享 Session Storerouting table
│ 雛形in-memory單進程 Phase 1Redis │
└─────────────────────────────┬──────────────────────────────────────────┘
│ 查到該 token 的 tunnel 在哪個 proxy 節點
┌────────────────────────────────────────────────────────────────────────┐
│ visionA-backend / remote-proxy (有狀態) │
│ 持有 yamux.Session map[token]→Session │
└────────────────────────────┬───────────────────────────────────────────┘
│ WebSocket + yamux長連線
┌────────────────────────────────────────────────────────────────────────┐
│ 使用者電腦 local agent │
│ (local-tool 或 tunnel-only client連 remote-proxy 出站) │
│ 本機 HTTP server :3721 │
└────────────────────────────┬───────────────────────────────────────────┘
│ USB
┌──────────────────┐
│ Kneron 裝置 │
│ KL520 / KL720 │
└──────────────────┘
外部依賴(均透過介面,雛形 stub
├─ kneron_model_converter (`/api/converter/*` stub, TODO)
├─ S3-compatible 物件儲存 (LocalFSStore for prototype)
└─ PostgreSQL + Auth provider (in-memory for prototype, ADR-005)
```
**關鍵概念**
- **Session key = pairing token**,一個 token 對應一個 yamux tunnel。
- **API Server 把收到的請求**,查 session store 找到對應 token 的 tunnel**轉發**到該 tunnel 上的 remote-proxy 節點,**由 proxy 打 yamux stream** 送進 local agent拿到 response 再回傳瀏覽器。
- **WebSocket 訂閱**同理api-server 升級 WS 後,在 session store 裡找到 tunnel把 WS 幀透過 yamux stream 送給 local agent 的 `/ws/*`
---
## 1.9 Non-Goals雛形明確不做的事2026-04-22 M-8
以下項目在 **Phase 0 雛形階段刻意不支援**,列出以避免誤解:
| # | Non-Goal | 原因 | 對應 Phase |
|---|----------|------|-----------|
| N1 | **多 instance 部署** — 雛形僅支援單一 `api-server` instance + 單一 `remote-proxy` instance | 無共享 state 機制(無 Redis、無 DB session metadata開兩個 `api-server` 會因為 session lookup 散到不同節點而壞掉;開兩個 `remote-proxy` 會讓 tunnel 註冊到 A 節點、但 api-server 的 `ProxyClientStore` 配置只連 B查無 session | Phase 1 |
| N2 | **真實使用者註冊 / 登入**`StaticAuthProvider` 無論帳密都回 demo-user | Auth 不是 POC → 產品驗證的核心風險;整合 Clerk / 自建 OIDC 需 2-4 週,放 Phase 1 | Phase 1 |
| N3 | **真實 DB 持久化** — 所有 repository 走 in-memory map | ADR-005 明定Phase 1 實作 `Postgres*Repository` | Phase 1 |
| N4 | **真實 Converter 整合**`/api/converter/*` 走 Stub | Converter 團隊 API 規格未定;見 `api/api-converter-contract.md` | Phase 1 |
| N5 | **Pairing Token 兩階段升級** — 雛形 Pairing 與 Session 合併為單一 token | 單 token 比對流程足以驗證 tunnel兩階段 DB transaction 需 Postgres | Phase 1必須在公開 release 前完成)|
| N6 | **HTTPS / WSS** — 雛形走明文 HTTP / WS | TLS termination 由 Phase 1 LB / reverse proxy 處理 | Phase 1 |
| N7 | **Rate limiting / Audit log** — 雛形無 | 雛形只跑 dev / 內測 | Phase 1 |
| N8 | **Observabilitymetrics / trace / alert** — 雛形只有 stdout log | 雛形不追求 SLO | Phase 1 |
| N9 | **Local agent 自己的 binaryvisionA/local-agent/** — 雛形用 POC `edge-ai-server` 當 tunnel client 暫代 | 讓雛形專注在 backend 協定正確性Phase 1 從 local-tool 複製起步 | Phase 1 |
| N10 | **`cmd/dev-all-in-one` 單進程合併模式** | 會讓部署拓撲與 Production 不一致,反而掩蓋 bug | 永不做 |
**重要後果**
- 開第二個 `api-server`(例如為了測試無狀態性)會因 `ProxyClientStore` 只配一個 `VISIONA_PROXY_INTERNAL_URL`,導致兩個 api-server 都指向同一個 remote-proxy這**可以**運作(真實多 instance 場景)。但開兩個 `remote-proxy` 會壞 — tunnel 連上的是 A但 api-server 可能查到 B視 LB 分配B 沒有 session 就回 404。
- 雛形的部署指引明確:**恰好 1 個 api-server + 恰好 1 個 remote-proxy**。
- Phase 1 解多 `remote-proxy` 節點時會補 session metadata 共享機制(見 `tunnel.md` §5.4 + 待產出的新 ADR
---
## 2. 系統邊界與組件
### 2.1 visionA-frontend客戶端
| 屬性 | 值 |
|------|-----|
| 技術 | Next.js 16 App Router + React 19 + TypeScript + Tailwind 4 + Radix + Zustand 5 + Lucide + Recharts + driver.js |
| 部署 | 靜態打包 + CDN雛形用 Next.js 本地 dev serverPhase 1 上 Vercel / Cloudflare Pages / S3+CloudFront|
| 狀態 | 無(純前端,所有資料 via API|
| Auth | JWT / session cookie雛形 stubPhase 1 真實) |
| 連線對象 | **只連 `visionA-backend/api-server`****不直連** remote-proxy 或 local agent |
**從 local-tool 搬來的內容**所有頁面、components、stores、i18n、UI styling改 API base URL移除 localhost hardcode。
**新增**
- `/login``/register`雛形骨架Auth stub
- `/account`(雛形骨架)
- `/devices/pair`(輸入 / 產生 pairing token
- `/clusters`(從 POC 搬)
### 2.2 visionA-backend / api-servercmd/api-server
| 屬性 | 值 |
|------|-----|
| Binary | `cmd/api-server/main.go` |
| 狀態 | **無狀態**(所有狀態在 DB / session store / 物件儲存)|
| 水平擴展 | ✅ 多實例 + 前置 L7 load balancer |
| 對外 | HTTP :3001雛形預設正式上 443 |
| 職責 | REST API、WebSocket 升級、Auth、權限、把請求 proxy 到 remote-proxy、Storage presigned URL、Converter 呼叫 |
### 2.3 visionA-backend / remote-proxycmd/remote-proxy
| 屬性 | 值 |
|------|-----|
| Binary | `cmd/remote-proxy/main.go` |
| 狀態 | **有狀態**(持有 yamux.Session|
| 水平擴展 | 可多實例session 路由交給 session store |
| 對外local agent | WS :3800POC 預設)|
| 對內api-server | HTTP :3801內部 API不對外|
| 職責 | 接受 local agent 的 tunnel 連線、維護 yamux session、轉發 api-server 送來的請求 |
### 2.4 共享狀態Session Store2026-04-22 Q1 裁決 C + ADR-006雛形即雙 binary無 Redis
| 雛形實作 | Phase 1 實作 |
|---------|-------------|
| Session state **完全由 remote-proxy 持有**in-memoryapi-server 無狀態,透過 internal HTTP 向 remote-proxy 查詢 | 多 remote-proxy 節點間的 metadata 共享機制**待 Phase 1 評估**Redis / gossip / sticky LB 等 — 不預設採用 Redis |
**雛形設計**
- `cmd/remote-proxy`**唯一**持有 `*yamux.Session` 的 process`InMemoryStore` 儲存
- `cmd/api-server`:無狀態;`internal/session` 載入 `ProxyClientStore`internal HTTP client
- 兩 binary 透過 `internal/forward/*``internal/session/*` endpoints 溝通(詳見 `api/api-internal.md`
**Non-Goal刻意不做**
- **不做 `cmd/dev-all-in-one` 單進程合併模式** — 會讓部署拓撲與 Production 不一致,反而讓 bug 在雛形階段無法暴露
- **不引入 Redis** — POC 從未用過(見 ADR-006
詳細見 TDD §2 與 `tunnel.md` §5。
### 2.5 local agent使用者電腦
三種形態:
1. **local-tool**(桌面版 Wails 應用):原本離線用,加一個 config 選項「啟用雲端模式」後,額外啟動 tunnel client 連 remote-proxy。**local-tool 本身不動**;雲端模式是新增 opt-in 模組,不影響離線使用。
2. **tunnel-only client**未來專為「headless / server 使用者」提供的輕量 Go binary只跑 tunnel client + 最小 HTTP server不含 Wails / UI。雛形不做。
3. **既有 edge-ai-platform**POC 的 tunnel client 可直接繼續用來做技術驗證。
### 2.6 外部依賴
| 依賴 | 雛形 | Phase 1 |
|------|------|--------|
| `kneron_model_converter` | Stub`/api/converter/*` 回假資料 | 真實打 converter API |
| 物件儲存 | `LocalFSStore`(本地檔案)| `S3Store`AWS S3 / Cloudflare R2 / MinIO|
| 資料庫 | in-memory repositories | PostgreSQL |
| Auth | `StaticAuthService`(永遠 demo-user| 真實 Auth |
| Observability | stdout log | Prometheus + Loki + OpenTelemetry |
---
## 3. 12-Factor 合規策略
| # | Factor | 雛形做法 | Phase 1 做法 |
|---|--------|---------|-------------|
| 1 | Codebase | ✅ Monorepo (`visionA/visionA-frontend` + `visionA/visionA-backend`) | 同 |
| 2 | Dependencies | ✅ `go.mod` + `package.json` 明確宣告;無系統隱式依賴 | 同 |
| 3 | Config | ✅ 全走 env vars`VISIONA_*` prefix`internal/config` 讀取 | 同 + 密鑰用 Secrets Manager |
| 4 | Backing services | ✅ Storage / DB / Auth 全走 interface | 同(實作 swap|
| 5 | Build / Release / Run | ⚠️ 雛形只有 `make build` + `docker-compose` | BuildCI 產出 imageReleasetag + manifestRunK8s / ECS deploy |
| 6 | Processes | ✅ api-server 無狀態state 全走 Store interface | 同 |
| 7 | Port binding | ✅ api-server `:3001`remote-proxy 對 agent `:3800`,對 api `:3801` | 同port 由 env 指定)|
| 8 | Concurrency | ✅ 單進程多 goroutine跨進程靠 SessionStore | 多實例 + auto-scale |
| 9 | Disposability | ⚠️ 雛形 SIGTERM graceful shutdowntunnel 斷線有重連 | 同 + drain period |
| 10 | Dev/Prod Parity | ✅ Docker 一致化 | 同 |
| 11 | Logs | ⚠️ 雛形 stdout已有 broadcaster WebSocket 看 log| 結構化 JSON log + 集中收集 |
| 12 | Admin processes | ⚠️ 雛形手動 | 後台 CLI / admin API |
**雛形妥協**log 未結構化、缺 metrics、缺 trace。記錄為 TODO不影響功能驗證。
---
## 4. 水平擴展策略
### 4.1 api-server無狀態
- 多實例,前置 L7 load balancerALB / nginx / Cloud Run 自動)
- Sticky session **不需要**(無狀態)
- 擴展訊號CPU > 60% 或 p95 延遲 > 300ms
### 4.2 remote-proxy有狀態
remote-proxy 的狀態是 `map[token]*yamux.Session`。擴展的挑戰:
- Local agent 連 proxy 時,會連到某一個**具體節點**(由 LB 分派ALB + IP hash 或 DNS round-robin
- 後續 api-server 要送請求到該 token 的 tunnel 時,需要**知道這條 tunnel 在哪個 proxy 節點**
**解決方案Session Store 記錄 routing table**
```
Session Store 儲存Redis Hash:
session:{token} = {
proxy_node_id: "proxy-2",
proxy_internal_url: "http://proxy-2.internal:3801",
connected_at: "...",
last_seen: "..."
}
```
api-server 送請求的流程:
```
1. 收到 API 請求GET /api/devices + X-Pairing-Token: xxx
2. 查 Session Storetoken → proxy_internal_url
3. 呼叫該 proxy 的 internal endpointPOST http://proxy-2.internal:3801/forward
- body = 原請求method, path, headers, body
4. proxy-2 收到後,從自己 in-memory map 取 yamux.Session
5. 開 stream傳 HTTP request
6. 等 response → 回給 api-server → 回給瀏覽器
```
### 4.3 雛形簡化(單節點)
雛形期 api-server 與 remote-proxy **同進程**SessionStore 就是本機 map**跳過跨節點轉發**
```
1. 查 SessionStorelocal map取 yamux.Session
2. 直接開 stream 送請求
```
Phase 1 時把 SessionStore 換 Redis、引入「proxy internal HTTP API」不改 API handler 程式碼。
### 4.4 擴展邊界
| 資源 | 估算 |
|------|------|
| remote-proxy 單節點 tunnel 數上限 | ~10K受檔案描述符 / 記憶體限制,每個 tunnel ~100KB|
| api-server 單節點 QPS | ~5KGin + Go 典型值)|
| Session StoreRedis單節點 QPS | ~100K |
雛形單節點即可撐 demo / 早期內測。Phase 1 再引入多節點。
---
## 5. 資料流
### 5.1 前端呼叫 REST API最常見情境
```
[瀏覽器] GET /api/devices
↓ HTTPS + Cookie/JWT
[api-server] authMiddleware 驗 user
↓ 從 user 找對應 pairing token雛形 env 寫死Phase 1 查 DB
[api-server] 查 SessionStore(token) 取 proxy location
(單節點雛形:直接拿到 yamux.Session
(多節點:轉發 http://proxy-X.internal:3801/forward
[remote-proxy] 從 session open yamux stream
↓ 把 HTTP request 寫進 stream沿用 POC 方法)
[local agent] tunnel client accept stream
↓ 轉發到本機 127.0.0.1:3721
[local HTTP server] 處理 /api/devices → 回 response
↓ 經 yamux stream 回到 remote-proxy
↓ remote-proxy 回 api-server
↓ api-server 回瀏覽器
[瀏覽器] 得到裝置列表
```
### 5.2 前端開 WebSocket 訂閱(例:裝置事件串流)
```
[瀏覽器] WS /ws/devices/events (connect)
[api-server] authMiddleware → 升級 WS
↓ 查 SessionStore → 取 yamux session
↓ 開 stream把 HTTP upgrade request 寫進 stream沿用 POC proxyWebSocket 邏輯)
[local agent] handleStream 偵測 upgrade → 連本機 raw TCP → 雙向 copy
[local HTTP server] /ws/devices/events 升級 → 開始推事件
↓ 事件 frame → yamux stream → api-server → 瀏覽器
```
POC 已完整實作此流程visionA 直接沿用。
### 5.3 模型上傳(**不走 tunnel**
```
[瀏覽器] 點「上傳模型」
[api-server] POST /api/models/upload-url
↓ 呼叫 Storage.PresignedPutURL → 回給瀏覽器
[瀏覽器] 直接 PUT 檔案到 S3 / LocalFS不走 tunnel省 tunnel 頻寬)
↓ 上傳完成後
[瀏覽器] POST /api/models/register (告知 api-server 上傳完成 + metadata
[api-server] 寫入 model repository
```
**為何不走 tunnel**
- 模型檔可達百 MB走 tunnel = 占用使用者本地頻寬兩次(上傳 → 雲端 → 下載)
- S3 presigned URL 讓瀏覽器直連scalable
- 需要時 api-server 再叫 local agent「下載這個 model 的 URL」由 local agent 用自己網路下載
### 5.4 轉檔呼叫Phase 1
```
[瀏覽器] POST /api/converter/convert {source_url, target_chip: "kl520"}
[api-server] 驗 user → 呼叫 kneron_model_converter API
↓ (非同步)取得 job_id
[api-server] 回 job_id
↓ 輪詢 /api/converter/jobs/{id} 或 WS 訂閱進度
```
雛形 api-server 提供端點,但回 stubjob_id 假的,狀態永遠 `queued`)。
---
## 6. 安全架構
### 6.1 通訊加密
- **瀏覽器 ↔ api-server**HTTPSPhase 1雛形開發用 HTTP
- **api-server ↔ remote-proxy 內部**:雛形同進程無需加密;多節點 Phase 1 考慮 mTLS 或 VPC-only
- **local agent ↔ remote-proxy**WSSPhase 1雛形 WS。TLS 由前端反代ALB / nginx終止
### 6.2 認證 / 授權
| 物件 | 雛形 | Phase 1 |
|------|------|--------|
| 使用者登入 | `StaticAuthService` 永遠過 | OIDC / SAML / 自建 |
| 前端 call API | 無 token 也接受stub| JWT / session cookie |
| local agent 連 proxy | `VISIONA_PAIRING_TOKEN` env 寫死 | DB-backed Pairing Token見 ADR-003|
| API handler 授權 | 一律通過 | RBAC`user 只能看自己的 device` |
### 6.3 CORS / CSRF
- **CORS**api-server 雛形設 `Access-Control-Allow-Origin: *`devPhase 1 白名單
- **CSRF**:用 JWT in header非 cookie可天然免疫若用 session cookie 則需 CSRF token
- **WebSocket Origin**:本 repo 的 `local-tool/server/internal/api/ws/origin.go` 已有成熟 allowlist搬過來用
### 6.4 Pairing Token 安全
詳見 ADR-003。重點
- 雛形env 寫死
- Phase 1DB 存 `sha256(token)`不存明文15min expiry可 revoke綁 user_id + device_id
### 6.5 輸入驗證
- 模型檔案格式驗證(雛形僅 extensionPhase 1 加 magic bytes + file size limit
- API body schema 驗證(用 struct tags `binding:"required"``go-playground/validator`
### 6.6 STRIDE 分析(重點項目)
| 威脅 | 防護 | 雛形 / Phase 1 |
|------|------|--------------|
| 偽冒Spoofing他人冒用 token | `sha256(token)` 存 DB + rate limit雛形 env 隔離 | Phase 1 必做 |
| 竄改Tampering中間人改 request | TLS | Phase 1 |
| 否認Repudiation | Audit log | Phase 1 |
| 資訊洩露Information Disclosure | TLS + least privilege log | Phase 1 |
| DoS | rate limit on `/tunnel/connect` + API | Phase 1 |
| 提權EoP | RBAC | Phase 1 |
**雛形期驗證技術,不預期公開部署**,以上多數 Phase 1 才補全。
---
## 7. 部署架構
### 7.1 雛形(開發 / 內測)
**方案 A本機一鍵啟動**
```
docker-compose up
```
`docker-compose.yml`
```
services:
api-server:
build: { context: ., dockerfile: docker/Dockerfile.api-server }
ports: ["3001:3001"]
environment:
VISIONA_SESSION_BACKEND: inmemory
VISIONA_STORAGE_BACKEND: localfs
VISIONA_AUTH_MODE: static
VISIONA_PAIRING_TOKEN: dev-token-abc123
volumes: ["./data:/data"]
remote-proxy:
build: { context: ., dockerfile: docker/Dockerfile.remote-proxy }
ports: ["3800:3800", "3801:3801"]
environment:
VISIONA_SESSION_BACKEND: inmemory
VISIONA_PAIRING_TOKEN: vAc_<32 hex> # 格式見 security.md §1.3
frontend:
build: { context: visionA-frontend }
ports: ["3000:3000"]
environment:
NEXT_PUBLIC_API_BASE: http://localhost:3001
```
**雛形交付物Phase 0**:上述雙 binary + docker-compose 即完整雛形。**不提供** `cmd/dev-all-in-one`(見 §2.4 Non-Goal
### 7.2 Phase 1正式部署草圖
```
┌──────────┐
│ CDN │ (Cloudflare / CloudFront)
└────┬─────┘
│ static frontend
┌───────────────┴────────────────┐
│ │
┌────▼─────┐ ┌──────▼────┐
│ ALB │ │ NLB │ (for WebSocket, TCP pass-through)
└────┬─────┘ └──────┬────┘
│ HTTPS /api/*, /ws/* │ WSS /tunnel/connect
│ │
┌────▼───────────────┐ ┌────▼──────────────────┐
│ api-server cluster │◄──────────►│ remote-proxy cluster │
│ (K8s / ECS) │ Redis │ (K8s / ECS, StatefulSet│
│ stateless, N pods │ Session │ or DaemonSet) │
└────┬───────────────┘ Store └────┬──────────────────┘
│ │
├─► PostgreSQL (RDS) │
├─► S3 / R2 (object store) │
└─► Converter API │
│ WSS + yamux
使用者電腦 local agent
```
**Cloud-agnostic**所有組件Redis、PG、S3都有對應的 interface可用 AWS / GCP / 自建。
### 7.3 CI/CD雛形目標
- `make build` → 兩個 binary
- `make docker-build` → 兩個 image
- `make docker-compose-up` → 本機跑起來
- GitHub Actions / GitLab CIPhase 1→ 自動 build + push registry + deploy
---
## 8. 觀測Observability
### 8.1 雛形
| 項目 | 做法 |
|------|------|
| Log | stdout沿用 local-tool 的 log broadcasterWS 看 log|
| Metrics | 無;`/api/system/health` 回 ok 即可 |
| Trace | 無 |
| Alert | 無 |
### 8.2 Phase 1TODO
| 項目 | 做法 |
|------|------|
| Log | 結構化 JSON → Loki / CloudWatch Logs |
| Metrics | Prometheus export`qps`, `p95_latency`, `tunnel_count`, `session_active_count` |
| Trace | OpenTelemetry SDK → Tempo / X-Ray |
| SLO | API 可用性 99.9%p95 < 500msTunnel 連線穩定度 99%7 天滾動|
| Alert | Grafana / PagerDuty |
---
## 9. ADR 索引
| 編號 | 標題 | 狀態 |
|------|------|------|
| [ADR-001](adr/adr-001-two-binaries.md) | 單一 Go 專案 / binary 結構 | Accepted |
| [ADR-002](adr/adr-002-tunnel-protocol.md) | 沿用 POC Tunnel 協定WebSocket + yamux| Accepted |
| [ADR-003](adr/adr-003-pairing-token.md) | Pairing Token 取代 SHA256(MAC) Token | Accepted |
| [ADR-004](adr/adr-004-storage-interface.md) | 模型儲存採用 S3-Compatible 介面 | Accepted |
| [ADR-005](adr/adr-005-no-db-auth-in-prototype.md) | 雛形階段不接真實 DB Auth | Accepted |
---
## 10. 三方交叉審閱檢核清單
### 給 PM 審閱
- [ ] 所有 PRD 中列出的 P0 功能是否在本 Design Doc 都有對應的技術路徑
- [ ] 雲端能操作使用者本地裝置的核心價值主張是否由架構支撐
- [ ] 雛形 vs Phase 1 的差異PM 能否向使用者解釋現在能做什麼未來會做什麼」?
### 給 Design 審閱
- [ ] pairing token 輸入頁面是否技術可行API 已定義
- [ ] 模型上傳流程的 presigned URL UX 是否清楚
- [ ] tunnel 斷線時瀏覽器要怎麼顯示已在 §5.2 指出走 POC 同機制 Design 規劃 UI
### 給 Architect 自我檢查
- [x] 每個 ADR 都有 Context / Decision / Consequences
- [x] 所有雛形實作都有明確的 Phase 1 替換計畫
- [x] 擴展策略說明完整(§4
- [x] 安全架構覆蓋 STRIDE(§6.6
---
**下一步**閱讀 `TDD.md`實作細節以及各 ADR