visionA/docs/autoflow/04-architecture/adr/adr-011-supersede-adr-005.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

8.3 KiB
Raw Permalink Blame History

ADR-011推翻 ADR-005 — 雛形階段升級接 Innovedus Member Center

狀態

Accepted — 2026-04-26

推翻

ADR-005 — Auth 部分DB 部分仍有效)

背景 (Context)

ADR-0052026-04-21在 Phase 0 雛形階段決定不接 auth

  • StaticAuthProvider 任何帳密都通過、永遠回 demo-user
  • StaticAuthService middleware 永遠注入 demo-user UserContext
  • 雛形 PRD / TDD 中所有 user-bound 資源Device / Model / PairingToken都綁到 demo-user

當時的決策邏輯:

  • 雛形階段目標是驗證「雲端端對端連通」技術可行性
  • 把時間花在 Auth、user 系統、DB schema 上會延誤核心驗證
  • 介面(AuthProvider / AuthService)已切乾淨,未來換實作零業務邏輯改動

到了 Phase 0.62026-04-26情況變了

  • 雛形已交付Phase 0 + Phase 0.5 全綠),核心架構通過驗證
  • 需要進入 Phase 1多用戶、上線給 FAE 試用)— 沒真實 user 寸步難行
  • 同期間 Innovedus 集團另一條線 Member Center 已可用C# .NET Core + OpenIddict + PostgreSQL70% 完成度OAuth Authorization Code + PKCE + JWKS 都能跑)
  • 跨產品 SSO 是 Innovedus 集團方向visionA / kneron_model_converter / 未來其他產品線)

繼續用 StaticAuth 的代價:

  • 無法做多用戶測試(內部 FAE 試用無法區分使用者)
  • 無法把雛形交給內部使用者(資料會混在一起)
  • 之後要接 OIDC 還是要做 → 不如現在做完,後面少一輪改動

決策 (Decision)

推翻 ADR-005 的 Auth 部分Phase 0.6 起 visionA-backend 的唯一認證路徑改為 OIDC接 Innovedus Member Center。

具體做法

  1. 拔除 StaticAuthProvider / StaticAuthService

    • 刪除 internal/auth/static.go + static_test.go
    • internal/api/middleware.goAuthMiddleware 拿掉雙模式分支,只剩 OIDC
    • internal/api/api.goDeps 拿掉 AuthService / AuthProvider 欄位;validate() 強制 OIDCProvider + SessionManager 必填(缺則啟動 panic
    • cmd/api-server/main.go 拿掉 cfg.OIDC.Enabled 旗標分支OIDC 變成必須路徑
  2. OIDC 實作OB1-OB4 已完成;本 ADR 只記錄決策)

    • 採 OAuth 2.0 Authorization Code + PKCE + BFF Pattern詳見 ADR-010
    • visionA-backend 是 OIDC confidential client持有 client_secret
    • frontend 完全不接觸 token只看到 visiona_session cookie
    • In-memory session store重啟即消失雛形階段可接受
  3. 保留 AuthProvider / AuthService interface

    • 雖然 Static 實作已刪interface 本身仍保留在 internal/auth/auth.go
    • 給未來新增備援 providerPhase 1 backup local auth、service-to-service token使用
    • 介面代表 contract — 提早設計、提早被驗證的介面比 ad-hoc 重新發明便宜
  4. Pairing Token 流程不動ADR-005 的另一個面向)

    • PairingStore / SessionTokenStore 仍是 in-memory + interface 抽象
    • 唯一改變:UserContext.UserID 從固定的 "demo-user" 變成 OIDC subUUID自然穿透到 PairingStore.Create 的 user_id 參數
    • Agent 端不知道 user 是誰、不接 OIDC
  5. dev 環境策略

    • 不寫 mock OIDC server測試例外 — 見 internal/oidctest
    • 開發者要登入就得起 Member Centerdocker-compose 一鍵化)
    • 為了讓 demo-user 流程繼續可用Member Center 端會 seed demo@visionA.local / demo123 帳號

仍維持 ADR-005 規範的部分

  • 不接真實 DBDevice / Model / Pairing 仍用 InMemoryRepository
  • Repository interface 抽象Phase 1 換 PostgresRepository 仍然零業務邏輯改動
  • 資料重啟會遺失:雛形 process 重啟 → user session、device、model、pairing token 全消失

考慮過的替代方案

方案 評估 排除原因
繼續用 StaticAuth 到 Phase 1 不用做事 無法多用戶測試FAE 試用會撞牆;之後還是要接
保留 dev fallback 切換 dev 環境不需起 Member Center 各環境行為分歧難排查;且 Member Center docker-compose 一鍵起,成本不高
接 Auth0 / Clerk / Cognito 現成 跨 Innovedus 產品 SSO 需企業方案vendor lock-in資料外流
自刻 email + password + JWT 完全掌控 要做密碼重設、2FA、暴力破解防禦維運成本太高

詳細替代方案分析見 ADR-010

後果 (Consequences)

正面影響

  • 跨 Innovedus 產品 SSO:使用者一組帳號用所有 Innovedus 產品線
  • 真實 user binding for Pairing token:多使用者上線時不再混淆
  • 進 Phase 1 的前置就緒FAE 內部試用、多用戶測試、上線都有 Auth 基礎
  • frontend 安全性提升Token 在 backend不存 localStorage順便清掉 security.md §14.1 / §14.2 / §14.3 三筆雛形安全債)
  • demo-user 流程繼續可用Member Center seed 同名帳號,雛形 demo 體驗不變
  • 程式碼更乾淨:拔除「雙模式 if/else」之後 auth middleware 邏輯線性、容易追蹤

負面影響(接受的取捨)

  • dev 環境多一個依賴:起 visionA 要先起 Member Center + Postgresdocker-compose 緩解)
  • 對 Member Center dev 環境穩定性有依賴MC 掛掉 visionA 也無法登入
    • 緩解docker-compose 固定版本Member Center 團隊維持基礎可用性
  • session 重啟即消失in-memory store雛形 Phase 0.6 可接受,內部測試者
    • Phase 1 換 Redis/DB同 interface

風險

風險 緩解
Member Center API 改動 → visionA 跟著爆 用 OIDC 標準介面discovery + JWKS — Member Center 改實作不改介面就 OK
Member Center webhookuser 刪除 / 停用)未實作 雛形不接收Phase 1 補(記入 oidc-tdd.md TODO
OIDC client_secret 外洩 env / Secrets Manager + 不 commit + log 不印 secret + 可隨時 rotate
既有 Pairing flow 對 user_id 變動的破壞 OB5 整合測試 TestOIDCE2E_PairingTokenBindsToOIDCUser + TestOIDCE2E_MultiUserIsolation 驗證 user binding 正確

合規性

  • Architect 確認
  • 使用者裁決 Q1OIDC + PKCE redirect— 見 ADR-010
  • 使用者裁決 Q4完全取代 StaticAuth不保留 dev fallback— 見 ADR-010
  • OB5 任務完成StaticAuth 已從 codebase 移除
  • OB5 任務完成:所有測試(含原 build-tag 隔離的 oidc_e2e_test.go皆通過
  • Phase 1 Kick-off補 user 表 + 接 DB取代 in-memory session store

相關文件

  • 上位:ADR-005(被本 ADR 推翻 Auth 部分DB 部分仍有效)
  • 同層:ADR-010OIDC 接入策略 — 為什麼選 BFF + Authorization Code + PKCE + Member Center
  • 詳細實作:oidc-tdd.mdPhase 0.6 OIDC TDD 增補)
  • 安全:security.md §2、§14前端安全債清單

後記2026-05-01

Phase 0.7 stage 部署時發現 Innovedus stage Member Center 配給 visionA 的 login OAuth client 是 public PKCE-only(無 client_secret),與本 ADR §32 中「visionA-backend 是 OIDC confidential client持有 client_secret」的假設不符。

具體狀況:

  • Stage MC 端為 redirect flow 配的是 public clientb8093fea1a504a5d8f0e04bee9f78f2e,無 secret
  • 另配一組 confidential client<see stage .env.stage> + secret給未來 client_credentials grant 用,login flow 不用此組
  • 表示 ADR-010 §「MC 強制 confidential」前提對 redirect flow 不再成立(對 server-to-server flow 仍成立)

處理:

  • visionA-backend 擴充為兩種 mode 都支援ClientSecret 從必填變選填runtime 判斷走哪條路)
  • 詳細決策見 ADR-013
  • 本 ADR 的核心結論OIDC 取代 StaticAuth、保留 AuthProvider/AuthService interface、Pairing 流程不動、in-memory session全部仍有效,只是 client 配置層多了一個維度

版本記錄

日期 版本 變更
2026-04-26 1.0 初版 — OB5 完成後正式記錄推翻 ADR-005 Auth 部分
2026-05-01 1.1 新增「後記」段stage 部署發現 MC login client 為 public PKCE-only擴充由 ADR-013 處理