241 lines
11 KiB
Markdown
241 lines
11 KiB
Markdown
<!-- b5e97267-b1d5-4ef9-9217-ebd91392307c -->
|
||
---
|
||
todos:
|
||
- id: "ddl-mail-tables"
|
||
content: "在 slot-notification 新增 mail_config(SMTP 直字段)/ mail_template / mail_send_log 表 DDL"
|
||
status: pending
|
||
- id: "mail-module"
|
||
content: "实现 app/mail 模块:Model、Entity、Cache、MailService、SmtpMail SDK"
|
||
status: pending
|
||
- id: "notification-api"
|
||
content: "新增 EmailController + MailConfigAdminController 与 route 注册"
|
||
status: pending
|
||
- id: "sdk-client"
|
||
content: "扩展 slot-lib / slot-sdk 的 MailService 客户端方法"
|
||
status: pending
|
||
- id: "console-migrate"
|
||
content: "slot-console CommonController 改调 notification;废弃本地 MailService"
|
||
status: pending
|
||
- id: "admin-ui"
|
||
content: "slot-admin 后端 + slot-admin-vue 邮件配置管理页"
|
||
status: pending
|
||
- id: "data-migration"
|
||
content: "编写 mail_config 从 slot-console 配置组到表的幂等迁移脚本"
|
||
status: pending
|
||
- id: "verify"
|
||
content: "跑 verify-slot-backend.sh,验证发信/验码/后台 CRUD 链路"
|
||
status: pending
|
||
isProject: false
|
||
---
|
||
# slot-notification 邮件配置表化(对齐短信)
|
||
|
||
## 现状与结论
|
||
|
||
当前两套通知渠道配置方式不一致:
|
||
|
||
| 能力 | 短信(已收口) | SMTP 邮件(未收口) |
|
||
|---|---|---|
|
||
| 配置存储 | [`slot-notification/app/sms/model/SmsConfigModel.php`](slot-notification/app/sms/model/SmsConfigModel.php) → `sms_config` 表 | [`slot-console/app/service/lib/MailService.php`](slot-console/app/service/lib/MailService.php) → `ConfigService::getGroupData('mail_config')` |
|
||
| 发送服务 | [`slot-notification/app/sms/services/SmsService.php`](slot-notification/app/sms/services/SmsService.php) | `slot-console` 本地 `MailService` + PHPMailer |
|
||
| 验证码 API | `/innerapi/sms/sendVerifyCode` | `slot-console` `CommonController::sendEmailCode` |
|
||
| 后台管理 | slot-admin → slot-lib → notification `/innerapi/admin/*` | slot-admin 通用配置页 `email_config`(另一套) |
|
||
|
||
**结论:应该建表。** 你已选择「完整对齐短信」,建议把 SMTP 邮件作为 slot-notification 的第二条外发渠道,与短信保持同一套「配置表 + 发送日志 + innerapi + 后台管理 + SDK 客户端」模式。
|
||
|
||
注意:slot-notification 里现有 [`MailController`](slot-notification/app/innerapi/controller/MailController.php) / [`EmailService`](slot-notification/app/message/service/EmailService.php) 实际是**站内消息**兼容别名,不是 SMTP。新 SMTP 能力应使用独立命名空间(建议 `app/mail/*`)和独立路由前缀(建议 `/innerapi/email/*`),避免与 `/innerapi/mail/*`(站内消息)冲突。
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph before [当前]
|
||
lobby1[Lobby] --> console1[slot-console CommonController]
|
||
console1 --> config1["ConfigService mail_config"]
|
||
console1 --> mail1[MailService PHPMailer]
|
||
end
|
||
|
||
subgraph after [目标]
|
||
lobby2[Lobby] --> console2[slot-console 薄代理]
|
||
console2 --> sdk[slot-lib MailService]
|
||
sdk --> notif[slot-notification EmailController]
|
||
notif --> table["mail_config 表"]
|
||
notif --> smtp[SmtpMail PHPMailer]
|
||
notif --> log["mail_send_log 表"]
|
||
end
|
||
```
|
||
|
||
---
|
||
|
||
## 表结构设计(邮件用直字段,短信保留 JSON)
|
||
|
||
在 `s_message`(与 `sms_config` 同库)新增两张表。
|
||
|
||
### 为什么邮件不用 JSON、短信用 JSON?
|
||
|
||
| 对比 | 短信 `sms_config.config` | 邮件 `mail_config` |
|
||
|---|---|---|
|
||
| 字段形态 | 各平台差异大(Buka 要 appId/senderId,Ant/Chuanglan 字段不同) | SMTP 标准字段固定,截图与代码一致 |
|
||
| 后台表单 | 按 `platform` 动态展示不同表单项 | 固定 6~8 个输入框,与现有配置页一一对应 |
|
||
| 查询/校验 | 结构不统一,适合 JSON | 可直接列级校验、索引、迁移映射 |
|
||
|
||
**结论:邮件配置用直接字段更好;不必为了「和短信表长得像」而强行 JSON。**
|
||
|
||
### 当前邮件配置项(来自截图,仅 SMTP 连接)
|
||
|
||
截图中的 6 项即为 `mail_config` 配置组现有字段,与 [`MailService`](slot-console/app/service/lib/MailService.php) 读取项一致。**这就是邮件配置表应存的全部内容**:
|
||
|
||
| 配置项 | 列名建议 | 说明 |
|
||
|---|---|---|
|
||
| smtp host | `smtp_host` | 如 `email-smtp.us-east-1.amazonaws.com` |
|
||
| 用户名 | `username` | SMTP 登录账号 |
|
||
| 密码 | `password` | SMTP 密码/应用专用密码 |
|
||
| 端口 | `port` | 如 `587` |
|
||
| 发件人地址 | `from_address` | 原 `from` |
|
||
| 发件人名称 | `from_name` | 如 `TOGOO` |
|
||
|
||
加密方式(`tls`/`ssl`)**不单独落库**:发送时按 `port` 推断即可(`587` → STARTTLS,`465` → SSL),与现网行为一致。
|
||
|
||
### 邮件模板(独立概念,不属于 mail_config)
|
||
|
||
验证码邮件的标题/正文来自 `email_template` 配置组(`title`、`binding_email`),属于**发送模板**,不是 SMTP 连接配置。
|
||
|
||
发送邮件时需要两张表配合:
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
sendMail[MailService 发信] --> mailConfig["mail_config\nSMTP 连接"]
|
||
sendMail --> mailTemplate["mail_template\n标题/正文模板"]
|
||
```
|
||
|
||
### `mail_config`(仅 SMTP 连接,直字段)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| `id` | bigint PK | 主键 |
|
||
| `platform` | varchar(32) | 渠道标识,如 `AwsSes`、`Zoho` |
|
||
| `status` | tinyint | 1 启用 / 2 禁用 |
|
||
| `num` | int | 排序,降序优先 |
|
||
| `smtp_host` | varchar(255) | SMTP 主机 |
|
||
| `username` | varchar(128) | SMTP 用户名 |
|
||
| `password` | varchar(512) | SMTP 密码 |
|
||
| `port` | int | SMTP 端口 |
|
||
| `from_address` | varchar(255) | 发件人邮箱 |
|
||
| `from_name` | varchar(128) | 发件人显示名 |
|
||
| `create_time` / `update_time` | datetime | 审计字段 |
|
||
|
||
### `mail_template`(邮件发送模板,独立表)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| `id` | bigint PK | 主键 |
|
||
| `template_code` | varchar(64) | 模板编码,如 `bindingEmail`、`authEmail` |
|
||
| `template_name` | varchar(128) | 模板名称 |
|
||
| `title` | varchar(255) | 邮件标题模板 |
|
||
| `body` | text | 邮件正文模板,支持 `{code}` 等变量 |
|
||
| `status` | tinyint | 1 启用 / 2 禁用 |
|
||
| `create_time` / `update_time` | datetime | 审计字段 |
|
||
|
||
首期迁移:把 `email_template` 配置组中的 `title` + `binding_email` 迁入 `mail_template`(`template_code=authEmail` 或按业务拆分)。
|
||
|
||
**注意**:`message_template` 是站内消息模板,与 SMTP 外发邮件模板是不同业务,不混用。
|
||
|
||
### `mail_send_log`(发送日志,放 `s_common`)
|
||
|
||
镜像 [`sms_send_log`](slot-notification/app/sms/model/SmsSendLogModel.php):
|
||
|
||
- `unique_sn`, `email`, `platform`, `subject`, `content`, `status`, `type`, `retry_num`, `create_time`
|
||
|
||
---
|
||
|
||
## 后端实现(slot-notification)
|
||
|
||
### 1. 数据层
|
||
|
||
新建 `app/mail/` 模块,参照 `app/sms/`:
|
||
|
||
- `MailConfigModel` / `MailSendLogModel`
|
||
- `MailConfigEntity`(后台 CRUD,复用短信 Entity 分页模式)
|
||
- 在 [`initDB.php`](slot-notification/app/command/initDB.php) 补充 DDL;另提供 `db/mail_config.sql` 便于手工执行
|
||
|
||
### 2. 发送层
|
||
|
||
- `composer.json` 增加 `phpmailer/phpmailer`
|
||
- `MailService`:从 `mail_config` 取 SMTP 连接,从 `mail_template` 取标题/正文 → PHPMailer 发信 → 写 `mail_send_log`
|
||
- `app/mail/services/sdk/BaseMail.php` + `SmtpMail.php`(首期只实现 SMTP,结构与 `BaseSms` 一致,便于后续扩展 SendGrid 等)
|
||
- `MailCache`:验证码 Redis 缓存(镜像 `SmsCache`),key 规则与 slot-console [`EmailCodeLibService`](slot-console/app/service/lib/EmailCodeLibService.php) 保持一致,避免迁移期验证码失效
|
||
|
||
### 3. API 层
|
||
|
||
新增路由([`config/route.php`](slot-notification/config/route.php)):
|
||
|
||
- `POST /innerapi/email/send-verify-code`
|
||
- `POST /innerapi/email/verify-code`
|
||
- `POST /innerapi/admin/mail-config/index|save|update|destroy`
|
||
- `POST /innerapi/admin/mail-template/index|save|update|destroy`(模板 CRUD,与配置分开)
|
||
|
||
新建 `EmailController`(发送/校验)与 `MailConfigAdminController`(配置 CRUD),**不要**复用现有站内消息 `MailController`。
|
||
|
||
### 4. 渠道选择策略
|
||
|
||
首期与短信一致:按 `status=启用` + `num desc` 取第一条;预留后续 failover(注释掉的短信轮询逻辑可一并参考)。
|
||
|
||
---
|
||
|
||
## 跨服务改造
|
||
|
||
### slot-lib / slot-sdk
|
||
|
||
在 [`slot-lib/src/services/notification/`](slot-lib/src/services/notification/) 新增 `MailService`(或 `EmailService`):
|
||
|
||
- `sendVerifyCode(email, type)`
|
||
- `verifyCode(email, code, type)`
|
||
- `getMailConfigPageList` / `saveMailConfig` / `updateMailConfig` / `destroyMailConfig`
|
||
|
||
同步扩展 [`slot-sdk/src/service/notification/NotificationService.php`](slot-sdk/src/service/notification/NotificationService.php)。
|
||
|
||
### slot-console(调用方改造)
|
||
|
||
[`CommonController::sendEmailCode`](slot-console/app/api/controller/CommonController.php) / `verifyEmailCode`:
|
||
|
||
- 改为调用 slot-lib `MailService`,不再直接依赖本地 `MailService` + `ConfigService`
|
||
- 本地 [`MailService`](slot-console/app/service/lib/MailService.php) 标记废弃或删除(确认无其他引用后)
|
||
|
||
限流、参数校验仍留在 slot-console Controller 层(与现有短信 napi 模式一致)。
|
||
|
||
### slot-admin + slot-admin-vue
|
||
|
||
镜像短信后台:
|
||
|
||
- 后端:[`slot-admin/app/game/controller/SmsController.php`](slot-admin/app/game/controller/SmsController.php) → 新建 `MailController`
|
||
- 前端:新建 `mail/config/` 页,仅 6 个 SMTP 字段 + platform/status/num;另建 `mail/template/` 页管理标题/正文模板
|
||
- 菜单/权限:新增 `mailConfig` 路由与按钮权限
|
||
|
||
---
|
||
|
||
## 数据迁移
|
||
|
||
新增一次性迁移脚本(建议 `slot-notification/app/command/MigrateMailConfig.php`):
|
||
|
||
1. 从 `s_config` 读取 `mail_config` 配置组 → 写入 `mail_config` 表(6 个 SMTP 字段)
|
||
2. 从 `s_config` 读取 `email_template` 配置组 → 写入 `mail_template` 表(`title` + `binding_email`)
|
||
3. 幂等插入(已存在则跳过)
|
||
|
||
迁移完成后,`slot-console` 侧 `mail_config` / `email_template` 配置组可保留只读一段时间,确认无回退需求后再清理。
|
||
|
||
---
|
||
|
||
## 风险与边界
|
||
|
||
- **命名冲突**:`/innerapi/mail/*` 继续保留给站内消息;SMTP 统一走 `/innerapi/email/*`
|
||
- **验证码兼容**:`MailCache` 的 Redis key 必须与 slot-console 现有 `ShareRedisKeyManagerService::emailCode()` 一致
|
||
- **模板范围**:本期只迁移验证码邮件模板(`binding_email`/`title`);充值/提现等 MQ 站内邮件模板(`message_template` 配置组)不在本次范围
|
||
- **多 SMTP failover**:表结构支持,首期实现「取第一条启用配置」即可
|
||
|
||
---
|
||
|
||
## 验收标准
|
||
|
||
1. slot-admin 可 CRUD `mail_config`,与短信配置页体验一致
|
||
2. Lobby 发/验邮箱验证码链路走 slot-notification,功能与迁移前一致
|
||
3. 发送成功/失败均写入 `mail_send_log`
|
||
4. slot-console 不再读取 `ConfigService::getGroupData('mail_config')`
|
||
5. 执行 `verify-slot-backend.sh` 通过
|