mass_mail_engine/docs/OPENAPI.md
warrenchen e9712fb1f7 feat: Implement SendEngine database context and migrations
- Added SendEngineDbContext for managing database interactions.
- Created SendEngineDbContextFactory for design-time database context creation.
- Established dependency injection for the infrastructure layer.
- Defined entity configurations for Tenant, MailingList, Subscriber, ListMember, EventInbox, Campaign, SendJob, SendBatch, DeliverySummary, AuthClient, AuthClientKey, and WebhookNonce.
- Generated initial database migration snapshot.
- Implemented installer program for database migration commands.
2026-02-10 17:56:29 +09:00

257 lines
5.5 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.

# OpenAPI Notes
本文件描述 Send Engine 對外 API、Webhook 驗證與與 Member Center 的介接規則。
目標是讓 Member Center 與租戶網站可以清楚交換資料與責任邊界。
## Auth 與驗證
### 1. 租戶網站 → Send Engine API
使用 OAuth2 Client Credentials 或 JWT由 Member Center 簽發)。
必要 claims
- `tenant_id`
- `scope`(至少 `newsletter:send.write`
規則:
- `tenant_id` 只能取自 token不接受 body 覆寫
- `list_id` 必須屬於該 tenant
### 2. Member Center → Send Engine Webhook
使用簽名 WebhookHMAC或 OAuth2 Client Credentials建議簽名
Header 建議:
- `X-Signature`: `hex(hmac_sha256(secret, body))`
- `X-Timestamp`: Unix epoch seconds
- `X-Nonce`: UUID
- `X-Client-Id`: Auth client UUID對應 `auth_clients.id`
驗證規則:
- timestamp 在允許時間窗內(例如 ±5 分鐘)
- nonce 不可重複(重放防護)
- signature 必須匹配
- client 必須存在且為 active
### 3. Send Engine → Member Center 回寫
使用 OAuth2 Client CredentialsSend Engine 作為 client
scope 最小化:
- `newsletter:events.write`(停用回寫)
- `newsletter:list.read`(若未來仍需查詢)
## 通用欄位
### Timestamp
- 欄位:`occurred_at`
- 格式RFC3339例如 `2026-02-10T09:30:00Z`
### ID
- `tenant_id``list_id``subscriber_id``event_id` 皆為 UUID
## 通用錯誤格式
```json
{
"error": "string_code",
"message": "human readable message",
"request_id": "uuid"
}
```
## WebhookMember Center → Send Engine
### A. 訂閱事件(增量)
用途:同步新增/取消/偏好變更。
Endpoint
- `POST /webhooks/subscriptions`
Scope
- `newsletter:events.write`
事件型別:
- `subscription.activated`
- `subscription.unsubscribed`
- `preferences.updated`
Request Body示意
```json
{
"event_id": "uuid",
"event_type": "subscription.activated",
"tenant_id": "uuid",
"list_id": "uuid",
"subscriber": {
"id": "uuid",
"email": "user@example.com",
"status": "active",
"preferences": { "topic": "news" }
},
"occurred_at": "2026-02-10T09:30:00Z"
}
```
Response
- `200 OK`accepted
- `401/403`:驗證失敗
- `409`event_id 重複或 nonce 重放
- `422`:格式錯誤
### B. 全量名單同步
用途:由 Member Center 主動推送全量或分批名單,避免 Send Engine 拉取名單。
Endpoint
- `POST /webhooks/lists/full-sync`
Scope
- `newsletter:events.write`
Request Body分批示意
```json
{
"sync_id": "uuid",
"batch_no": 1,
"batch_total": 10,
"tenant_id": "uuid",
"list_id": "uuid",
"subscribers": [
{ "id": "uuid", "email": "a@example.com", "status": "active" },
{ "id": "uuid", "email": "b@example.com", "status": "unsubscribed" }
],
"occurred_at": "2026-02-10T09:30:00Z"
}
```
Response
- `200 OK`accepted
- `401/403`:驗證失敗
- `409`sync_id + batch_no 重複
- `422`:格式錯誤
## API租戶網站 → Send Engine
### C. 建立 Send Job
用途:租戶網站送入內容,建立 Campaign/Send Job 並排程。
Endpoint
- `POST /api/send-jobs`
Scope
- `newsletter:send.write`
Request Body
```json
{
"tenant_id": "uuid",
"list_id": "uuid",
"name": "Weekly Update",
"subject": "Weekly Update",
"body_html": "<p>Hello</p>",
"body_text": "Hello",
"template": null,
"scheduled_at": "2026-02-11T02:00:00Z",
"window_start": "2026-02-11T02:00:00Z",
"window_end": "2026-02-11T05:00:00Z",
"tracking": { "open": true, "click": false }
}
```
欄位規則:
- `subject` 必填,最小長度 1
- `body_html` / `body_text` / `template` 至少擇一
- `window_start` 必須小於 `window_end`(若有提供)
Response
```json
{
"send_job_id": "uuid",
"status": "pending"
}
```
### D. 查詢 Send Job
Endpoint
- `GET /api/send-jobs/{id}`
Scope
- `newsletter:send.read`
Response
```json
{
"id": "uuid",
"tenant_id": "uuid",
"list_id": "uuid",
"campaign_id": "uuid",
"status": "running",
"scheduled_at": "2026-02-11T02:00:00Z",
"window_start": "2026-02-11T02:00:00Z",
"window_end": "2026-02-11T05:00:00Z"
}
```
### E. 取消 Send Job
Endpoint
- `POST /api/send-jobs/{id}/cancel`
Scope
- `newsletter:send.write`
Response
```json
{
"id": "uuid",
"status": "cancelled"
}
```
## WebhookSES → Send Engine
### F. SES 事件回報
用途:接收 bounce/complaint/delivery/open/click 等事件。
Endpoint
- `POST /webhooks/ses`
驗證:
- 依 SES/SNS 規格驗簽(可用 `Ses__SkipSignatureValidation=true` 暫時略過)
Request Body示意
```json
{
"event_type": "bounce",
"message_id": "ses-id",
"tenant_id": "uuid",
"email": "user@example.com",
"bounce_type": "hard",
"occurred_at": "2026-02-10T09:45:00Z"
}
```
Response
- `200 OK`
## 外部 APISend Engine → Member Center
以下為 Member Center 端提供的 API非 Send Engine 的 OpenAPI 規格範圍。
### G. 停用訂閱回寫
用途:因 hard bounce / complaint 停用訂閱,並在 Member Center 註記來源。
EndpointMember Center 提供):
- `POST /api/subscriptions/disable`
Scope
- `newsletter:events.write`
Request Body示意
```json
{
"tenant_id": "uuid",
"subscriber_id": "uuid",
"list_id": "uuid",
"reason": "hard_bounce",
"disabled_by": "send_engine",
"occurred_at": "2026-02-10T09:45:00Z"
}
```
## 狀態碼與錯誤
通用錯誤:
- `401/403`Auth 或 scope 不符
- `409`重放或事件重複nonce / event_id
- `422`:資料格式錯誤
- `500`:伺服器內部錯誤