- Introduced SqsSesPollerWorker to poll messages from SQS and process SES events. - Implemented SesEventProcessingService to handle SES event payloads and store them in the database. - Updated DevMockSenderWorker to support new SES sending methods and improved logging for unsubscribe headers. - Added AWS SDK for SQS to project dependencies.
102 lines
3.4 KiB
Markdown
102 lines
3.4 KiB
Markdown
# Design
|
||
|
||
本文件描述 Send Engine 的核心模組、資料流、模組邊界與 Auth/Scope 設計。
|
||
本引擎只負責事件控制與執行,不提供 UI。
|
||
ESP 介接暫定為 Amazon SES。
|
||
|
||
## 核心模組
|
||
- Event Ingest
|
||
- List Store(多租戶)
|
||
- Campaign / Send Job
|
||
- Sender Adapter
|
||
- Delivery & Bounce Handling
|
||
|
||
## Sending Proxy 規格整合
|
||
### 目標與邊界
|
||
- 接收內容網站或會員平台送來的發送工作
|
||
- 呼叫 Amazon SES API(優先 SES v2)
|
||
- 必帶 Configuration Set + Message Tags
|
||
- 消費 SES 回流事件(Bounce / Complaint / Delivery)
|
||
- 必要時回寫 Member Center
|
||
|
||
不負責:
|
||
- List-Unsubscribe one-click endpoint 本身的服務實作
|
||
- 會員最終名單權威資料庫
|
||
|
||
### 狀態機
|
||
Job 狀態(目前實作):
|
||
- pending
|
||
- running
|
||
- completed
|
||
- failed
|
||
- cancelled
|
||
|
||
Job 狀態(規劃擴充):
|
||
- queued
|
||
- sending
|
||
- sent
|
||
- partially_failed
|
||
|
||
Recipient 狀態:
|
||
- pending
|
||
- sent
|
||
- delivered
|
||
- soft_bounced
|
||
- hard_bounced
|
||
- complained
|
||
- suppressed
|
||
|
||
### SES 事件回流架構(建議)
|
||
- `SES Configuration Set -> SNS Topic -> SQS Queue -> ECS Worker`
|
||
- Worker 職責:
|
||
- Poll SQS
|
||
- 解析 SNS envelope 與 SES payload
|
||
- 更新 DB 狀態
|
||
- 必要時呼叫 Member Center 停用/註記 API
|
||
|
||
目前實作:
|
||
- 已提供 `SqsSesPollerWorker`(SQS 輪詢)
|
||
- worker 直接呼叫內部 SES processing service(不走 HTTP self-call)
|
||
- 仍保留 `POST /webhooks/ses` 直接接收模式(相容/測試)
|
||
|
||
## 信任邊界與 Auth 模型
|
||
### 外部角色
|
||
- Member Center:事件來源與名單權威來源(authority)
|
||
- 各租戶網站:內容來源(campaign/content producer)
|
||
- Send Engine:執行與狀態記錄(executor)
|
||
|
||
### 信任邊界
|
||
- Send Engine 不自行發放 tenant 身分;一律以 Member Center 代表的 tenant scope 為準
|
||
- 所有 API 必須攜帶 tenant_id,且在驗證後固定於 request context
|
||
|
||
### 驗證方式(建議)
|
||
1. **Member Center → Send Engine**
|
||
- 使用簽名 Webhook(HMAC,已實作)
|
||
- header 內含 `X-Client-Id`,對應 `auth_clients.id` 並受 tenant 綁定與 scope 驗證
|
||
2. **租戶網站 → Send Engine**
|
||
- 使用 OAuth2 Client Credentials 或 JWT(由 Member Center 簽發)
|
||
- token 內含 `tenant_id` 與 scopes(例如 `newsletter:send.write`)
|
||
3. **Send Engine → Member Center**
|
||
- 使用 OAuth2 Client Credentials(Send Engine 作為 client)
|
||
- scopes 只允許 `newsletter:list.read` / `newsletter:events.read` / `newsletter:events.write`
|
||
|
||
### Tenant Scope 取得與約束
|
||
- **事件 ingest**:以 token 中的 `tenant_id` 為唯一來源,不接受 body 覆寫
|
||
- **Send Job 建立**:tenant_id 從 token 取得;list_id 必須屬於該 tenant
|
||
- **名單同步**:由 Member Center 主動推送(全量/增量),Send Engine 不主動拉取名單
|
||
- **回寫事件**:回寫時攜帶同一 tenant_id,Member Center 做二次驗證
|
||
|
||
### 防護與審計
|
||
- 所有跨服務呼叫需記錄 `tenant_id`、`client_id`、`scope`、`request_id`
|
||
- API 層進行 scope 檢查與 tenant 一致性檢查
|
||
- Event Ingest 與 Webhook 需具備重放防護(timestamp + nonce)
|
||
|
||
### 名單外流風險控制
|
||
- Send Engine 不提供「名單查詢 API」
|
||
- 全量同步由 Member Center 發動並推送
|
||
- 如需測試/診斷,僅回傳計數與版本資訊,不回傳名單內容
|
||
|
||
## 資料模型原則
|
||
- 事件為 append-only,快照表僅反映最新狀態
|
||
- 任何狀態變更必須可追溯(含來源與租戶)
|