member_center/docs/DESIGN.md

129 lines
4.8 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.

# 系統設計草案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
- 多租戶為邏輯隔離,但會員資料跨站共享
- 訂閱狀態同步採 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`
- 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`