97 lines
6.5 KiB
Markdown
97 lines
6.5 KiB
Markdown
# Install
|
||
|
||
- 需求:.NET SDK 8.x, PostgreSQL
|
||
- 設定:複製 `.env.example` → `.env`
|
||
- AWS Credential(SQS/SES):
|
||
- Local / Docker 開發:
|
||
- 設定 `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`(若為臨時憑證再加 `AWS_SESSION_TOKEN`)
|
||
- 設定 `AWS__Region`(或 `Sqs__Region` / `Ses__Region`)
|
||
- 建議設 `AWS_EC2_METADATA_DISABLED=true`,避免本機誤打 EC2 metadata
|
||
- ECS 正式環境(建議):
|
||
- 不要放 Access Key,改用 ECS Task Role(`taskRoleArn`)
|
||
- Task Role 至少授權:
|
||
- `sqs:ReceiveMessage`
|
||
- `sqs:DeleteMessage`
|
||
- `sqs:GetQueueAttributes`
|
||
- `ses:SendEmail`(raw_bulk)
|
||
- `ses:SendBulkEmail`(bulk_template,若有使用)
|
||
- ECS Task Definition 可設定環境變數:
|
||
- `AWS_REGION=ap-northeast-1`(或直接用 `.env` 的 `AWS__Region`)
|
||
- Migration:
|
||
- 預設由 API 啟動時自動執行(`Db__AutoMigrate=true`)
|
||
- 需要關閉時請設定 `Db__AutoMigrate=false`
|
||
- 手動執行可用 `dotnet run --project src/SendEngine.Installer -- migrate`
|
||
- Webhook Auth 初始化(不使用 SQL 檔,改用 Installer):
|
||
- 若僅需先建立 tenant 基本資料:
|
||
- `dotnet run --project src/SendEngine.Installer -- ensure-tenant --tenant-id <tenant_uuid> [--tenant-name <name>]`
|
||
- 使用 Installer 建立 webhook client(`id` 自動隨機產生):
|
||
- `dotnet run --project src/SendEngine.Installer -- add-webhook-client --tenant-id <tenant_uuid> [--tenant-name <name>] --client-id <client_id> --name <display_name> --scopes <scope1,scope2>`
|
||
- 例如:`dotnet run --project src/SendEngine.Installer -- add-webhook-client --tenant-id 11111111-1111-1111-1111-111111111111 --tenant-name "Tenant A" --client-id member-center-webhook --name "Member Center Webhook" --scopes newsletter:events.write`
|
||
- 若 tenant 不存在,Installer 會先自動建立 `tenants` 基本資料,避免 webhook 出現 `tenant_not_found`
|
||
- 建立成功後,Member Center webhook header `X-Client-Id` 請帶回傳的 `id`
|
||
- 若要自動同步到 Member Center `POST /integrations/send-engine/webhook-clients/upsert`(保留原手動流程):
|
||
- `dotnet run --project src/SendEngine.Installer -- add-webhook-client --tenant-id <tenant_uuid> --client-id <client_id> --name <display_name> --scopes <scope1,scope2> --upsert-member-center --mc-base-url <member_center_base_url> --mc-client-id <oauth_client_id> --mc-client-secret <oauth_client_secret> --mc-scope newsletter:events.write.global`
|
||
- 可選參數:
|
||
- `--mc-token-path`(預設 `/oauth/token`)
|
||
- `--mc-upsert-path`(預設 `/integrations/send-engine/webhook-clients/upsert`)
|
||
- `--mc-token-url` / `--mc-upsert-url`(使用完整 URL 時可覆蓋 path 組合)
|
||
- Webhook 驗證規則為 tenant 綁定:`auth_clients.tenant_id` 必須等於 payload `tenant_id`
|
||
- 不支援 `X-Client-Id` fallback
|
||
- 預設拒絕 `tenant_id = NULL` 的通用 client(`Webhook__AllowNullTenantClient=false`)
|
||
- Member Center 回寫授權(建議):
|
||
- `MemberCenter__BaseUrl`(建議)
|
||
- `MemberCenter__DisableSubscriptionPath`(預設 `/subscriptions/disable`)
|
||
- `MemberCenter__TokenPath`(預設 `/oauth/token`)
|
||
- `MemberCenter__OneClickUnsubscribeTokensPath`(預設 `/newsletter/one-click-unsubscribe-tokens`)
|
||
- `MemberCenter__ClientId`
|
||
- `MemberCenter__ClientSecret`
|
||
- `MemberCenter__Scope=newsletter:events.write`
|
||
- `MemberCenter__ApiToken` 僅作暫時 fallback(非首選)
|
||
- Send Job API 驗證(JWT):
|
||
- `Jwt__Issuer`
|
||
- `Jwt__Audience`
|
||
- 建議(Member Center OIDC/JWKS):
|
||
- `Jwt__Authority`(例如 `http://member-center`)
|
||
- 或 `Jwt__MetadataAddress`(例如 `http://member-center/.well-known/openid-configuration`)
|
||
- 若兩者都未設定,會自動回退使用 `MemberCenter__BaseUrl + /.well-known/openid-configuration`
|
||
- `Jwt__RequireHttpsMetadata`(本機可設 `false`)
|
||
- 相容舊模式(不建議):`Jwt__SigningKey`(HS 對稱驗簽)
|
||
- 本機測試輔助(臨時):
|
||
- `TestFriendly__Enabled=true` 時:
|
||
- webhook 收到未知 tenant 會自動建立 tenant
|
||
- `/webhooks/ses` 不做任何 DB 存取,但會保留 Member Center callback 流程(僅用於測試流程打通)
|
||
- Dev Sender(Mock 發信):
|
||
- `DevSender__Enabled=true`:背景 worker 會處理 `pending` send jobs,並將每位收件人的預計發送內容寫入 `events_inbox`(`source=dev_sender`, `event_type=send.preview`)
|
||
- `DevSender__PollIntervalSeconds`:輪詢間隔秒數(預設 5)
|
||
- `ESP__Provider=ses` 時,即使 `DevSender__Enabled=false`,背景 sender 仍會啟動並改用 SES 發送(模式由 `Ses__SendMode` 決定)
|
||
- SES 相關參數:`Ses__Region`、`Ses__FromEmail`、`Ses__ConfigurationSet`(可選)、`Ses__SendMode`、`Ses__TemplateName`
|
||
- SNS 簽章驗證參數:
|
||
- `Ses__SkipSignatureValidation`(建議正式環境 `false`)
|
||
- `Ses__AllowedTopicArns`(逗號分隔 allowlist;建議正式環境必填)
|
||
- `Ses__AllowedCertHosts`(逗號分隔;留空時只接受 `sns.*.amazonaws.com`)
|
||
- `Ses__SignatureMaxSkewSeconds`(預設 300)
|
||
- `Ses__SendMode=raw_bulk`(預設):使用 SES `SendEmail`,依內容分組後每次最多 50 位收件者(不依賴 SES Template)
|
||
- `Ses__SendMode=bulk_template`:使用 SES `SendBulkEmail` + Template(需提供 `template.ses_template_name` 或 `Ses__TemplateName`)
|
||
- SES 發送時會附帶 message tags:`tenant_id`、`list_id`、`campaign_id`、`send_job_id`
|
||
- SQS Poller(SES 事件回流):
|
||
- `Sqs__Enabled=true`
|
||
- `Sqs__QueueUrl=<aws_sqs_queue_url>`
|
||
- `Sqs__Region`(未設定時回退 `AWS__Region` 再回退 `Ses__Region`)
|
||
- `Sqs__PollWaitSeconds`(預設 20)
|
||
- `Sqs__MaxMessages`(預設 10)
|
||
- `Sqs__VisibilityTimeoutSeconds`(預設 30)
|
||
- SQS poller 目前未提供獨立 DLQ worker;可先用 AWS SQS redrive policy 管理失敗訊息
|
||
- `SendBulkEmail` 會使用 SES 模板名稱:
|
||
- 先讀 `campaign.template.ses_template_name`
|
||
- 若未提供則回退 `Ses__TemplateName`
|
||
- 若設定了 Member Center one-click token endpoint,sender 會在發送前批次呼叫 `/newsletter/one-click-unsubscribe-tokens`,僅發送 `status=issued` 的收件者
|
||
- 內容替換合約(Mock 與 SES 共用):
|
||
- `{{email}}`
|
||
- `{{unsubscribe_token}}`
|
||
- `{{tenant_id}}` / `{{list_id}}` / `{{campaign_id}}` / `{{send_job_id}}`
|
||
- 若在 `campaign.template` 提供:
|
||
- `list_unsubscribe_url_template`
|
||
- `list_unsubscribe_mailto`
|
||
- sender 會自動加上 `List-Unsubscribe` 與 `List-Unsubscribe-Post` headers
|
||
- 正式環境建議維持 `false`
|