warrenchen d49c30b447 feat: Add SQS integration for SES event processing
- 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.
2026-02-26 17:10:25 +09:00

102 lines
3.4 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
本文件描述 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**
- 使用簽名 WebhookHMAC已實作
- 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 CredentialsSend 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_idMember Center 做二次驗證
### 防護與審計
- 所有跨服務呼叫需記錄 `tenant_id``client_id``scope``request_id`
- API 層進行 scope 檢查與 tenant 一致性檢查
- Event Ingest 與 Webhook 需具備重放防護timestamp + nonce
### 名單外流風險控制
- Send Engine 不提供「名單查詢 API」
- 全量同步由 Member Center 發動並推送
- 如需測試/診斷,僅回傳計數與版本資訊,不回傳名單內容
## 資料模型原則
- 事件為 append-only快照表僅反映最新狀態
- 任何狀態變更必須可追溯(含來源與租戶)