fix: align channel copy and gateway connection state

This commit is contained in:
hectorzhao
2026-07-09 14:57:55 +08:00
parent 2a65b41c4e
commit 06e6be3c39
12 changed files with 309 additions and 157 deletions
@@ -415,12 +415,12 @@
- 支持新增、编辑、删除、启用、停用短信通道。
- 删除通道采用软删除或停用归档,不能破坏历史发送、报备、日志外键;删除、启用、停用、复制等高影响操作必须二次确认并写系统日志。
- 支持复制通道:复制后新建一个通道,除 id/code 自动生成外,通道配置、CMPP 参数、通道报备字段、签名/引流报备材料和个性化字段配置均需从源通道复制;名称默认追加“副本”。
- 支持复制通道:复制后新建一个通道,除 id/code 自动生成外,通道配置、CMPP 参数、通道报备字段、签名/引流报备材料和个性化字段配置均需从源通道复制;名称默认追加“副本”;若源通道为 active,新副本默认保存为 disabled,避免复制后立即占用上游连接
- 支持发送测试短信。
- 支持查看通道成功率、未知率、失败率、累计发送量。
- 支持进入通道报备详情。
- 通道报备详情页中,签名下的引流信息默认收起,用户点击后展开;展开/收起只影响页面展示,不改变报备数据。
- 通道列表状态区域展示“连接日志”入口;点击后弹窗展示真实连接日志,包括连接请求、连接成功、断开、心跳、重连、异常等事件,日志来源于 Gateway 回写或 OperationLog。
- 通道列表状态区域展示“连接日志”入口;点击后弹窗展示真实连接日志,包括连接请求、连接成功、断开、心跳、重连、异常等事件,日志来源于 Gateway 回写或 OperationLog。通道连接状态、连接数和最近错误必须来自 Gateway 真实上游连接池回写,不能以一次性探测拨号成功代替长连接在线状态。
- 通道操作按钮应保持一致的两列布局,报备详情、编辑、复制、发送测试、启停、删除等操作文案清晰。
### 5.14 运营端通道组管理
@@ -1331,7 +1331,7 @@
### 1. 登录入口
- 客户端和运营端必须使用独立登录页面:客户端 `/client/login`,运营端 `/admin/login`。
- 两端登录均输入邮箱或手机号密码和图形验证码。
- 两端登录均输入用户名、邮箱或手机号,外加密码和图形验证码。
- 登录接口必须调用真实 NestJS API,不允许前端静态用户、localStorage mock 或纯前端验证码作为验收依据。
- 运营端登录仅允许平台管理员;客户端登录仅允许已关联企业的企业管理员。
@@ -1347,7 +1347,7 @@
- 运营端和客户端用户管理均需接入真实 API,支持添加、编辑、启用/禁用、删除、修改密码。
- 启用/禁用、删除必须弹窗确认。
- 删除采用软删除,历史系统日志、审核记录和业务记录仍可追溯;删除后用户不可登录且列表默认不展示。
- 客户端用户字段必须包含邮箱和手机号,并支持邮箱或手机号登录。
- 客户端用户字段必须包含邮箱和手机号,并支持用户名、邮箱或手机号登录。
- 所有创建、编辑、启用、禁用、删除、修改密码动作必须写系统日志。
### 4. fail2ban
+5 -3
View File
@@ -247,6 +247,7 @@
- 通道协议默认为 CMPP,CMPP 版本默认 2.0,且可选择 2.0 或 3.0。
- 通道限速保存正确。
- 通道真实保存 `desiredConnections/windowSize`,后续 Gateway `ConnectChannel``SubmitCommand.upstream` 使用该配置。
- 通道列表和通道组页面展示的连接状态、连接数和最近错误来自 Gateway 真实上游连接池回写;一次性连接探测成功不能展示为 `connected`
- 通道测试短信必须调用真实 NestJS API,创建独立 `SmsMessageRecord``SmsSubmitRecord`,并向 Redis Stream `gateway.submit.commands` 写入 `SubmitCommand`;短信记录页面能查询到该测试短信。
- 通道测试短信不得绑定企业、企业应用或 `SmsBatchTask` 发送任务;submit result 和 receipt 只更新短信记录、提交记录、回执记录和分片审计,不向客户侧推送 Deliver。
- 若通道未启用或没有在线 CMPP 连接,测试短信 API 返回明确错误,不能只在前端假提示成功。
@@ -442,6 +443,7 @@
- 预期结果:
- 后端创建新通道,新通道 id/code 与源通道不同,名称默认追加“副本”。
- 通道配置、CMPP 参数、报备字段、签名/引流报备材料和个性化字段与源通道一致。
- 若源通道为 active,新通道默认保存为 disabled,且不会立即触发上游真实连接。
- 复制动作写入系统日志。
- 复制后新通道可继续编辑、启停、删除,不影响源通道。
@@ -3090,13 +3092,13 @@ npm run verify:phase8
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-AUTH-001 | 打开 `/admin/login`,输入平台管理员邮箱或手机号密码和正确图形验证码。 | 登录成功进入运营端;session 用户角色为 `platform_admin`;后续运营端 API 使用真实后端。 |
| TC-AUTH-001 | 打开 `/admin/login`,输入平台管理员用户名、邮箱或手机号,外加密码和正确图形验证码。 | 登录成功进入运营端;session 用户角色为 `platform_admin`;后续运营端 API 使用真实后端。 |
| TC-AUTH-002 | 使用企业管理员账号登录 `/admin/login`。 | 登录失败;返回“仅平台管理员可登录运营端”类错误;失败次数累计。 |
| TC-AUTH-003 | 打开 `/client/login`,输入已关联企业的企业管理员邮箱或手机号密码和正确图形验证码。 | 登录成功进入客户端;客户端 API 自动携带当前企业 `tenantId`;Dashboard、用户、日志等仅展示当前企业数据。 |
| TC-AUTH-003 | 打开 `/client/login`,输入已关联企业的企业管理员用户名、邮箱或手机号,外加密码和正确图形验证码。 | 登录成功进入客户端;客户端 API 自动携带当前企业 `tenantId`;Dashboard、用户、日志等仅展示当前企业数据。 |
| TC-AUTH-004 | 使用平台管理员或未关联企业的用户登录 `/client/login`。 | 登录失败;不进入客户端。 |
| TC-AUTH-005 | 同一用户连续输错密码 5 次。 | 第 5 次后用户锁定 24 小时;锁定期内正确密码也被拒绝;系统记录失败次数和锁定时间。 |
| TC-AUTH-006 | 输入错误或过期图形验证码登录。 | 返回 400 可读错误;必须刷新验证码后重试。 |
| TC-USER-ADMIN-001 | 运营端新增平台管理员,填写邮箱或手机号、初始密码。 | 创建成功;用户无 `tenantId`;可登录运营端;写 `user.created` 日志。 |
| TC-USER-ADMIN-001 | 运营端新增平台管理员,填写用户名/登录账号、邮箱或手机号、初始密码。 | 创建成功;用户无 `tenantId`;可登录运营端;写 `user.created` 日志。 |
| TC-USER-ADMIN-002 | 运营端新增企业管理员但不选择企业。 | 返回 400;不创建用户。 |
| TC-USER-ADMIN-003 | 运营端新增企业管理员并选择企业。 | 创建成功;用户关联企业;可登录客户端;客户端数据按该企业隔离。 |
| TC-USER-ADMIN-004 | 运营端编辑用户、启用/禁用、删除、修改密码。 | 编辑和改密调用真实 API;启停/删除有确认弹窗;删除后列表不展示且不可登录;均写系统日志。 |
+14
View File
@@ -8,6 +8,19 @@
- 已执行:`npm --prefix api test -- channels.service.spec.ts --runInBand``npm --prefix api run build``npm run build`。待生产部署后用指定号码做一次真实发送验证,并回查 DB/短信记录。
- 2026-07-09 追加:按产品边界收窄通道测试短信,`SmsMessageRecord/SmsSubmitRecord/SmsReceiptRecord/SmsMessageSegmentAudit` 支持 `tenantId/batchTaskId` 为空;通道测试只记录短信、提交结果和回执,不进入企业账务、发送任务进度、客户侧 Deliver 推送或业务补发。
## 2026-07-09 通道复制默认停用与真实连接池状态回写修复
- 生产验证发现当前 3 个赛邮行业通道中有 2 个由首个 active 通道复制而来;数据库 `CmppConnectionState` 曾显示 3 条通道都为 `connected/currentConnections=1`,但生产机 `ss/netstat` 与上游平台都只能看到 1 条真实 TCP 长连接。
- 根因一:`POST /api/admin/channels/:id/copy` 会继承源通道 `status=active`,复制后的通道创建完成后立即参与 Gateway 连接流程,和“复制只是拷贝配置,不应自动上线”的产品预期不符。
- 根因二:Gateway `/connections/connect` 之前只做一次性 `DialCMPP` 探测,探测成功后就把 `connected/currentConnections=desiredConnections` 回写给 NestJS;该探测连接随后立即断开,导致页面状态与真实上游连接池不一致。
- 已修复:
- 通道复制后统一保存为 `disabled`,复制日志补充 `sourceStatus``copiedStatus`,避免 active 通道副本自动占用上游连接。
- Gateway `ConnectChannel` 改为直接建立/复用真实上游连接池,并由连接池回写 `connected/failed/disconnected``currentConnections`、最近错误和断开时间;连接丢失时状态随真实连接数变化更新。
- 测试口径同步:
- `TC-ADMIN-003` 增加“连接状态必须来自真实上游连接池回写”的要求。
- `TC-ADMIN-016` 明确复制 active 通道后副本默认 `disabled`,且不会立即触发上游真实连接。
- 已执行:`npm --prefix api test -- channels.service.spec.ts --runInBand``npm --prefix api run build``go test ./internal/control ./internal/upstream``go build -o ..\\dist\\cmpp-gateway .\\cmd\\gateway`
## 2026-07-09 线上通道 CMPP 版本修复
- 线上生产验证发现 3 个赛邮行业通道配置均指向 `121.40.172.212:7890`,其中 2 个已触发 Gateway 真实连接并失败,`CmppConnectionState.lastError``packetWriter.ReadBytes error: ReadBytes reads 14 bytes, not equal to 16 we expected`
@@ -468,6 +481,7 @@ GET /api/admin/system-logs?page=1&pageSize=2
- 新增用户登录字段和 fail2ban 持久化字段:`email``phone``failedLoginCount``lockedUntil``lastLoginAt``deletedAt`
- 登录入口拆分为 `/client/login``/admin/login`,两端均调用真实验证码和登录 API。
- 用户登录入口和用户表单统一文案为“用户名/登录账号”,提示可用用户名、邮箱或手机号登录。
- 运营端登录仅允许 `platform_admin`;客户端登录仅允许已关联企业的 `enterprise_admin`
- 运营端用户管理接入真实 `/api/admin/users`,支持平台管理员和企业管理员的新增、编辑、启用/禁用、删除、改密;企业管理员必须关联企业。
- 客户端用户管理接入真实 `/api/client/users`,所有操作继承当前登录企业 `tenantId`