feat(api): 升级开放 API 并支持投递回调

- 为 `/api/open/v1` 引入 Token scope、分页游标、幂等发信、发送事件与重试/取消能力。
- 新增投递事件签名回调与状态 webhook outbox,补充相关配置、迁移和测试。
- 同步更新 Web 端 API 类型、个人中心 Token 权限管理,以及中英文文档和 OpenAPI 契约。
This commit is contained in:
LanQin_
2026-07-10 10:47:58 +08:00
parent 25f54bc42f
commit 47f782a03c
20 changed files with 1891 additions and 162 deletions
+18 -2
View File
@@ -365,10 +365,26 @@ func (a *App) recordSendAudit(ctx context.Context, event, status string, in send
if source == "" {
source = "unknown"
}
_, err := a.db.ExecContext(ctx, `INSERT INTO send_audit_events(id,queue_id,user_id,mailbox_id,sent_message_id,source,event,status,mail_from,header_from,recipients_json,error,created_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)`, newID("audit"), in.QueueID, in.UserID, in.MailboxID, in.SentMessageID, source, event, status, normalizeEmail(in.MailFrom), normalizeEmail(in.HeaderFrom), jsonEncode(dedupeEmails(in.Recipients)), in.Error, a.now().UTC().Format(time.RFC3339Nano))
id := newID("audit")
createdAt := a.now().UTC()
item := SendAuditEvent{ID: id, QueueID: in.QueueID, MailboxID: in.MailboxID, SentMessageID: in.SentMessageID, Source: source, Event: event, Status: status, MailFrom: normalizeEmail(in.MailFrom), HeaderFrom: normalizeEmail(in.HeaderFrom), Recipients: dedupeEmails(in.Recipients), Error: in.Error, CreatedAt: createdAt}
tx, err := a.db.BeginTx(ctx, nil)
if err != nil {
a.log.Warn("failed to start send audit transaction", "event", event, "error", err)
return
}
defer tx.Rollback()
if _, err := tx.ExecContext(ctx, `INSERT INTO send_audit_events(id,queue_id,user_id,mailbox_id,sent_message_id,source,event,status,mail_from,header_from,recipients_json,error,created_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)`, id, in.QueueID, in.UserID, in.MailboxID, in.SentMessageID, source, event, status, item.MailFrom, item.HeaderFrom, jsonEncode(item.Recipients), in.Error, createdAt.Format(time.RFC3339Nano)); err != nil {
a.log.Warn("failed to record send audit", "event", event, "error", err)
return
}
if err := a.enqueueStatusWebhook(ctx, tx, "audit:"+id, "send."+event, in.MailboxID, item); err != nil {
a.log.Warn("failed to enqueue send status webhook", "event", event, "error", err)
return
}
if err := tx.Commit(); err != nil {
a.log.Warn("failed to commit send audit", "event", event, "error", err)
}
}