member_center/docs/DESIGN.md

5.0 KiB
Raw Blame History

系統設計草案Member Center

日期2026-01-30

1. 需求摘要(已確認)

  1. 多個網站共用的會員登入中心SSO
  2. 電子報訂閱管理(發送另建)
  3. 未註冊會員可訂閱;註冊後沿用訂閱資料
  4. 未註冊會員可取消訂閱(單一清單退訂)
  5. 登入需支援 API 與 Redirect 兩種方式OAuth2 + OIDC

2. 架構原則

  • OAuth2 + OIDCAuthorization Code + PKCE
  • 會員中心只管理 Email 與訂閱狀態
  • Double Opt-in
  • 各站自行設計 UI主要走 API少數狀況使用 redirect
  • 多租戶為邏輯隔離,但會員資料跨站共享
  • 公開訂閱端點必須使用 list_id + email 做資料邊界,禁止僅以 email 查詢或操作
  • 訂閱狀態同步採 event/queue
  • PostgreSQL
  • 實作C# .NET Core + MVC + OpenIddict

3. 使用者故事(精簡)

  • 訪客:在任一站點未登入狀態下輸入 Email 訂閱電子報
  • 訪客:在信件中點擊連結完成 double opt-in
  • 訪客:點擊取消訂閱連結即可退訂(單一清單)
  • 會員在任一站點登入後其他站點可無痛登入SSO
  • 站點後台:可管理站點資訊、訂閱清單、會員基本資料

4. 核心模組

  • Identity Service註冊、登入、密碼重設、Email 驗證
  • OAuth2/OIDC Service授權流程、token 發放、ID Token
  • Subscription Service訂閱/退訂/偏好管理
  • Admin Console租戶與清單管理
  • Mailer Integration驗證信/退訂信/確認信的發送介面(外部系統)
  • Event Publisher訂閱事件發佈供發信系統或數據系統消費

5. 資料模型(概念)

  • tenants
    • id, name, domains, status, created_at
  • users (ASP.NET Core Identity)
    • id, user_name, email, password_hash, email_confirmed, lockout, created_at
  • roles / user_roles (Identity)
    • id, name, created_at
  • OpenIddictApplications
    • id, client_id, client_secret, display_name, permissions, redirect_uris, properties
  • OpenIddictAuthorizations
    • id, application_id, status, subject, type, scopes
  • OpenIddictTokens
    • id, application_id, authorization_id, subject, type, status, expiration_date
  • OpenIddictScopes
    • id, name, display_name, resources
  • newsletter_lists
    • id, tenant_id, name, status, created_at
  • newsletter_subscriptions
    • id, list_id, email, user_id (nullable), status, preferences, created_at
  • email_verifications
    • id, email, tenant_id, token_hash, purpose, expires_at, consumed_at
  • unsubscribe_tokens
    • id, subscription_id, token_hash, expires_at, consumed_at
  • audit_logs
    • id, actor_type, actor_id, action, payload, created_at
  • system_flags
    • id, key, value, updated_at

關聯說明:

  • newsletter_subscriptions.email 與 users.email 維持唯一性關聯
  • 使用者註冊時,如 email 存在訂閱紀錄,補上 user_id
  • 單一清單退訂unsubscribe token 綁定 subscription_id

6. 核心流程

6.1 OAuth2/OIDC Redirect 登入Authorization Code + PKCE

  1. 站點導向 /oauth/authorize,帶 client_id, redirect_uri, code_challenge, scope=openid email
  2. 使用者於會員中心登入
  3. 成功後導回 redirect_uri 並附 code
  4. 站點以 code + code_verifier/oauth/token 換取 token + id_token

6.2 OAuth2 API 使用(站點自行 UI

  1. 站點以 API 驗證使用者登入(會員中心提供 login API
  2. 成功後取得 token含 ID Token 可選)
  3. 站點以 access_token 呼叫其他會員中心 API

6.3 未登入狀態的訂閱流程(在獨立平台)

  1. 使用者在各站點輸入 Email 並選擇訂閱清單
  2. 站點呼叫 POST /newsletter/subscribe
  3. 會員中心建立 pending 訂閱並發送驗證信(透過外部發信系統)
  4. 使用者點擊信件連結 /newsletter/confirm?token=...
  5. 訂閱狀態改為 active
  6. 會員中心發出事件 subscription.activated 到 event/queue

6.4 未登入退訂(單一清單)

  1. 信件提供「一鍵退訂」連結 /newsletter/unsubscribe?token=...
  2. 驗證 token 後將該訂閱標記為 unsubscribed
  3. 會員中心發出事件 subscription.unsubscribed 到 event/queue

6.5 註冊後銜接

  1. 使用者完成註冊
  2. 系統搜尋 newsletter_subscriptions.email
  3. user_id 補上並保留偏好
  4. 可選:發出事件 subscription.linked_to_user

7. API 介面(草案)

  • GET /oauth/authorize
  • POST /oauth/token
  • GET /.well-known/openid-configuration
  • POST /auth/login (API-only login)
  • POST /auth/refresh
  • POST /newsletter/subscribe
  • GET /newsletter/confirm
  • POST /newsletter/unsubscribe
  • POST /newsletter/unsubscribe-token
  • GET /newsletter/preferences
  • POST /newsletter/preferences

8. 安全與合規

  • 密碼強度與防暴力破解rate limit + lockout
  • Token rotation + refresh token revoke
  • Redirect URI 白名單 + PKCE
  • Double opt-in可配置
  • Audit log
  • GDPR/CCPA資料匯出與刪除規劃中

9. 其他文件

  • docs/UI.md
  • docs/USE_CASES.md
  • docs/FLOWS.md
  • docs/OPENAPI.md
  • docs/SCHEMA.sql
  • docs/TECH_STACK.md