Files
lislgosms/docs/system-functional-test-cases.md
T

5065 lines
445 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.
# CMPP 短信平台第一版系统功能测试用例
## 1. 用例说明
本文档补充第一版系统功能测试用例,面向验收测试、人工回归测试和后续 E2E 自动化改造。系统功能用例必须依赖真实 NestJS API、Prisma/PostgreSQL、Redis/BullMQ、MinIO 或对应本地服务完成闭环;用例不依赖真实运营商 CMPP 网关,Gateway 场景使用 Go Gateway、本地 SMSC 模拟器、队列契约和连接状态回写 API 验证。
优先级定义:
- P0:第一版上线阻断项,必须通过。
- P1:核心功能回归项,建议每轮发布通过。
- P2:增强/边界项,可按时间和环境选择执行。
## 2. 测试数据基线
| 数据类型 | 建议数据 |
| --- | --- |
| 租户 | `tenant-a` 正常企业,`tenant-b` 用于租户隔离验证。 |
| 用户 | 客户端企业管理员、客户端普通用户、运营管理员、运营审核员。 |
| 短信应用 | `app-a`,状态 active,日限额开启,模板不匹配策略分别准备 reject/manual_review/allow 三组;另准备普通队列应用 `app-normal` 和优先队列应用 `app-priority`。 |
| 签名 | `【测试签名】`,审核通过且报备通过;另准备待审核、驳回、报备失败签名。 |
| 模板 | 验证码模板 `验证码为 ${code}`,营销模板 `尊敬的${name},优惠活动开始`,分别准备草稿、待审核、通过、驳回。 |
| 通道 | active CMPP 通道、disabled 通道、备用通道;通道组包含主备优先级。 |
| 号码 | 合法号码、重复号码、非法号码、企业黑名单号码、全局黑名单号码。 |
| 账户 | 现金余额与授信额度组合后的和为正数、0、负数;授信额度覆盖正数、负数和 0;不配置套餐余量。 |
| 企业认证 | 未认证、待审核、已通过、已驳回四类企业认证资料。 |
## 2.1 2026-07-15 运营端细节回归
| 用例编号 | 优先级 | 验证内容 | 预期结果 |
| --- | --- | --- | --- |
| TC-ADMIN-UI-0715-01 | P1 | 新建/编辑企业应用并留空或修改 CMPP 账号 | 企业代码控件不可编辑且实时跟随账号;API 最终持久化二者相等;超过每任务号码上限时整个任务被拒绝并有拆分说明。 |
| TC-ADMIN-DICT-0715-02 | P1 | 删除手机号段;分别删除引用数为 0 和大于 0 的报备字段 | 号段从 PostgreSQL 删除;字段列表显示真实使用通道数,未引用字段删除成功,已引用字段按钮禁用且直接调用 DELETE 也返回 400。 |
| TC-ADMIN-CMPP-0715-03 | P1 | 建立连接后主动断开,再制造心跳超时 | 连接详情只显示 active 连接;断开/超时行从 `CmppDownstreamConnection` 删除,操作日志仍保留断开审计。 |
| TC-ADMIN-AUDIT-0715-04 | P0 | 不勾选、勾选部分任务分别点击批量操作 | 未勾选时按钮禁用;只通过已选任务,未选任务状态不变;确认弹窗数量等于选择数。 |
| TC-ADMIN-DOWNSTREAM-0715-05 | P1 | 选择下游投递创建日期范围 | 列表及页面 Dashboard 使用同一日期范围查询真实数据库,范围外记录不计入。 |
| TC-ADMIN-TEMPLATE-0715-06 | P1 | 将光标置于模板中间并插入推荐/自定义变量 | 变量在光标或选区处插入,原选区被替换,光标停在变量后;运营端和客户端一致。 |
| TC-ADMIN-RECORD-0715-07 | P1 | 查看桌面/窄屏短信记录及失败详情 | 卡片不产生页面横向滚动,信息分组清晰;失败原因独立突出;详情仍读取真实 submit、receipt 和分片审计 API。 |
| TC-ADMIN-MISC-0715-08 | P2 | 查看签名引流信息、零待审核通知和充值弹窗 | 使用“引流信息”标题且无提交时间;0 为黑字灰底;充值弹窗无操作人字段。 |
| TC-ADMIN-NOTICE-0715-09 | P1 | 制造下游投递告警后打开右上角“待审核任务” | 待审核总数和菜单仅包含五类真实审核任务,不出现“下游投递告警”;运营看板和下游投递页仍展示下游告警。 |
| TC-ADMIN-CMPP-0715-10 | P0 | 为企业应用配置扩展码 `0001`,切换接入号填充并配置前缀 `00` | 开关关闭时前缀不显示且不可编辑;开启后才显示;API/PostgreSQL 保存扩展码、开关、前缀及客户侧 `Src_Id=000001`,上游 Submit 使用“通道基础号 + 0001”,不携带 `00`。 |
| 客户 | 正常客户、停用客户、欠费客户、未认证客户、跨租户客户、客户联系人和开票资料。 |
| 导入文件 | UTF-8 CSV、GBK CSV、TXT、超 20 MB 文件、含空行/重复/非法号码/非法字符文件。 |
| 非法内容 | 控制字符、emoji、换行、不可见字符、超长变量、签名外置内容、敏感词内容。 |
## 3. 业务闭环覆盖矩阵
| 业务闭环 | 必须验证 |
| --- | --- |
| 企业认证闭环 | 客户提交资料、运营审核、客户查看状态、驳回重提、通过后才允许使用受限发送能力、日志可追溯。 |
| 客户管理闭环 | 客户创建、编辑、启停、认证、额度/余额、客户下应用/签名/模板/发送记录联动、租户隔离、日志可追溯。 |
| 短信应用闭环 | 创建、启停、删除、密钥重置、IP 白名单、模板不匹配策略、变更后对发送实时生效、日志可追溯。 |
| 应用队列等级闭环 | 客户端和运营端创建/编辑应用时保存普通/优先队列配置;发送入队按应用队列等级分流;优先队列在不绕过业务校验和通道限速的前提下插队消费。 |
| 签名闭环 | 创建、材料、审核、删除、报备状态变化、发送可用性校验、历史任务不受错误覆盖、日志可追溯。 |
| 引流信息闭环 | 字段配置、客户填写、删除字段或删除客户引流信息、报备材料影响、发送阻断或审核原因可见。 |
| 模板闭环 | 单变量、多变量、审核、删除、变量缺失/多传/格式异常、计费预估、发送可用性校验。 |
| 号码导入闭环 | 文件上传、解析、去重、非法号码、黑名单、导入结果展示、生成任务、生成手机号记录。 |
| 发送闭环 | 立即发送、定时发送、到点触发、入队、submit、回执、上行、任务进度、发送详情、trace、对账。 |
| CMPP 连接闭环 | 通道连接状态、登录认证、active test、断线重连、连接异常对路由/发送影响、状态监控和日志告警。 |
| Dashboard 闭环 | 客户端/运营端指标口径、数据范围、时间筛选、状态统计、账务统计、通道连接指标和明细跳转一致。 |
| 内容校验闭环 | 非法字符展示、敏感词、控制字符、内容清洗或拒绝、计费不被非法字符干扰、错误原因可见。 |
| 计费闭环 | 预估、余额校验、冻结、扣费、释放、退款、短信计费记录、充值记录、对账。账单流水页面和公开交易查询 API 暂不纳入第一版验收。 |
| 系统日志闭环 | 登录、创建、修改、删除、审核、导入导出、密钥重置、发送、报备、账务动作均可查询和定位操作者。 |
## 4. 客户端功能用例
### TC-CLIENT-001 登录与租户隔离
- 优先级:P0
- 前置条件:存在 `tenant-a``tenant-b`,两个租户各有发送任务和充值/计费记录。
- 步骤:
1. 使用 `tenant-a` 企业管理员登录客户端。
2. 打开工作台、批量任务、发送详情、上行短信、账户余额。
3. 使用查询条件搜索 `tenant-b` 的任务编号或手机号。
- 预期结果:
- 登录成功,返回当前租户上下文。
- 所有列表只展示 `tenant-a` 数据。
- 查询 `tenant-b` 数据无结果或返回无权限。
### TC-CLIENT-002 创建短信应用并重置密钥
- 优先级:P1
- 前置条件:企业管理员已登录。
- 步骤:
1. 创建短信应用,填写名称、场景、回调地址、IP 白名单、日限额,并选择发送队列等级。
2. 查询应用列表和详情。
3. 执行应用密钥重置。
- 预期结果:
- 应用创建成功,状态为 active。
- IP 白名单、日限额、模板不匹配策略和发送队列等级保存正确,刷新后仍来自真实 API/数据库。
- 密钥重置后旧密钥不可见,新密钥或密钥摘要更新。
- 生成操作日志。
### TC-CLIENT-003 签名创建、材料上传与提交审核
- 优先级:P0
- 前置条件:MinIO 或等价对象存储测试服务可用;如不可用,本用例标记为阻塞或未执行,不得用文件服务 mock 作为验收通过依据。
- 步骤:
1. 创建短信签名,填写完整中文黑括号名称 `【测试签名】`、用途、引流信息。
2. 上传或登记签名证明材料。
3. 提交审核。
4. 打开签名列表和详情。
- 预期结果:
- 签名初始为 draft。
- 材料与签名关联成功。
- 提交后签名状态变为 pending。
- 生成审核记录。
- PostgreSQL保存完整名称`【测试签名】`,客户端和运营端新增、编辑输入框及列表、详情均显示恰好一层黑括号。
### TC-CLIENT-003B 签名黑括号格式前后端强制校验
- 优先级:P0
- 前置条件:存在可创建签名的企业和应用。
- 步骤:
1. 分别在客户端和运营端新增、编辑签名,输入`测试签名``[测试签名]``【【测试签名】】``【 】``【测试签名】附加文本`
2. 绕过页面直接调用真实新增、编辑API提交相同非法名称。
3. 输入合法完整名称`【测试签名】`并保存,刷新列表、详情、审核和报备页面。
4. 选择该签名生成模板内容和发送预览。
- 预期结果:
- 所有非法格式在前端不可提交,直接调用API也返回400及可行动错误,不写入`SmsSignature`
- 合法名称以完整格式写入PostgreSQL;新增、编辑和所有展示位置均为`【测试签名】`
- 模板与发送预览只包含一层签名,不出现`【【测试签名】】`
### TC-CLIENT-003C 签名空白与不可见字符前后端强制校验
- 优先级:P0
- 前置条件:存在可创建、编辑签名的企业和应用。
- 步骤:
1. 分别在客户端和运营端新增、编辑签名,尝试键入或粘贴包含普通空格、换行、制表符、不换行空格、零宽空格、BOM和变体选择符的名称。
2. 观察受控输入框、错误提示和提交按钮。
3. 绕过页面直接调用真实新增、编辑API提交相同非法名称。
4. 输入不含空白或不可见字符的合法名称`【测试签名】`并保存。
- 预期结果:
- 非法字符不进入客户端或运营端受控输入值,页面立即提示且不能提交;已有合法输入不因一次非法粘贴被覆盖。
- 直接调用API返回400及可行动错误,不写入或更新`SmsSignature`,不能通过前端绕过。
- 合法名称可正常保存,刷新后仍来自真实PostgreSQL记录。
### TC-CLIENT-003A 签名与引流信息工作台及通道信息隔离
- 优先级:P0
- 前置条件:真实 PostgreSQL 中存在多个审核状态的企业签名、至少一个已通过签名包含引流信息;应用的生效路由配置了通道级动态资料字段。
- 步骤:
1. 企业客户打开“签名与引流信息”,核对顶部全部、审核中、通过、需修改数量与真实 API/数据库。
2. 按签名关键字、所属应用、审核状态筛选,并展开签名查看关联引流信息。
3. 新增签名并填写动态审核资料;对可编辑签名和引流信息执行修改,对记录执行删除确认。
4. 检查 `/client/signatures``/client/signatures-workspace``/client/applications/:id/report-fields` 响应和页面文本。
- 预期结果:
- 列表、统计、筛选、审核状态、资料数量、修改说明和引流信息均来自真实 NestJS API 与 PostgreSQL,刷新后保持一致。
- 客户端只展示“待提交、资料审核中、审核通过、需修改”等客户状态;签名审核通过后才可新增引流信息,待审记录不可重复编辑。
- 页面及客户端 API 均不包含通道 ID/编码/名称、通道组、路由、运营商报备汇总、报备任务或内部资料要求快照;动态字段仍按真实应用路由合并并由 API 校验必填值。
- 删除操作经过确认并写入真实状态,其他企业的签名无法读取、修改或删除。
### TC-CLIENT-004 模板变量识别与提交审核
- 优先级:P0
- 前置条件:存在 active 应用和可用签名。
- 步骤:
1. 选择签名 `【测试签名】`,确认模板内容自动出现该前缀,再填写正文 `验证码为 ${code}`
2. 切换到另一个签名,确认只替换原签名前缀且不重复追加。
3. 保存后查看变量列表和完整内容计费条数。
4. 分别用正确内容、缺少签名和错误签名前缀调用真实模板 API。
5. 提交模板审核。
- 预期结果:
- 客户端和运营端模板表单均提示模板必须包含签名;选择签名自动填入完整 `【签名】`,切换时保留正文并替换前缀。
- 系统识别变量 `code`
- 字符数和计费条数包含签名,按 70/67 字规则预估。
- NestJS 拒绝未选择签名、签名不属于当前企业/应用或内容未以所选签名开头的请求。
- 提交后模板状态为 pending。
- 生成审核记录。
### TC-CLIENT-005 客户端发送任务创建成功
- 优先级:P0
- 前置条件:应用、签名、模板审核通过;签名报备通过;账户余额充足;通道可用。
- 步骤:
1. 选择应用、签名、模板。
2. 填写模板变量。
3. 输入 3 个合法手机号。
4. 提交立即发送。
5. 查看批量任务详情和发送明细。
- 预期结果:
- 返回批量任务编号。
- 批量任务 `sourceType=client`
- 手机号维度生成 3 条短信记录。
- 任务进入 queued/sending/completed 之一的正常流转状态。
- 发送明细可按手机号查询。
### TC-CLIENT-006 手机号去重与非法号码提示
- 优先级:P0
- 前置条件:存在通过审核的发送资源。
- 步骤:
1. 输入合法号码 A、合法号码 A、非法号码 X、合法号码 B。
2. 提交发送。
3. 查看预审结果和任务明细。
- 预期结果:
- 重复号码被识别,重复率写入风控指标。
- 非法号码被识别,非法率写入风控指标。
- 如命中拒绝阈值,任务被 rejected,返回可读拒绝原因。
- 如未命中拒绝阈值,仅合法且去重后的号码进入后续发送。
### TC-CLIENT-007 账户余额不足禁止发送
- 优先级:P0
- 前置条件:企业现金余额小于预估发送费用。
- 步骤:
1. 使用长内容和多个手机号生成较高预估费用。
2. 提交发送。
3. 查看账单流水。
- 预期结果:
- 发送前账户校验失败。
- 不创建可发送状态的批量任务,或任务进入 rejected。
- 不生成冻结/扣费流水。
- 客户端展示余额不足原因。
### TC-CLIENT-008 客户端账单流水查询
- 优先级:P1
- 前置条件:存在充值、冻结、扣费、退款、释放流水。
- 步骤:
1. 打开账单流水。
2. 按时间、交易类型、任务编号查询。
3. 查看单条流水关联对象。
- 预期结果:
- 流水类型和金额方向正确。
- 任务、短信记录或充值订单可追溯。
- 客户端只展示本租户流水。
### TC-CLIENT-009 客户端上行短信查询
- 优先级:P1
- 前置条件:已通过 Gateway 模拟器写入上行事件。
- 步骤:
1. 打开上行短信页面。
2. 按手机号和时间查询。
3. 查看上行关联下发记录。
- 预期结果:
- 展示上行内容、接入号、接收时间、上行网关消息 ID、匹配状态和匹配说明。
- 后端已通过接入号或手机号时间窗匹配时,即使上行事件没有关联平台 `messageId`,详情仍直接展示响应中嵌入的真实下发记录及其平台 `messageId`
- 上行网关消息 ID 与关联平台消息 ID 分栏展示,不把供应商 MO `Msg_Id` 误作历史 MT Submit 消息 ID。
- 未匹配或多候选上行仍可查询,并显示真实状态;多候选提示联系运营人员认领。
### TC-CLIENT-010 用户管理与企业管理员唯一性
- 优先级:P1
- 前置条件:企业管理员已登录,租户下已有一个企业管理员和一个普通用户。
- 步骤:
1. 打开客户端用户管理页面。
2. 新增普通用户并保存。
3. 编辑普通用户,尝试将角色改为企业管理员。
4. 删除普通用户并确认。
- 预期结果:
- 新增、编辑、删除均调用真实客户端用户 API。
- 第一版同一租户只允许一个企业管理员;重复设置时返回明确错误或前端禁用该角色选项。
- 删除按钮使用统一危险操作样式,删除前二次确认。
- 用户创建、编辑、删除均写入系统日志。
### TC-CLIENT-011 头像菜单、密码修改与系统日志分页
- 优先级:P1
- 前置条件:客户端用户已登录,系统日志超过一页。
- 步骤:
1. 点击右上角用户头像。
2. 执行修改密码并重新登录。
3. 再次点击头像执行退出登录。
4. 打开客户端系统日志,切换分页并查看长详情。
- 预期结果:
- 头像下拉展示退出登录、修改密码,不展示独立账号设置菜单。
- 修改密码调用真实 API,旧密码失效,新密码可登录。
- 退出登录清理会话并写日志。
- 系统日志分页来自真实 API,长详情使用详情卡或弹窗展示,不被表格窄列截断。
## 5. 运营端功能用例
### TC-ADMIN-001 签名审核通过
- 优先级:P0
- 前置条件:客户端已提交待审核签名。
- 步骤:
1. 运营审核员打开签名审核列表。
2. 查看签名材料和引流信息。
3. 点击通过。
- 预期结果:
- 签名状态变为 approved。
- 写入审核记录,包含审核人、动作、时间。
- 客户端签名列表同步展示通过状态。
### TC-ADMIN-002 模板审核驳回
- 优先级:P0
- 前置条件:客户端已提交待审核模板。
- 步骤:
1. 运营审核员打开模板审核详情。
2. 填写驳回原因。
3. 点击驳回。
- 预期结果:
- 模板状态变为 rejected。
- 驳回原因保存并返回客户端。
- 被驳回模板不能用于发送。
### TC-ADMIN-001A 运营端新建签名自动通过
- 优先级:P0
- 前置条件:运营管理员已登录,目标企业和应用存在。
- 步骤:
1. 在运营端企业签名页新建签名并保存。
2. 查询签名列表、签名审核页和审核记录。
- 预期结果:
- `SmsSignature.auditStatus=approved`,不停留在 draft。
- 生成 `admin_create_approved` 审核记录。
- 客户端自行新建签名仍按 draft → pending → approved/rejected 流转。
### TC-ADMIN-003 通道创建与启停
- 优先级:P0
- 前置条件:运营管理员已登录。
- 步骤:
1. 创建 CMPP 通道,填写网关地址、端口、账号、密码密文、接入号、CMPP 版本、限速、期望连接数和提交窗口。
2. 查询通道列表。
3. 在在线通道上打开“短信测试”,填写真实手机号、短信内容和可选接入号后发送测试短信。
4. 查询短信记录和提交记录。
5. 停用通道后创建发送任务。
- 预期结果:
- 通道协议默认为 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 返回明确错误,不能只在前端假提示成功。
- 停用通道不会被路由选中。
### TC-ADMIN-004 通道组与路由规则
- 优先级:P0
- 前置条件:存在移动、联通、电信专属通道和三网通道,存在主通道和备用通道。
- 步骤:
1. 创建移动通道组、联通通道组、电信通道组。
2. 尝试创建三网通道组。
3. 在移动通道组中添加 mobile item,引用移动通道或三网通道。
4. 尝试在移动通道组中添加 unicom item 或引用电信专属通道。
5. 尝试在移动通道组中添加山东省网 item,但引用发送地区为河南的通道。
6. 在同一通道组中为山东省重复添加第二个省网通道。
7. 添加主通道优先级 10、备用全国通道优先级 20,并尝试添加另一个优先级 20 的全国通道。
8. 配置补发时间上限为 12 小时 30 分钟并保存,再重新打开编辑页。
9. 创建租户/应用维度路由规则。
10. 创建发送任务触发送链路。
- 预期结果:
- 只能创建 mobile/unicom/telecom 通道组,三网通道组被拒绝。
- 通道组明细 carrier 必须等于通道组运营商。
- 通道组明细引用通道时必须满足通道本体能力兼容:移动组只允许 mobile/all,联通组只允许 unicom/all,电信组只允许 telecom/all。
- 省网 item 的省份必须与通道发送地区一致。
- 同一通道组内同一省份只能配置一个通道,全国通道可配置多个但优先级不能重复。
- 省网通道和全国通道在添加/编辑页以表格展示,通道状态文案为“链接正常/通道停用”,且“链接正常”来自真实 CMPP 连接状态。
- 补发时间上限按分钟级真实保存,12 小时 30 分钟回填为 12 小时 30 分钟。
- 路由优先命中租户/应用规则。
- 主通道 active 时选择主通道。
- 主通道 disabled 时选择备用 active 通道。
- 通道组不支持权重分流,同优先级全国通道配置被拒绝。
### TC-ADMIN-005 签名报备任务生成与导出
- 优先级:P0
- 前置条件:签名审核通过,通道配置了报备字段。
- 步骤:
1. 为签名登记通道报备材料。
2. 生成报备任务。
3. 执行报备资料导出。
4. 查看报备记录。
- 预期结果:
- 生成 pending 报备任务。
- 导出后任务状态变为 exporting。
- 生成导出文件记录。
- 报备记录包含 create/export 两个动作。
### TC-ADMIN-005A 报备字段库到企业资料动态继承
- 优先级:P0
- 前置条件:存在两个 active 通道、一个包含这两个通道的通道组,以及绑定该通道组的企业应用。
- 步骤:
1. 在报备字段库创建图片字段“营业执照”和字符串字段“网站主体”,并直接调用 API 尝试创建整数、网址、电话、日期等其他类型。
2. 将营业执照配置为通用签名报备必填,将网站主体配置为通用引流信息报备必填;再在通道一选择同一个营业执照字段配置为签名报备,在通道二配置其他通道专用字段。
3. 分别打开绑定应用和不绑定应用的企业签名添加/编辑弹窗,以及对应引流信息添加/编辑弹窗;同时在客户端执行新增签名和新增/修改引流信息。
4. 分别尝试缺少必填值保存,再补齐文件和值后保存。
5. 查询 PostgreSQL 中签名、签名报备材料和引流报备材料记录;删除该引流项后再次查询。
- 预期结果:
- 通用字段和通道字段按字段库 ID 合并去重;营业执照在所有签名添加/编辑表单中出现,网站主体在所有引流信息添加/编辑表单中出现,不绑定应用也不能绕过通用必填校验。
- 企业签名弹窗不再展示固定签名依据、资质凭证、企业信息和责任人信息;资料全部来自动态配置。
- 通用字段仍可在通道报备字段选择器中选中;删除通用配置不删除字段定义和历史资料,字段仍被通道或通用配置引用时禁止删除字段定义。
### TC-ADMIN-005B 引流信息按通道报备及三入口同步
- 优先级:P0
- 前置条件:企业应用已绑定通道组,至少一个目标通道配置 `drainage``both` 报备字段。
- 步骤:
1. 客户端在已审核通过的企业签名中新增引流信息,填写动态字段并提交。
2. 查询 `SmsDrainageInfo``DrainageReportMaterial``ChannelSignatureReportTask(reportType=drainage)`,并尝试直接调用状态变更接口。
3. 在运营端“引流信息审核”查看完整资料并通过,再次查询上述表和报备记录。
4. 分别从企业签名、通道报备详情、报备任务页修改同一引流项在同一通道的状态,并在报备记录页按引流信息筛选。
5. 客户端修改已通过的引流信息,确认任务冻结后由运营再次审核通过;随后导出任务并导入回执。
6. 对另一条待审引流信息执行带原因驳回,客户端查看驳回原因。
- 预期结果:
- 新建/修改均写独立 `SmsDrainageInfo``AuditRecord(targetType=sms_drainage_info)`;客户端提交为 pending,运营端列表和待审数量同步增加。
- 审核通过前没有新的可处理通道任务或可导出材料,直接修改通道报备状态返回 400;审核通过后每个“签名 + 引流项 + 通道”生成独立 pending 任务和 `audit_approved_create/reset` 记录。
- 已通过引流信息再次修改后,旧材料被停用、已有任务变为 waiting_review;再次审核通过后材料按新值重建且任务恢复 pending,历史记录保留。
- 三个入口的状态和通过数/总数一致,修改写入 `ChannelSignatureReportRecord.sourceEntry`;报备记录分别显示“企业签名修改”“通道信息修改”“报备任务修改”。
- 引流任务不参与 `SmsSignature.reportStatus` 聚合,也不能被短信发送选路误当为签名报备通过。
- 字段库页面只提供字符串、图片、文件三种类型;API 对其他类型返回 400,历史其他类型迁移为字符串。
- 缺少必填资料时前端禁止提交;直接调用 API 也返回 400,不能绕过页面保存不完整资料。
- 文件通过真实对象存储上传;动态值保存在 `SmsDrainageInfo.reportValues`,审核通过后按来源通道分别写入规范化报备材料表。
- 报备任务与报备记录页可区分签名/引流信息并显示真实通道名称、签名内容、站点、地址、备注和所属签名;动作、状态变化显示中文;删除引流项后任务进入 abandoned,不再可导出或改状态,历史记录仍可追溯。
### TC-ADMIN-005C 运营列表独立组合搜索与表头对齐
- 优先级:P1
- 前置条件:存在不同企业、应用、签名、引流信息、模板、黑名单和启停状态的数据。
- 步骤:
1. 在企业模板管理分别填写企业名称、企业应用、模板名称、模板内容,再组合查询。
2. 在企业签名管理分别填写企业名称、企业应用、签名名称/用途、引流信息;使用引流站点或 URL 查询。
3. 在企业应用管理组合企业名称、应用名称、状态查询。
4. 在企业黑名单组合企业名称、应用名称、手机号、入库原因、状态查询。
5. 查看充值记录和短信记录表头。
- 预期结果:
- 每个查询条件作为独立 API 参数进入 NestJS,并由 Prisma 对应字段执行 AND 组合过滤,不拼成一个模糊关键字。
- 引流信息命中后只展示包含该命中项的签名分组,并自动展开匹配的引流信息。
- 重置恢复全部数据;列表仍来自真实 PostgreSQL。
- 充值记录和短信记录表头全部靠左对齐。
### TC-ADMIN-005B 企业签名、通道详情和报备任务状态一致性
- 优先级:P0
- 前置条件:企业应用绑定移动、联通通道组,移动组含两个通道,联通组含一个通道;企业签名已存在。
- 步骤:
1. 在企业签名页打开“报备状态”,确认显示三个具体目标通道,将移动通道一标记通过。
2. 在移动通道二的通道报备详情中标记报备通过。
3. 在报备任务页将联通任务标记报备中,再通过回执导入改为通过。
4. 每步后分别刷新企业签名、通道详情和报备任务页面,并查询数据库任务、记录和签名状态。
5. 向移动通道组新增一个通道但不生成任务,再刷新企业签名列表。
- 预期结果:
- 三个入口操作同一条 `ChannelSignatureReportTask`;不存在的目标通道任务由统一接口真实创建。
- 每次变化写入 `ChannelSignatureReportRecord`,包含前后状态、原因、操作人和时间。
- 两个移动通道均通过后移动汇总为通过;联通处理中时签名全局状态不是通过;联通回执通过后三网目标通道全部通过,签名全局状态为 approved。
- 新增移动通道后移动汇总立即变为部分通过/报备中,分母包含新增通道,不能继续误显示全部通过。
- 发送时仍校验最终路由通道对应任务为 approved,不以企业签名列表汇总标签代替通道级校验。
### TC-ADMIN-005C 部分通道报备通过时的发送路由
- 优先级:P0
- 前置条件:签名和模板审核通过;应用通道组包含主、备用两个在线通道;签名全局报备状态为 reporting,主通道任务 pending,备用通道任务 approved。
- 步骤:
1. 使用该签名发送一条短信。
2. 查看短信记录、路由通道和 Gateway SubmitCommand。
3. 将备用通道任务也改为 pending,再次发送。
4. 将主通道任务改为 approved,模拟主通道提交失败并触发补发。
- 预期结果:
- 第一次发送不因全局 reportStatus=reporting 被提前拒绝,只选择已报备通过的备用通道。
- 两个候选通道均未通过时发送失败,原因明确为无已报备通过且在线的可用通道,不进入 Gateway。
- 补发重新按新候选通道的任务状态筛选,不能切换到未报备通过通道。
- 最终提交前仍执行通道级二次校验,避免路由后状态变化导致错误发送。
### TC-ADMIN-006 报备回执导入通过
- 优先级:P0
- 前置条件:存在 exporting 报备任务。
- 步骤:
1. 导入全部成功的通道回执。
2. 查看报备任务和签名状态。
- 预期结果:
- 导入批次记录 rowCount、successCount、failedCount。
- 报备任务状态变为 approved。
- 签名 `reportStatus` 同步为 approved。
- 报备记录包含 receipt_import。
- 发送前仅允许使用最终选中通道上报备状态为 approved 的签名。
### TC-ADMIN-007 报备回执导入失败
- 优先级:P1
- 前置条件:存在 exporting 报备任务。
- 步骤:
1. 导入存在失败行的通道回执。
2. 填写失败原因。
3. 查看签名报备状态。
- 预期结果:
- 报备任务状态变为 rejected 或 partial_approved。
- 失败原因可查询。
- 签名报备状态同步为对应失败状态。
### TC-ADMIN-008 风控规则配置覆盖默认规则
- 优先级:P0
- 前置条件:存在平台默认风控规则。
- 步骤:
1.`tenant-a` 创建同 code 的租户级规则,阈值低于平台默认值。
2. 提交达到租户阈值但未达到平台阈值的任务。
3. 查看风控命中记录。
- 预期结果:
- 生效规则使用租户级配置。
- 风控命中记录写入租户规则 id、规则编号、阈值、实际值、处理动作。
- 运营端审核页面展示命中原因。
### TC-ADMIN-009 短信审核通过后入队
- 优先级:P0
- 前置条件:发送任务因风控进入 pending_review。
- 步骤:
1. 运营审核员打开短信审核详情。
2. 查看号码量、内容、计费条数、命中规则。
3. 点击通过。
4. 查看发送队列和任务状态。
- 预期结果:
- 审核状态变为 approved。
- 任务进入 queued/sending。
- 生成发送队列消息。
- 审核动作写入日志。
### TC-ADMIN-010 短信审核驳回
- 优先级:P0
- 前置条件:发送任务因风控进入 pending_review。
- 步骤:
1. 运营审核员填写驳回原因。
2. 点击驳回。
3. 客户端查看任务状态。
- 预期结果:
- 任务状态变为 rejected。
- 不再进入发送队列。
- 客户端可见驳回原因。
### TC-ADMIN-010A 短信审核批量驳回
- 优先级:P0
- 前置条件:至少存在两条因风控进入 `pending_review` 的真实发送任务。
- 步骤:
1. 在短信审核列表勾选两条待审核任务。
2. 点击“驳回已选”,填写统一驳回原因并确认。
3. 刷新审核列表和客户端任务状态。
- 预期结果:
- 前端只提交已选任务 id 和非空原因到真实 `/admin/risk-review/tasks/batch/reject` API。
- 两条任务均持久化为 `rejected`,保留相同驳回原因和审核时间,并逐项执行发送链路拒绝处理。
- 未勾选任务不受影响;空选择、空原因和超过单批上限的请求被拒绝。
### TC-ADMIN-011 运营看板与监控
- 优先级:P1
- 前置条件:存在 delivered、failed、unknown、timeout 多种短信记录。
- 步骤:
1. 打开运营看板。
2. 打开发送监控。
3. 按租户和通道过滤。
- 预期结果:
- 看板展示任务数、发送状态分布、上行数、账务聚合,不重复展示通道连接或通道运行数据。
- 看板按当天真实短信记录展示“不含引流/含引流”两组签名统计;每行包含签名、企业、发送总数、成功、未知、失败、成功率和平均到达时长。
- 监控展示最近发送、最近回执、最近上行。
- 过滤条件生效。
### TC-ADMIN-011A 通道今日质量与日期通道占比
- 优先级:P1
- 前置条件:北京时间当天至少两个通道存在 accepted Submit,其中包含成功、失败和未回执记录;另一个历史日期有不同通道分布。
- 步骤:
1. 打开运营端通道列表。
2. 对照 `SmsSubmitRecord``SmsReceiptRecord` 核验“今日总数/今日发送质量”。
3. 打开数据统计,确认默认日期后切换到准备好的历史日期并查询。
- 预期结果:
- 通道列表按真实提交通道展示当天总数、成功、未知、失败及比例,不再全部为前端固定 0。
- 通道占比默认日期为北京时间当天;切换日期后重新请求该日期数据,图例展示真实通道名称且占比随数据变化。
### TC-ADMIN-012 发送链路 Trace
- 优先级:P0
- 前置条件:存在一条完成 submit result、receipt、billing、uplink 的短信。
- 步骤:
1. 在运营端按 messageId 查询 trace。
2. 查看批量任务、API 请求、提交记录、回执记录、计费记录、上行记录。
- 预期结果:
- trace 返回完整链路。
- submitId、sequenceId、gatewayMessageId 可追踪。
- 计费记录和短信记录金额一致。
### TC-ADMIN-013 对账 reconciliation
- 优先级:P0
- 前置条件:存在同一 taskId 下的短信记录、短信计费记录和账户流水。
- 步骤:
1. 按租户和 taskId 查询对账。
2. 对比短信记录金额、计费记录金额、账户流水金额。
- 预期结果:
- 无异常时 diff 为 0。
- 若人为构造缺失流水,diff 展示差额。
- 查询结果支持定位 taskId/messageId。
### TC-ADMIN-014 短信模板审核搜索与审核
- 优先级:P1
- 前置条件:存在不同客户、应用、内容、状态的短信模板审核记录。
- 步骤:
1. 打开运营端短信模板审核页面。
2. 分别按客户、应用、模板内容、审核编号、审核状态搜索。
3. 对一条待审核模板执行通过。
4. 对另一条待审核模板执行驳回并填写原因。
- 预期结果:
- 搜索条件由真实后端 API 处理,结果只包含匹配记录。
- 运营端企业模板管理新增的短信模板在审核页状态直接为 approved,不进入待审核。
- 通过后模板状态变为 approved,驳回后模板状态变为 rejected。
- 审核记录、操作者、审核时间和驳回原因可追溯。
- 客户端模板列表同步展示最新状态。
### TC-ADMIN-015 企业认证详情与审核闭环
- 优先级:P1
- 前置条件:客户已提交企业认证资料,包含主体信息、营业执照、对公账户验证和联系人信息。
- 步骤:
1. 打开运营端企业认证审核列表并按客户名称搜索。
2. 进入认证详情,核对统一社会信用代码、法定代表人、注册地址、营业执照附件、银行验证资料、联系人、提交时间。
3. 审核通过一条认证。
4. 驳回另一条认证并填写原因,客户修改资料后重新提交。
- 预期结果:
- 详情页展示客户真实提交资料,不使用前端静态内容。
- 通过后认证记录和租户认证状态同步为 approved。
- 驳回后客户可见驳回原因,可重新提交。
- 审核动作写入系统日志,并影响立即发送和定时到点发送准入。
### TC-ADMIN-016 通道复制真实闭环
- 优先级:P1
- 前置条件:存在一个 active CMPP 通道,已配置 CMPP 参数、通道报备字段、签名/引流报备材料和个性化字段。
- 步骤:
1. 在通道列表点击复制通道并确认。
2. 查询新通道详情。
3. 打开新通道报备详情。
4. 查询操作日志。
- 预期结果:
- 后端创建新通道,新通道 id/code 与源通道不同,名称默认追加“副本”。
- 通道配置、CMPP 参数、报备字段、签名/引流报备材料和个性化字段与源通道一致。
- 若源通道为 active,新通道默认保存为 disabled,且不会立即触发上游真实连接。
- 复制动作写入系统日志。
- 复制后新通道可继续编辑、启停、删除,不影响源通道。
### TC-ADMIN-017 通道启停、删除确认与软删除
- 优先级:P1
- 前置条件:存在 active 通道,且通道关联历史发送、报备和日志记录。
- 步骤:
1. 点击停用通道,取消确认。
2. 再次点击停用并确认。
3. 点击启用并确认。
4. 点击删除并确认。
5. 查询历史发送、报备和日志。
- 预期结果:
- 取消确认不改变数据库状态。
- 启用、停用、删除均调用真实后端 API 并写系统日志。
- 删除采用软删除或停用归档,不破坏历史发送、报备、日志外键。
- 软删除后的通道不再参与路由和新任务发送。
### TC-ADMIN-018 企业应用 CMPP 连接数、连接详情与参数复制
- 优先级:P1
- 前置条件:Gateway 或测试替身已向 NestJS 回写企业应用连接状态,应用已配置 CMPP 接入参数。
- 步骤:
1. 打开企业应用管理列表。
2. 查看 CMPP 状态列连接数。
3. 点击连接数打开连接详情。
4. 删除一个连接并确认。
5. 点击 CMPP 连接参数按钮并一键复制。
- 预期结果:
- 连接数来自真实连接状态 API。
- 连接详情展示连接 id、状态、建立时间、最近心跳时间、上次提交时间、窗口占用等要素。
- 删除连接调用真实后端或 Gateway 接口,连接状态刷新并写系统日志。
- CMPP 参数来源于真实应用/通道配置,一键复制内容与 API 返回一致。
### TC-ADMIN-018A 企业应用新增表单企业选择与队列等级
- 优先级:P0
- 前置条件:存在至少两个真实企业,运营管理员已登录,通道组基础数据可用。
- 步骤:
1. 打开运营端企业应用管理,点击新增短信应用。
2. 在第一步选择企业下拉框中查看企业选项、加载态和空态。
3. 选择企业后进入应用参数表单。
4. 配置应用名称、客户单价、IP 白名单、发送队列等级、短信接口开关、接口类型、CMPP 6 位账号、企业代码、应用扩展码、接入号填充开关/前缀、16 位接口密码、客户最大连接数、移动/联通/电信通道组后保存。
5. 刷新列表并打开编辑页。
- 预期结果:
- 企业选择使用项目通用 Select/下拉控件,样式、禁用态、错误态与系统其他下拉一致。
- 企业选项来自真实企业 API,不使用静态数组、mock 或 localStorage。
- 请求体包含 tenantId、queuePriority、客户单价、IP 白名单、`interfaceEnabled``interfaceType=cmpp20``cmppAccount``cmppEnterpriseCode``passwordCipher``cmppMaxConnections` 和通道组绑定;企业应用表单不展示或提交客户侧 `cmppWindowSize`
- “短信接口”开关刷新后仍来自真实数据库;关闭后该应用不能通过客户端/API 发送,也不能通过 Gateway bind/login 或 submit。
- CMPP 协议当前只能选择 CMPP2.0;HTTP 使用独立配置区、总开关和子能力,不与 CMPP `interfaceType` 互斥;手工提交 `interfaceType=http` 时后端仍返回 400。
- `cmppAccount` 可显式填写 6 位数字;留空时由后端自动生成唯一账号;重复或非法格式保存失败并提示可读错误。
- `cmppEnterpriseCode` 来自应用自身配置,不透传上游通道企业代码;`passwordCipher` 为 16 位,编辑留空不覆盖原密码。
- 填充开关关闭时不渲染填充前缀输入框;开启后前缀才显示并可编辑。前后端只接受数字扩展码/前缀,客户侧接入号为二者拼接且不超过 21 位;关闭填充后前缀清空。
- 客户 CMPP Submit 的 `Src_Id` 必须精确等于当前应用客户侧接入号,错误或缺失时在创建任务、计费和入队前拒绝;正确值写入 `SmsMessageRecord.clientSrcId`,真实扩展码写入 `applicationExtension` 快照。
- Gateway 上游 Submit 的 `Src_Id` 为通道基础接入号拼接短信快照中的应用扩展码;客户填充前缀不参与上游号码,上游号码超过 21 位时受控失败且不产生半成品提交记录。
- 后端真实保存应用队列等级和 CMPP 参数,刷新列表、编辑页和 CMPP 参数弹窗后仍显示正确。
- 不选择任何通道组或缺少必填字段时不能保存,并显示可读提示。
### TC-ADMIN-019 通道连接日志展示
- 优先级:P1
- 前置条件:Gateway 或测试替身已产生连接请求、连接成功、心跳、断开、重连、异常事件。
- 步骤:
1. 打开短信通道管理页面。
2. 在状态区域点击连接日志。
3. 查看日志时间、事件类型、连接 id、详情。
- 预期结果:
- 连接日志由真实后端 API 返回,不使用前端硬编码数据。
- 日志包含连接请求、连接成功、断开、心跳、重连、异常等事件。
- 日志按时间倒序展示,并可定位到对应通道或连接。
### TC-ADMIN-020 安全控制搜索、添加、启停与删除
- 优先级:P1
- 前置条件:运营管理员已登录,存在企业、应用和若干黑名单/敏感词数据。
- 步骤:
1. 在企业黑名单中按企业、应用、手机号、原因、状态搜索。
2. 新增企业应用级黑名单,停用后再删除。
3. 在全局黑名单中按手机号、原因、状态搜索,并新增、停用、删除。
4. 在敏感词管理中按词、分类/级别、状态搜索,并新增、停用、删除。
- 预期结果:
- 搜索、添加、启停、删除均调用真实字典 API。
- 企业黑名单必须绑定短信应用,只影响该应用发送预览和风控;同企业其他应用不被拦截。
- 启停/删除后发送前风控只使用 active 数据。
- 所有安全控制变更写入系统日志。
- 操作按钮使用统一编辑、删除、启停样式。
### TC-ADMIN-021 运营端消息铃铛审核提醒
- 优先级:P1
- 前置条件:浏览器允许通知,存在企业认证、短信审核、模板审核、签名审核待处理任务。
- 步骤:
1. 打开运营端任意页面,查看右上角消息铃铛数字。
2. 点击铃铛查看分类数量。
3. 点击某个分类。
4. 新增一条待审核任务。
- 预期结果:
- 铃铛数字等于所有待审核任务总数,分类数量来自真实待审核统计 API。
- 点击分类跳转到对应审核页面并带入筛选状态。
- 新审核任务进入时触发浏览器通知或站内提醒。
- 审核完成后总数和分类数量刷新。
### TC-ADMIN-022 运营端系统日志分页与详情展示
- 优先级:P1
- 前置条件:存在超过一页的运营端系统日志,且部分日志详情较长。
- 步骤:
1. 打开运营端系统日志页面。
2. 按操作者、操作类型、资源、时间搜索。
3. 切换分页。
4. 查看长详情日志。
- 预期结果:
- 分页、搜索由真实后端 API 处理。
- 页面只保留一个标题和一个图标。
- 长详情使用详情卡或弹窗展示,不被表格窄列截断。
- 能查询到登录、退出、审核、通道复制、通道启停、通道删除、连接状态变化、安全控制变更等日志。
## 6. 风控规则专项用例
### TC-RISK-001 单任务最大号码数直接拒绝
- 优先级:P0
- 前置条件:应用最大号码数阈值为 100。
- 步骤:提交 101 个合法号码。
- 预期结果:
- 命中 `MAX_PHONES_PER_TASK`
- 任务 rejected。
- 风控命中记录包含阈值 100、实际值 101、动作 reject/block。
### TC-RISK-002 重复号码比例进入人工审核
- 优先级:P0
- 前置条件:重复率阈值为 30%,动作为人工审核。
- 步骤:提交 10 个号码,其中 4 个为重复号码。
- 预期结果:
- duplicateRatio 为 0.4。
- 命中重复号码规则。
- 任务 pending_review。
### TC-RISK-003 非法号码比例直接拒绝
- 优先级:P0
- 前置条件:非法率阈值为 10%,动作为拒绝。
- 步骤:提交 10 个号码,其中 2 个非法。
- 预期结果:
- illegalRatio 为 0.2。
- 任务 rejected。
- 客户端展示非法号码比例过高。
### TC-RISK-004 黑名单命中比例人工审核
- 优先级:P0
- 前置条件:黑名单率阈值为 5%,动作为人工审核。
- 步骤:提交 20 个号码,其中 2 个在企业或全局黑名单。
- 预期结果:
- blacklistHitRatio 为 0.1。
- 任务 pending_review。
- 命中记录写入黑名单规则。
### TC-RISK-005 模板变量缺失直接拒绝
- 优先级:P0
- 前置条件:模板要求变量 `code`
- 步骤:提交发送时不传 `code`,或额外传入未定义变量。
- 预期结果:
- 命中 `TEMPLATE_VARIABLE_ANOMALY`
- 任务 rejected。
- variableIssues 记录缺失或多传变量。
### TC-RISK-006 非工作时间营销大批量人工审核
- 优先级:P1
- 前置条件:非工作时间大批量阈值为 5000。
- 步骤:在 21:00 后提交营销类短信 5001 个号码。
- 预期结果:
- 命中非工作时间营销大批量规则。
- 任务 pending_review。
- 审核原因可见。
### TC-RISK-007 短时间任务创建频控
- 优先级:P1
- 前置条件:10 分钟最多创建 10 次任务。
- 步骤:同租户同应用 10 分钟内创建第 11 个任务。
- 预期结果:
- 命中频控规则。
- 按规则动作进入人工审核或拒绝。
- 命中记录包含 recentTaskCount。
## 7. 计费专项用例
### TC-BILLING-001 70/67 计费条数
- 优先级:P0
- 步骤:
1. 使用 70 字内容提交 1 个号码。
2. 使用 71 字内容提交 1 个号码。
3. 使用 134 字内容提交 1 个号码。
- 预期结果:
- 70 字为 1 条。
- 71 字为 2 条。
- 134 字为 2 条。
- 金额等于计费条数乘单价。
### TC-BILLING-002 发送前冻结
- 优先级:P0
- 前置条件:账户余额充足,计费口径需要发送前冻结。
- 步骤:创建发送任务并进入待发送。
- 预期结果:
- 生成 frozen 流水。
- 企业现金余额减少。
- 流水关联 taskId。
### TC-BILLING-003 submit 成功扣费
- 优先级:P0
- 前置条件:企业应用已配置客户单价,发送任务已冻结预算。
- 步骤:模拟 Gateway 返回 submit accepted。
- 预期结果:
- 生成 charged 流水。
- 短信计费记录状态更新为 charged。
- 扣费金额按企业应用客户单价计算,不按通道成本价或运营商差异价计算。
- 可按 messageId 对账。
### TC-BILLING-004 最终失败退款
- 优先级:P0
- 前置条件:短信已扣费。
- 步骤:模拟 receipt undelivered。
- 预期结果:
- 短信状态 failed/undelivered。
- 生成 refunded 流水。
- 退款金额与原扣费一致。
- 重复 failed receipt 不重复退款。
### TC-BILLING-005 72 小时超时退款
- 优先级:P0
- 前置条件:短信状态 unknown 且超过 72 小时。
- 步骤:执行未知转超时补偿任务。
- 预期结果:
- 短信状态 timeout。
- 生成退款或释放流水。
- 后续二次成功回执不自动覆盖 timeout 状态。
## 8. 发送链路专项用例
### TC-SEND-001 批量任务创建和手机号拆分
- 优先级:P0
- 步骤:提交包含多个手机号的客户端批量任务。
- 预期结果:
- 生成 1 条 `SmsBatchTask`
- 每个有效手机号生成 1 条 `SmsMessageRecord`
- `SmsBatchTask.progressTotal` 等于有效手机号数量。
### TC-SEND-002 发送任务入队
- 优先级:P0
- 前置条件:任务审核通过。
- 步骤:触发送 worker 入队。
- 预期结果:
- 每条 queued 短信生成一个发送 job。
- jobId 使用 messageRecordId,避免重复入队。
- 批量任务状态变为 queued。
### TC-SEND-002A 生产发送 Worker 配置门禁
- 优先级:P0
- 前置条件:使用生产环境文件执行发布脚本。
- 步骤:
1. 删除或关闭 `API_ENABLE_SEND_WORKER`,执行发布脚本。
2. 配置 `API_ENABLE_SEND_WORKER=true` 和正整数 `API_SEND_WORKER_CONCURRENCY`,重新发布。
3. 创建一条 queued 短信并观察 Redis BullMQ 与数据库提交记录。
- 预期结果:
- 步骤 1 在构建、迁移和服务重启前终止,明确提示发送 Worker 未启用。
- 步骤 2 发布成功,API 启动发送 Worker。
- 步骤 3 的 job 不长时停留在 `prioritized/wait`,且真实生成 `SmsSubmitRecord` 并进入 Gateway。
### TC-SEND-003 通道路由和 Gateway SubmitCommand
- 优先级:P0
- 前置条件:企业应用已绑定对应运营商的 active 通道组,通道组内存在 active 且 online 的通道。
- 步骤:处理一条发送 job。
- 预期结果:
- 先按号码前缀正则识别运营商,再只在企业应用绑定的对应运营商通道组内选择正确通道。
- 创建 SmsSubmitRecord。
- 投递 Gateway SubmitCommand,包含 traceId、messageId、channelId、submitId、phoneNumber、content、cmpp 参数。
- 未配置对应运营商通道组或未命中可用通道时不发送,并记录可读失败原因。
### TC-SEND-010 禁止路由规则直接绑定单通道
- 优先级:P0
- 前置条件:存在通道 A、通道组 G、企业应用 App。
- 步骤:
1. 尝试创建或启用直接绑定通道 A 的路由规则。
2. 创建 App 的发送任务。
3. 查看 submit record、trace 和系统日志。
- 预期结果:
- 系统不允许直接绑定单个通道作为发送规则。
- 发送链路只接受通道组路由。
- 如存在历史单通道规则,发送链路不得使用该规则,并记录配置错误。
### TC-SEND-011 未命中企业应用通道组时不发送
- 优先级:P0
- 前置条件:企业应用 App 未配置通道组,系统存在其他 active 通道。
- 步骤:
1. 创建 App 的发送任务。
2. 触发送 worker。
3. 查看发送明细、submit record、trace 和系统日志。
- 预期结果:
- 系统不 fallback 到其他 active 通道。
- 不投递 Gateway SubmitCommand。
- 发送明细进入 failed。
- 运营端 trace 和系统日志可看到“未配置可用通道组”原因;客户端本期只展示失败状态,不展示通道细节。
### TC-SEND-012 手机号段识别归属地参与路由
- 优先级:P0
- 前置条件:运营商区分规则可识别移动号码;手机号段库存在 `prefix/province/city` 数据;企业应用绑定移动通道组,组内配置山东省网通道 A、全国通道 B。
- 步骤:
1. 使用山东手机号创建发送任务。
2. 触发送 worker。
3. 查询 submit record、trace 和路由日志。
- 预期结果:
- 系统按可配置前缀正则识别运营商,并按手机号段库查询省份和城市。
- 手机号段 carrier 仅作为后台校验或提示,不改变正则识别出的发送运营商。
- trace 记录识别出的运营商、省份和城市。
- 路由优先选择山东省网通道 A。
- Gateway SubmitCommand 的 channelId 为 A。
### TC-SEND-013 省网未匹配时走全国路由
- 优先级:P0
- 前置条件:手机号段库可识别四川手机号;企业应用绑定对应运营商通道组,组内无四川省网通道,但存在全国通道 B。
- 步骤:
1. 使用四川手机号创建发送任务。
2. 触发送 worker。
3. 查询 submit record 和 trace。
- 预期结果:
- 系统识别手机号归属地为四川。
- 省网未匹配时选择同一通道组内全国通道 B。
- 不选择其他通道组或全局 active 通道。
### TC-SEND-014 省网失败后补发全国通道
- 优先级:P0
- 前置条件:通道组内配置山东省网通道 A 和全国通道 B/C;A、B、C 均属同一企业应用授权通道组;A 可模拟 submit 失败、连接断开或最终回执失败。
- 步骤:
1. 使用山东手机号创建发送任务。
2. 首次路由命中 A。
3. 模拟 A submit rejected、submit timeout、连接断开、运营商失败回执或其他 receipt failed。
4. 查看补发记录、submit record、trace、计费流水。
- 预期结果:
- 系统立即切换到全国通道 B 补发,不再尝试同省第二省网通道。
- 如果 B 失败,继续按全国通道优先级补发到 C。
- 补发不跨出企业应用授权通道组。
- 原失败原因、补发次数、前后 channelId 和状态流转在 trace 中可查。
- 最终成功只按企业应用客户费率扣一次,不按通道成本价重复扣费。
- 补发选择通道时使用当前通道组配置,并重新校验新通道上的签名报备状态。
### TC-SEND-015 企业应用通道组保存校验
- 优先级:P0
- 前置条件:存在移动、联通、电信通道组。
- 步骤:
1. 新建或编辑企业应用,不选择任何通道组并保存。
2. 选择移动通道组后保存。
3. 再补充联通、电信通道组保存。
- 预期结果:
- 不选择任何通道组时页面不可保存,并提示至少配置一个运营商通道组。
- 允许只配置移动、联通或电信中的一类或两类。
- 已配置的运营商通道组会影响对应运营商短信分流。
### TC-SEND-016 运营商正则分流和识别失败默认移动
- 优先级:P0
- 前置条件:手机号段库的“运营商区分规则”已配置移动、联通、电信号码前缀正则;企业应用分别绑定移动、联通、电信通道组。
- 步骤:
1. 分别提交移动、联通、电信号码。
2. 提交一个正则无法识别运营商但号码格式合法的号码。
3. 查询 submit record 和 trace。
- 预期结果:
- 移动号码进入移动通道组。
- 联通号码进入联通通道组。
- 电信号码进入电信通道组。
- 运营商识别失败时进入移动通道组。
- 若手机号段库 carrier 与正则识别结果冲突,以正则识别结果为准,号段 carrier 仅记录为提示信息。
### TC-SEND-017 三网通道作为运营商通配
- 优先级:P0
- 前置条件:企业应用绑定移动通道组;移动通道组 carrier 为 mobile;组内明细 carrier 为 mobile;组内无可用移动全国通道,但有可用三网全国通道。
- 步骤:
1. 提交移动号码。
2. 触发送 worker。
3. 查询 submit record 和 trace。
4. 将同一三网通道放入联通通道组,再提交移动号码。
- 预期结果:
- 三网通道本体 `channel.carrier=all` 只表示通道能力,可被运营分配到移动、联通或电信通道组。
- 移动号码只会选择移动通道组内 `item.carrier=mobile` 且通道本体为 mobile/all 的通道。
- 放入联通通道组的三网通道不能被移动号码选中。
- route/trace 标明实际命中的三网通道。
### TC-SEND-016A 预发布运营商号段规则完整性
- 优先级:P0
- 前置条件:运营商区分规则已按当前公开码号资料同步。
- 步骤:
1. 读取真实 `GET /api/admin/dictionaries/phone-carrier-rules?page=1&pageSize=100`
2. 使用移动、联通、电信基础号段及 `162/165/167/170/171` 等移动转售号段生成代表号码。
3. 使用 `190/191/192/193/195/196/197/198/199` 生成代表号码。
4. 对每个代表号码按发送服务相同的优先级和 JavaScript 正则逐条匹配。
- 预期结果:
- 每个代表号码唯一命中一条 active 规则,不得重叠或漏配。
- `190/191/193/199` 归电信,`196` 归联通,`195/197/198` 归移动。
- 中国广电 `192` 按当前业务约定唯一归入移动。
- 测试结论仅代表原始号段分配规则,不把携号转网号码误宣称为实时运营商识别。
### TC-SEND-018 失败补发停止条件
- 优先级:P0
- 前置条件:通道组开启失败补发并配置补发时间上限;全国通道可连续模拟失败。
- 步骤:
1. 模拟普通 failed 回执,确认触发补发。
2. 模拟 unknown 状态,执行 72 小时超时补偿。
3. 将消息提交时间调整为超过 72 小时。
4. 将消息提交时间调整为超过通道组分钟级补发时间上限。
5. 关闭通道组失败补发后再次模拟 failed。
- 预期结果:
- 普通 failed 在限制内触发补发。
- unknown 不触发补发。
- 超过 72 小时不触发补发。
- 超过通道组分钟级补发时间上限不触发补发。
- 通道组关闭失败补发时不触发补发。
### TC-SEND-019 迟到旧通道回执不覆盖最终成功
- 优先级:P0
- 前置条件:短信首次通过通道 A 发送失败并补发到通道 B,通道 B 已返回 delivered。
- 步骤:
1. 查询短信记录列表,确认该短信当前状态为 deliveredchannelId/gatewayMessageId 为通道 B。
2. 模拟通道 A 迟到的 failed receipt。
3. 查询短信记录列表、短信详情弹窗、回执历史和账单流水。
- 预期结果:
- 短信记录列表仍展示最终 delivered 状态,不被通道 A 的 failed receipt 覆盖。
- 短信详情弹窗可见通道 A 的历史 failed receipt。
- 不产生重复退款,也不改变已成功短信的最终计费状态。
### TC-SEND-020 重复回调幂等
- 优先级:P0
- 前置条件:存在一条已 submit accepted 并完成账务扣费的短信。
- 步骤:
1. 连续发送两次相同 submit accepted 回调。
2. 连续发送两次相同 failed receipt 回调。
3. 查询短信记录、提交记录、回执记录、短信计费记录和账户流水。
- 预期结果:
- 提交/回执历史可追踪,但短信最终状态按最新有效尝试处理。
- accepted 不重复扣费。
- failed receipt 不重复退款。
- 账户流水、短信计费记录和 reconciliation 无重复金额。
### TC-SEND-004 SubmitResult accepted
- 优先级:P0
- 步骤:模拟 Gateway 返回 accepted。
- 预期结果:
- SmsSubmitRecord 写入 sequenceId、gatewayMessageId、accepted 状态。
- SmsMessageRecord 状态变为 submitted。
- 批量任务进度刷新。
### TC-SEND-005 SubmitResult rejected
- 优先级:P0
- 步骤:模拟 Gateway 返回 rejected 和错误码。
- 预期结果:
- SmsMessageRecord 状态变为 submit_failed。
- 记录 errorCode/errorMessage。
- 失败数统计增加。
### TC-SEND-006 Receipt delivered
- 优先级:P0
- 步骤:模拟 deliver 回执 `DELIVRD`
- 预期结果:
- 创建 SmsReceiptRecord。
- SmsMessageRecord 状态变为 delivered。
- 成功数统计增加。
### TC-SEND-007 Receipt unknown 后超时
- 优先级:P0
- 步骤:
1. 模拟 unknown 回执。
2. 将 deliveredAt 调整为 72 小时前。
3. 执行超时补偿。
- 预期结果:
- unknown 记录转为 timeout。
- timeoutTotal 增加。
- 错误信息说明 72 小时未收到明确回执。
### TC-SEND-008 上行短信匹配
- 优先级:P1
- 步骤:
1. 模拟带平台 `messageId` 的兼容上行事件。
2. 模拟真实供应商 MO:仅带独立 `gatewayMessageId`,不带历史平台 `messageId`,并分别制造接入号唯一匹配、手机号 72 小时唯一匹配和多候选场景。
3. 打开客户端和运营端详情。
- 预期结果:
- 创建 SmsUplinkMessage。
- `gatewayMessageId` 原样持久化;兼容事件仍可通过平台 `messageId` 精确关联。
- 不带平台 `messageId` 时按接入号、手机号 72 小时窗口执行匹配;唯一结果写入 `tenantId/applicationId/messageRecordId`,多候选保留为 `ambiguous`
- 客户端和运营端均可查询;详情优先使用 API 响应内嵌 `messageRecord`,不因 `messageId` 为空误报“无法匹配”。
- 运营端对已匹配或已认领应用显示“加入应用黑名单”,确认后调用真实企业应用黑名单 API;客户端保持只读。
### TC-SEND-009 未匹配上行短信入库
- 优先级:P1
- 步骤:模拟不带 messageId 或匹配不到下发记录的上行事件。
- 预期结果:
- 上行短信仍入库。
- 供应商 MO `gatewayMessageId` 与平台 `messageId` 分别保存,不能用前者伪造后者的关联。
- tenantId 可为空。
- 运营端可查询并人工判断。
## 9. Gateway 专项用例
### TC-GW-001 SEQID/MSGID 追踪
- 优先级:P0
- 步骤:
1. Gateway 接收 SubmitCommand。
2. 分配 sequenceId。
3. 模拟 submit resp 返回 gatewayMessageId。
4. 按 gatewayMessageId 查询映射。
- 预期结果:
- messageId、sequenceId、gatewayMessageId 三者可互查。
- 并发提交时映射不串。
### TC-GW-002 重连后继续消费
- 优先级:P0
- 步骤:
1. 模拟 SMSC 连接失败。
2. Gateway 执行重连。
3. 重连成功后继续处理新 SubmitCommand。
- 预期结果:
- 重连次数可观测。
- 未成功连接时不丢失任务。
- 连接恢复后继续消费。
### TC-GW-003 Health 检查
- 优先级:P0
- 步骤:访问 Gateway `/health`
- 预期结果:
- 返回 HTTP 200。
- payload 包含 `status=ok` 和服务名。
### TC-GW-004 gocmpp submit/resp 模拟器
- 优先级:P0
- 步骤:
1. 启动或调用模拟 SMSC。
2. Gateway 发起 submit。
3. 模拟器返回 submit resp 和 deliver。
- 预期结果:
- submit resp 可解析。
- deliver 回执可转为队列事件。
- 不依赖真实运营商。
### TC-GW-005 重复回执
- 优先级:P1
- 步骤:同一 gatewayMessageId 连续发送两次 delivered 回执。
- 预期结果:
- 第一条更新最终状态。
- 第二条记录历史或被幂等处理。
- 不重复扣费或重复变更最终状态。
### TC-GW-006 下游客户 CMPP 17890 入站 bind/submit
- 优先级:P0
- 前置条件:企业已认证通过;短信应用 active 且存在独立 6 位 `cmppAccount`、应用级 `cmppEnterpriseCode` 和 16 位 `passwordCipher`;应用 IP 白名单包含测试客户端 IP;应用已有审核和报备通过的签名/模板;通道组、余额和 Gateway 均可用。
- 步骤:
1. 启动 Go Gateway,确认 `GATEWAY_CMPP_ADDR=0.0.0.0:17890`
2. 使用 gocmpp 或真实 CMPP 客户端连接 `17890``Source_Addr` 填应用 `cmppAccount`,密码填应用 CMPP 参数 `passwordCipher`
3. 分别发送 CMPP 2.0 和 CMPP 3.0 单号码 SubmitReq;再发送 `DestUsrTl=2`、两个合法 `DestTerminalId` 的多号码 SubmitReq,手机号和内容均匹配已审核模板。
4. 再发送一条不匹配审核模板的 SubmitReq,检查客户收到的 SubmitResp 和 Gateway 日志。
5. 查询 NestJS 数据库和运营端短信记录。
- 预期结果:
- 17890 是真实 CMPP Server 监听,不是 HTTP 端口。
- bind 阶段调用真实 NestJS API 校验账号、密码、企业状态、认证状态、应用状态、短信接口开关和 IP 白名单。
- CMPP2.0 和 CMPP3.0 连接分别返回对应版本 ConnectResp,后续 Submit/Deliver 按该 TCP 连接协商版本解包和组包,不发生字段错位。
- 密码错误、应用停用、企业停用、短信接口关闭、IP 不在白名单时 connect/login 被拒绝。
- submit 被接受后返回 CMPP SubmitResp 成功,并在真实数据库创建 `sourceType=cmpp` 的发送记录,进入真实发送链路。多号码 Submit 仍只返回一个 SubmitResp/Msg_Id,但必须为全部目标号码分别创建 `SmsMessageRecord` 和内部批次,分别校验、计费、路由和提交;每个号码的 Deliver Receipt 使用同一原 Submit Msg_Id,并以各自 `DestTerminalId` 区分。Gateway 重启后从持久化分组消息 ID 和 Submit Sequence_Id 恢复时,所有号码的回执 Msg_Id 仍必须与原 SubmitResp 完全一致。
- `sourceType=cmpp` 的内部批次不出现在运营端或客户端“短信任务进度”;客户端不能通过任务 ID 读取该内部批次的详情、短信明细或执行取消。
- Submit 应用身份使用 bind 已鉴权账号;`MsgSrc` 使用应用级企业代码并独立校验。企业代码与登录账号不同时仍能正确定位应用,企业代码不匹配时返回失败。
- 鉴权失败、IP 白名单不符、任一目标手机号等协议参数不合法时返回非零 SubmitResp,且整包不创建短信记录;禁止多号码 Submit 返回成功后只保存或发送首号码。
- 已鉴权且参数合法的 Submit 必须先返回成功 SubmitResp 和平台 Msg_Id;内容不匹配审核模板、签名/报备未通过、余额不足、应用在 bind 后停用、无可用通道、上游 Submit 最终失败时,均须真实创建短信记录、`SmsReceiptRecord``CmppDownstreamDelivery`,并向客户下发 `undelivered/REJECTD` Deliver Receipt,不得仅以 SubmitResp 失败替代回执。
- 应用、企业或CMPP接口在bind后停用/删除时,仅本次已受理Submit产生的`ACCOUNT/INTERFACE`平台失败回执可绕过当前业务启用状态投向原CMPP会话;不得因此允许新bind、供应商Submit、普通HTTP消息转CMPP回执或其他停用资源继续发送。
- Gateway 对每次 submit 记录 `submit_received``submit_accepted`/`submit_rejected`;日志可按账号、IP、sequenceId、号码和 messageId 定位,拒绝时包含 NestJS 真实业务原因和 CMPP result,但不包含明文短信正文。
- CMPP 包在进入 handler 前因长度、命令字、读包或 Unpack 失败时,Gateway 记录 `read/unpack packet failed`、远端地址、协议模式、错误类型和原始错误,不得静默断开。
- 企业应用列表和连接详情展示真实下游 CMPP 会话:bind 后当前连接数加一,显示客户 IP、企业代码、CMPP 版本、连接建立时间与最后心跳;连接持续未响应 `ACTIVE_TEST` 超过阈值后转为心跳超时/断开,不能继续显示为正常连接。
### TC-SEND-038 批量任务与 CMPP 内部批次隔离
- 优先级:P0
- 前置条件:同一企业已存在一个客户端批量发送任务,并通过下游 CMPP 提交一条短信。
- 步骤:
1. 查询运营端短信任务进度。
2. 查询该企业的客户端批量任务列表。
3. 使用 CMPP 内部批次 ID 请求客户端任务详情、短信明细和取消接口。
4. 查询运营端短信记录。
- 预期结果:
- 两个任务进度列表只返回 `sourceType=client` 的客户端批量任务。
- CMPP 内部批次的详情、短信明细和取消请求均返回不可见/不存在,不泄露内部任务。
- CMPP 短信仍完整出现在短信记录、提交、回执和账务链路。
### TC-GW-006A 下游 CMPP UDH 长短信持久化重组
- 优先级:P0
- 前置条件:企业应用可正常 bind;已配置审核通过的完整签名和模板;NestJS、PostgreSQL、Redis 与 Go Gateway 使用真实本地或预发布链路。
- 步骤:
1. 使用 CMPP2.0 和 CMPP3.0 分别提交一条两片长短信,分片正文使用 UCS2,首片携带签名;覆盖 8 位 `05 00 03` 和 16 位 `06 08 04` UDH。
2. 第一片提交后查询 `CmppInboundLongMessage``CmppInboundLongMessageSegment``SmsBatchTask``SmsMessageRecord`
3. 乱序提交第二片,再重复提交内容和 `Sequence_Id` 完全相同的分片。
4. 使用相同引用号和片序号提交内容不同或 `Sequence_Id` 不同的冲突片。
5. 在全部分片已持久化、业务处理尚未完成时重启 API,再重放任一已存分片。
6. 只提交部分分片并等待超过 `CMPP_INBOUND_LONG_MESSAGE_TTL_SECONDS`,执行超时扫描。
- 预期结果:
- Gateway 去除 UDH 后才按 `MsgFmt` 解码,NestJS 收到的每片正文不含 `05 00 03`/`06 08 04` 控制字节;每个合法分片均返回 `SUBMIT_RESP status=0`
- 分片未齐全时只存在一条 collecting 分组和已收分片,API 返回稳定的分组 `messageId`,不得创建内部批次、短信主记录、计费或路由。
- 分片齐全后按 `segmentIndex` 唯一排序拼接,只创建一条完整正文 `SmsMessageRecord` 和一个内部批次;正文签名/模板识别针对拼接后的完整内容执行,`cmppSubmitSequenceId` 使用第一片 `Sequence_Id`
- 乱序可完成;完全相同的重复片幂等复用原结果;冲突片返回明确 4xx/非零 SubmitResp,数据库唯一约束禁止同组同片序号出现两行。
- API 重启后从 PostgreSQL 恢复分组、分片、原 `messageId` 和第一片 `Sequence_Id`,不得重复创建主记录。
- 超时未齐分组转为 expired,保留分片审计但不创建短信主记录;后续相同引用号的新消息可建立新分组。
### TC-SEND-039 CMPP 模板不匹配短窗口聚合人工审核
- 优先级:P0
- 前置条件:应用 A 配置 `templateMismatchMode=manual_review`,应用 B 配置 `reject`;两个应用均已配置审核和报备通过的签名、余额和通道组。
- 步骤:
1. 在 10 秒内用应用 A 的同一 CMPP 账号向不同手机号提交多条规范化后内容完全一致、签名合法但不匹配模板的短信。
2. 用应用 A 提交内容不同、账号不同或跨越聚合窗口的短信。
3. 用应用 B 提交同样的模板不匹配短信。
4. 分别审核通过和驳回应用 A 的聚合任务。
- 预期结果:
- 应用 A 同账号、同内容指纹、同窗口的短信只创建一个 `sourceType=cmpp_template_mismatch` 审核任务,审核页展示真实聚合号码数。
- 不同应用、账号、内容指纹或窗口的短信不合并。
- 应用 B 不进入人工审核,继续逐条产生 `REJECTD` Deliver Receipt。
- 审核通过后每条成员独立进入路由、提交和计费;审核驳回后每条成员独立释放冻结并向客户下发 `REJECTD`
- 签名无法识别、未审核通过、风控直接拒绝或余额不足时不进入聚合审核;签名报备状态由后续具体通道路由校验。
### TC-SEND-039A CMPP 完整括号签名与部分通道报备放行
- 优先级:P0
- 前置条件:应用配置 `templateMismatchMode=manual_review`;签名库名称为完整的 `【航天信息信诺网】``auditStatus=approved`、全局 `reportStatus=reporting`;主通道签名任务 approved、备用通道签名任务 pending。
- 步骤:
1. 通过真实 CMPP 入站提交 `【航天信息信诺网】您本次操作的验证码是171102,有效时间10分钟。`
2. 查看入站签名查询、人工审核聚合记录和失败回执。
3. 审核通过后查看短信路由与 Gateway SubmitCommand。
- 预期结果:
- 入站签名使用完整的 `【航天信息信诺网】` 查询,不剥离中括号,不以无括号名称查询。
- 全局 `reportStatus=reporting` 不在入站阶段触发 `SIGNATURE` 拒绝,短信进入真实人工审核聚合链路且不产生签名失败回执。
- 审核通过后只允许选择签名任务为 approved 的主通道,不能选择 pending 的备用通道;最终提交前继续执行同一通道级校验。
### TC-SEND-039B CMPP 变量模板匹配与 direct_send 策略
- 优先级:P0
- 前置条件:应用 A 存在审核通过模板 `【航天信息信诺网】您本次操作的验证码是${code},有效时间10分钟。`;应用 B 配置 `templateMismatchMode=direct_send`。两个应用均配置已审核签名、余额、真实通道组及至少一个签名报备通过且在线的通道。
- 步骤:
1. 应用 A 通过 CMPP 提交 `【航天信息信诺网】您本次操作的验证码是715021,有效时间10分钟。`
2. 查询 `SmsMessageRecord/SmsBatchTask/SmsSendTask`,并检查进入风险评估的模板和变量。
3. 应用 B 提交签名合法但没有任何模板匹配的短信。
4. 分别将应用 B 的签名改为未审核、账户改为余额不足、具体通道签名报备改为未通过后重复提交。
- 预期结果:
- 步骤 1 按固定正文和 `${code}` 占位符匹配模板,保存真实 `templateId`,向风控传入 `code=715021`,不得产生 `TEMPLATE/REJECTD` 失败回执。
- 应用 B 的模板不匹配短信按 `direct_send` 继续进入风控、余额、队列和真实通道路由;消息保存识别出的 `signatureId`,不能被模板拒绝分支截断。
- `direct_send` 只跳过模板匹配要求,不跳过企业/应用状态、签名审核、风控、余额、具体通道报备、通道在线状态和 Gateway 提交校验;任一校验失败时按真实失败原因拒绝或失败。
- `reject``manual_review` 的既有行为不变;CMPP SubmitResp、失败 Deliver Receipt 和最终上游回执仍按既有异步语义处理。
### TC-GW-007 CMPP 客户到上游 SMSC 完整闭环
- 优先级:P0
- 前置条件:企业已认证通过;短信应用 active 且配置独立 `cmppAccount/passwordCipher/IP 白名单`;签名、模板、报备、余额、通道组、通道连接状态均满足发送;Go Gateway、NestJS API、Redis、PostgreSQL 均使用真实本地或生产验证服务;上游使用真实 SMSC 测试环境或本地 gocmpp 模拟 SMSC。
- 步骤:
1. 客户 CMPP 客户端连接 Gateway `17890` 并完成 bind/login。
2. 客户分别提交匹配模板的短短信 SubmitReq,以及超过 140 字节、需要 CMPP UDH 分片的长短信 SubmitReq。
3. NestJS 入站接口执行应用状态、企业认证、IP 白名单、手机号、模板、签名报备、余额、黑名单、风控、运营商识别、通道组路由和通道连接可用性校验。
4. NestJS 生成真实发送记录、SubmitCommand 和 SmsSubmitRecord,将 SubmitCommand 写入 Redis Stream `gateway.submit.commands`,同时保留 BullMQ 审计/兼容投递。
5. Go Gateway submit worker 通过 consumer group 独立消费 SubmitCommand,使用其中的上游通道连接参数连接 SMSC,发送真实 CMPP Submit;长短信应按 6 字节 UDH 分片,设置 `PkTotal/PkNumber/TpUdhi` 并逐包提交。
6. 上游 SMSC 返回 SubmitRespGateway 回调 NestJS `SubmitResult`
7. 上游 SMSC 下发 deliver receiptGateway 解析为 `ReceiptEvent`NestJS 入库并更新最终状态。
8. NestJS 调用 Gateway `/downstream/receipt`,Gateway 向仍在线的客户连接下发 CMPP Deliver Receipt。
9. 上游 SMSC 下发普通 deliver 上行;长上行使用 UDH 分片乱序下发时,Gateway 应等待分片齐全后重组成一条 `UplinkEvent`NestJS 入库。
10. NestJS 调用 Gateway `/downstream/uplink`Gateway 对可关联 messageId 且客户仍在线的上行下发普通 CMPP Deliver。
11. 客户断开 CMPP 连接后再次产生 receipt/uplink,确认 NestJS 写入客户侧待投递记录。
12. 客户重新 bind/loginGateway 按账号拉取 pending 投递并补发,成功后回写 delivered。
- 预期结果:
- 客户 bind/login 使用真实数据库账号、密码、状态和 IP 白名单校验。
- 业务校验失败时不调用上游 submit,不扣费,不伪造成功。
- API 入队后不依赖同步调用 Gateway `/upstream/submit`Gateway 停止时命令留在 Redis StreamGateway 恢复后继续消费。
- 长短信 Submit 每个 CMPP 分片长度不超过 140 字节,分片 UDH 正确;所有 accepted 分片的上游 `MsgId` 均可映射回同一平台消息。
- 上游 submit accepted 后只按应用客户费率扣费一次;submit rejected/timeout 进入补发或释放冻结。
- deliver failed 触发补发或最终退款;重复/迟到回执不重复扣费或退款。
- 客户在线且 Gateway 仍保留 messageId 或账号会话时,可以收到最终 Deliver Receipt 和可关联上行 Deliver。
- 客户断线或 Gateway 控制面暂不可达时,`CmppDownstreamDelivery` 保留 pending、retryCount、nextRetryAt、lastError;客户重连后可补发并标记 delivered。
- 长上行分片未齐全前不入库不推送;分片齐全后只入库一条完整上行内容,且可继续执行 messageId、接入号或手机号时间窗口匹配。
- 无 messageId 上行优先按接入号匹配应用;接入号无法唯一匹配时按手机号和时间窗口匹配;多候选标记 ambiguous,不误推;完全匹配不到标记 unmatched 但仍入库。
- 后台周期重试、死信队列、过期策略和人工认领流程需按后续用例验收。
### TC-GW-008 Gateway 多连接窗口与窗口满等待
- 优先级:P0
- 前置条件:运营端通道配置 `desiredConnections=2``windowSize=1`,上游使用可延迟 SubmitResp 的真实测试 SMSC 或本地 gocmpp 模拟 SMSCNestJS API、Redis、PostgreSQL、Go Gateway 均运行真实服务。
- 步骤:
1. 通过真实发送链路连续提交 3 条可通过业务校验的短信,保证前 2 条 SubmitResp 暂不返回。
2. 观察 `SubmitCommand.upstream` 是否携带 `desiredConnections=2``windowSize=1`
3. 观察 Gateway 是否为同一通道建立 2 条上游 CMPP 连接,并将前 2 条短信分别占用两个连接窗口。
4. 第 3 条短信在两个窗口均满时等待,不得越过窗口容量继续 submit。
5. 释放任一 SubmitResp 后,确认第 3 条短信继续提交。
- 预期结果:
- Gateway 每条连接独立维护 sequence/pending 映射,SubmitResp 可正确回到原 `messageId/submitId/channelId`
- 窗口满时消息等待可用窗口;等待超过提交超时时返回 timeout,并由 NestJS 进入既有补发或释放冻结逻辑。
- 多连接窗口只改变 Gateway 提交并发,不绕过 API 侧模板、签名、余额、风控、通道组、通道连接可用性和限速校验。
- 当前阶段不要求断线后的 pending submit 恢复;该能力在后续在途恢复用例验收。
### TC-GW-009 Gateway 重启后认领 pending SubmitCommand
- 优先级:P0
- 前置条件:Redis Stream `gateway.submit.commands` 已创建 consumer groupGateway worker A 已消费一条 `SubmitCommand` 但尚未 ack;该消息空闲时间超过 pending claim 阈值。
- 步骤:
1. 停止或模拟断开 worker A,使该消息留在 PEL。
2. 启动 worker B 或重启 Gateway。
3. 观察 worker B 在消费新消息前执行 pending claim。
4. 观察该消息被重新提交、回调 `SubmitResult`,成功后 ack。
- 预期结果:
- 空闲超过阈值的 pending `SubmitCommand` 会被新的 consumer 认领,不会永久卡在 PEL。
- 被认领消息仍走正常发送链路,`messageId/submitId/channelId` 和上游回执映射保持一致。
- 提交成功后消息从 PEL 移除;提交失败时保留待后续重试或死信治理,不得静默丢失。
### TC-GW-010 上游连接断开时 pending submit 立即补偿
- 优先级:P0
- 前置条件:Gateway 已与上游 SMSC 建立连接;某条连接已成功发送 submit,但上游故意不立即返回 submit resp,随后主动断开 TCP 连接。
- 步骤:
1. 提交一条可通过真实业务校验的短信,使 Gateway 进入等待 submit resp 状态。
2.`defaultSubmitTimeout` 到达前,模拟上游连接断开。
3. 观察 Gateway 对该 pending submit 的处理,以及 NestJS 收到的 `SubmitResult`
- 预期结果:
- Gateway 不会一直等到固定超时才处理,而是立即将该 pending submit 补偿为 `timeout`,错误码为 `CONNECTION_LOST` 或等价可读值。
- NestJS 收到 `SubmitResult` 后走既有补发或释放冻结逻辑,短信状态不会永久卡在 `submit_queued`
- 同一连接上的其他 pending submit 也会被明确唤醒,不会静默丢失。
### TC-GW-011 submit_resp 丢失后按 receipt 保守归因
- 优先级:P0
- 前置条件:某条短信提交上游后,Gateway 因连接断开或 submit resp 丢失将该次提交记为 `timeout`,对应 `sms_submit_record.gatewayMessageId` 仍为空;后续上游真实回执已到达,receipt 中带有该手机号、通道和运营商侧 `MsgId`
- 步骤:
1. 构造一条无法按平台 `messageId/gatewayMessageId` 精确命中的 receipt 事件,但带上真实手机号、通道和运营商侧 `MsgId`
2. 保证同通道、同手机号、72 小时窗口内只有 1 条 `timeout + gatewayMessageId=null` 的 submit 记录。
3. 观察 Gateway 是否将手机号一并上送 NestJS,并检查 NestJS 的归因与入库结果。
4. 再构造“多候选”场景,重复执行同类 receipt 归因。
- 预期结果:
- 只有在唯一候选成立时,NestJS 才接收该 receipt,并回填真实 `sms_submit_record.gatewayMessageId/sequenceId`,同时写入 `sms_receipt_record``sms_message_record`
- 如果存在多条候选或无候选,则拒绝归因,不得误绑到其他短信。
- 已经由新通道成功送达的短信,旧尝试迟到回执仍只记历史,不覆盖最终送达状态。
### TC-GW-012 Gateway 提交异常入库与人工重新入队
- 优先级:P0
- 前置条件:Gateway submit worker 已连接 Redis Stream `gateway.submit.commands`;准备一条会持续触发处理错误的 `SubmitCommand`;NestJS 内部异常上报接口和运营端 Gateway 提交异常 API 真实可用。
- 步骤:
1. 让同一条 `SubmitCommand` 连续处理失败,达到 Gateway 配置的异常转存阈值。
2. 检查 Redis PEL 中该消息是否被 ack,不再无限 pending。
3. 检查 NestJS 是否在真实数据库写入一条 `GatewaySubmitDeadLetter`,保存失败原因、尝试次数和原始命令载荷。
4. 从运营端“网关异常”的“提交异常”Tab查询异常列表并打开脱敏详情。
5. 完成风险确认、原因和状态校验后,将该异常命令重新写回 `gateway.submit.commands`
- 预期结果:
- 达到阈值后,Gateway 会把该消息转存为提交异常,而不是永久卡在 PEL。
- 异常记录来自真实数据库,包含 `streamMessageId``messageId/submitId`、失败原因和尝试次数;浏览器端只收到脱敏命令,不收到原始 payload 或密码密钥。
- 人工重新入队成功后,异常状态更新为 `requeued`,记录新的 Redis Stream 消息 ID、操作人和原因,并写系统日志。
- 重新入队后如后续收到真实 `SubmitResult`,对应异常记录应自动转为 `resolved`
### TC-GW-013 下游客户在线时周期补投与失败封顶
- 优先级:P0
- 前置条件:客户应用 CMPP 账号真实可登录;平台已有至少 1 条 `CmppDownstreamDelivery.status=pending` 的回执或上行待投递记录;Gateway 周期补投任务已启动。
- 步骤:
1. 让客户先断线,制造一次投递失败,确认 `CmppDownstreamDelivery` 留在 `pending``retryCount` 递增。
2. 让客户重新 bind,检查 Gateway 是否立即拉取一次 pending 进行补发。
3. 在客户保持在线的情况下,继续制造一次临时投递失败,等待周期补投触发。
4. 把同一条待投递连续失败到重试上限。
- 预期结果:
- 客户重连后会立即补发 pending 记录;客户在线但上次投递失败时,Gateway 会按周期再次拉取并补投。
- 重试未超过上限时,`CmppDownstreamDelivery` 维持 `pending`,更新 `retryCount/nextRetryAt/lastError`
- 达到上限后,记录转为 `failed`,不再无限 pending,且写真实失败审计日志。
- 该能力只负责“客户已在线时的平台补投”和“消息不丢”;客户断线后的重新建链仍由客户系统自己负责。
### TC-GW-014 运营端下游投递记录查询与人工重投
- 优先级:P1
- 前置条件:数据库中已有 `CmppDownstreamDelivery` 记录,至少覆盖 `pending``failed``delivered` 三类状态;运营端已登录;Gateway 控制面和 NestJS API 均为真实服务。
- 步骤:
1. 进入运营端“下游投递记录”页面。
2. 分别按状态、投递类型、应用、关键字进行筛选,检查分页。
3. 打开一条记录详情,核对 payload、重试次数、最后错误和时间字段。
4. 对一条 `pending``failed` 记录点击人工重投,先取消确认弹窗,确认没有调用重投接口。
5. 再次点击重投并确认,观察提交期间按钮状态和接口成功后的结果弹窗;另模拟一次接口异常。
- 预期结果:
- 页面列表来自真实 `/api/admin/operations/downstream-deliveries`,不是前端静态数组或本地状态拼装。
- 详情展示真实 payload、`retryCount/nextRetryAt/deliveredAt/lastError`
- 人工重投调用真实 `/api/admin/operations/downstream-deliveries/{id}/requeue`,由后端实际触发 Gateway `/downstream/receipt``/downstream/uplink`
- 人工重投后 `manualRetryCount` 递增、`lastRetriedAt` 更新,新一轮 `retryCount` 从 0 开始;系统日志保留重投前状态、原自动重试次数和新人工重投次数。
- 重投后若尚未真正写出,列表显示“人工重投排队中”,不得误显示“待首次投递”;自动失败退避中的 pending 显示“等待自动重试”。
- `awaiting_ack` 记录在前端不可选且后端拒绝并发重投,不能仅依赖按钮禁用。
- 确认弹窗明确展示投递类型、消息 ID 和重复处理风险;取消时不得请求后端,确认提交期间操作按钮禁用并显示处理中状态。
- 单条成功弹窗展示真实返回的当前状态和 `manualRetryCount`;接口失败时弹窗展示错误,并提醒先刷新核对人工次数再决定是否重试,不能静默失败或诱导重复提交。
- 筛选区使用平台共享查询控件宽度;桌面端空间不足时条件按完整控件自然换行,不得把关键字、日期、状态、类型、应用和操作按钮挤压在同一行;移动端条件整行展示,查询与重置按钮清晰可操作。
### TC-GW-015 下游投递指数退避
- 优先级:P1
- 前置条件:存在一条可重复触发失败的 `CmppDownstreamDelivery`;系统已配置真实基础重试间隔和最大退避上限。
- 步骤:
1. 连续触发同一条下游投递失败 3 到 4 次。
2. 每次失败后记录 `nextRetryAt` 与当前时间的差值。
3. 持续失败直到接近退避上限。
- 预期结果:
- `nextRetryAt` 不是固定 60 秒,而是随失败次数递增。
- 退避间隔符合基础间隔的 2 倍递增趋势,并在达到最大退避上限后停止继续增大。
- 达到总重试上限后仍按既有规则转为 `failed`,不会无限重试。
### TC-GW-016 下游投递批量重投
- 优先级:P1
- 前置条件:当前页至少有多条 `pending``failed``CmppDownstreamDelivery`;运营端“下游投递记录”页面和真实批量重投接口可用。
- 步骤:
1. 在页面勾选多条可重投记录。
2. 点击“批量重投”。
3. 在平台确认弹窗中取消一次,确认未调用接口;再次打开并确认,检查提交期间防重复状态。
4. 检查后端返回的成功/失败汇总和逐条失败原因,并刷新列表。
- 预期结果:
- 页面调用真实 `/api/admin/operations/downstream-deliveries/requeue` 批量接口,不是前端逐条伪造结果。
- 后端逐条执行真实重投,返回 `total/successCount/failedCount/results`
- 成功和失败记录都会保留真实后端状态与错误信息;空选择时接口拒绝执行。
- 批量确认弹窗展示所选条数和重复处理风险;结果弹窗始终展示总数、成功数和失败数,部分失败时列出真实 `results[].errorMessage`,全成功时也不能静默关闭或只刷新列表。
### TC-GW-017 下游投递告警统一聚合
- 优先级:P1
- 前置条件:真实 `CmppDownstreamDelivery` 中准备阈值内/外的 `pending`、未超时/已超过 `ackDeadlineAt``awaiting_ack`、最近窗口内/外的 `failed/unconfirmed/rejected` 及正常 `delivered` 记录,且覆盖多个应用。
- 步骤:
1. 访问运营端 Dashboard、下游投递记录页和右上角待审核通知区域。
2. 调用真实 `/api/admin/operations/dashboard/statistics`,核对返回的下游投递告警聚合。
3. 打开右上角“待审核任务”,核对菜单和总数只包含审核业务。
- 预期结果:
- Dashboard 返回真实 `downstreamDeliverySummary`,至少包含 `pending/failed/delivered/stalledPending/stalledAck/recentFailed/alertCount`
- `alertCount` 精确等于“超阈值 pending + 超时 awaiting_ack + 最近窗口内 failed/unconfirmed/rejected”,阈值内 pending、未超时 awaiting_ack、历史失败和 delivered 不计入。
- 运营看板的“下游投递告警”数量与下游投递 Dashboard 在同一筛选范围下一致,不是前端写死值。
- 右上角“待审核任务”不出现下游投递告警菜单或数字;下游异常从运营看板或下游投递记录页进入处理。
### TC-GW-018 下游投递 Dashboard 聚合视图
- 优先级:P1
- 前置条件:真实 `CmppDownstreamDelivery` 中存在多应用、多类型和多重试次数的记录,至少覆盖 `receipt/uplink``pending/delivered/failed`
- 步骤:
1. 打开运营端“下游投递记录”页面,查看顶部总览卡片、类型分布、重试压力和应用告警排行。
2. 调用真实 `/api/admin/operations/downstream-deliveries/dashboard`,核对 `summary/typeBreakdown/retryBuckets/topApplications`
3. 切换应用和类型筛选,确认顶部 Dashboard 与下方记录列表同时切换到同一筛选范围。
- 预期结果:
- 顶部 Dashboard 必须来自真实聚合接口,不能由当前页列表条目在前端临时汇总。
- `summary``total/pending/awaitingAck/delivered/failed/unconfirmed/rejected/stalledPending/stalledAck/recentFailed/alertCount` 与数据库真实结果一致。
- `typeBreakdown` 能正确区分 `receipt``uplink` 的状态分布。
- `retryBuckets` 真实反映 `pending/failed` 记录的重试压力分布。
- `topApplications` 使用与 `summary.alertCount` 相同的时间窗和状态条件统计,各应用告警数之和与同范围总告警一致,并以告警量优先排序。
### TC-GW-019 下游在线账号 Presence 持久化
- 优先级:P1
- 前置条件:Gateway 已配置真实 `REDIS_URL`;客户端应用存在可用的 6 位 `cmppAccount`Gateway inbound 服务可正常接收 bind 和 submit。
- 步骤:
1. 使用真实 CMPP 客户端账号 bind Gateway。
2. 发送一条 submit,并触发至少一次下游回执或上行下发。
3. 检查 Redis 中该账号的下游 presence 记录。
4. 断开连接或触发发送失败清理后,再次检查 Redis。
- 预期结果:
- bind 成功后,Redis 中存在该 `cmppAccount` 的 presence 记录,不再只保存在 Gateway 内存 map。
- presence 至少包含账号、Gateway 实例标识、最近更新时间等信息。
- submit 或下游投递后,presence 的最近活跃时间会刷新。
- 连接清理后,presence 会被删除或过期,不把离线账号长期误判为在线。
### TC-GW-020 Gateway 恢复候选视图
- 优先级:P1
- 前置条件:Gateway 已配置真实 `REDIS_URL`;Redis 中已有部分下游账号 presence;另有至少一个账号当前在 Gateway 内存中处于在线状态。
- 步骤:
1. 重启 Gateway。
2. 观察 Gateway 启动日志中的恢复候选加载结果。
3. 调用 `GET /downstream/recovery-candidates`
4. 比对 Redis presence 和当前在线账号,确认返回候选列表。
- 预期结果:
- Gateway 启动后会读取 Redis presence,不再完全依赖进程内存冷启动。
- `/downstream/recovery-candidates` 返回恢复候选账号视图,至少包含账号、实例标识、状态、最近更新时间。
- 当前内存在线账号与 Redis presence 会合并成同一候选视图。
- 本阶段只提供恢复候选视图,不应误报为“已自动补投所有 pending 下游投递”。
### TC-GW-021 Gateway 重启后的 pending 恢复
- 优先级:P0
- 前置条件:真实 `CmppDownstreamDelivery` 中存在某账号的 `pending` 回执或上行;Redis presence 中保留该账号最近在线记录;Gateway 可正常重启。
- 步骤:
1. 让客户账号先在线并制造至少一条 `pending` 下游投递。
2. 重启 Gateway。
3. 检查 Gateway 启动后是否按恢复候选账号重新拉取 pending。
4. 若客户已重新 bind,则观察 pending 是否继续投递成功;若客户未重连,则观察记录是否仍保持 `pending`
- 预期结果:
- Gateway 重启后会重新尝试按恢复候选账号拉取真实 pending 下游投递。
- 客户重新 bind 后,pending 回执/上行可继续投递,不依赖重启前的内存连接映射。
- 若客户尚未重连,记录应继续保留为 `pending`,不能仅因 Gateway 重启或当前无连接就错误转成 `failed`
- 恢复执行基于真实后端 `CmppDownstreamDelivery`,不是前端或 Gateway 内存伪造状态。
### TC-GW-022 Gateway 恢复退避与状态审计
- 优先级:P1
- 前置条件:Gateway 已配置真实 `REDIS_URL`;存在可恢复账号;能人为制造“客户未重连”或“拉取 pending 失败”等恢复异常。
- 步骤:
1. 触发某账号恢复一次,但让客户保持未连接,或让 pending 拉取接口暂时失败。
2. 连续观察两轮恢复周期,检查是否出现对同一账号的高频重复恢复。
3. 调用 `GET /downstream/recovery-statuses` 查看恢复状态。
4. 恢复客户连接后,再次观察状态是否转为成功。
- 预期结果:
- 同一账号恢复过程中有恢复锁,不能并发重复恢复。
- 恢复失败或等待连接后会进入退避,下一轮不会无节制重复尝试。
- `/downstream/recovery-statuses` 能返回真实恢复状态、尝试次数、下一次可恢复时间和错误原因。
- 客户恢复连接后,后续状态可转为 `success`,而不是长期卡在错误状态。
### TC-GW-023 Gateway 恢复总览接口
- 优先级:P2
- 前置条件:Gateway 已配置真实 `REDIS_URL`;恢复候选与恢复状态已有真实数据。
- 步骤:
1. 调用 `GET /downstream/recovery-candidates``GET /downstream/recovery-statuses`
2. 调用 `GET /downstream/recovery-overview`
3. 比较总览接口与两个明细接口返回结果。
- 预期结果:
- `/downstream/recovery-overview` 同时返回候选账号列表和恢复状态列表。
- 总览接口中的 `candidates/statuses` 与两个明细接口真实结果一致,不允许返回静态拼装样例。
- 运维可仅通过总览接口快速判断“哪些账号待恢复、哪些账号处于退避或错误状态”。
### TC-GW-024 恢复状态回流与运营端展示
- 优先级:P1
- 前置条件:Gateway 已产生至少一条真实恢复状态;NestJS API、PostgreSQL 和运营端页面可访问。
- 步骤:
1. 触发某账号恢复状态变化,例如 `waiting_connection``success``failed`
2. 检查 Gateway 是否调用 `/api/gateway/events/downstream/recovery-status`
3. 查询数据库 `GatewayDownstreamRecoveryStatus`
4. 打开运营端“恢复状态管理”页面,查看恢复摘要、恢复状态列表和详情弹窗。
5. 按失败分类筛选,例如“客户未连接”“退避等待”“恢复执行失败”。
6. 使用当前筛选条件执行 CSV 导出。
- 预期结果:
- 恢复状态会从 Gateway 真实回流到 NestJS,并持久化到 PostgreSQL,不只停留在 Redis 或 Gateway 控制面。
- `GatewayDownstreamRecoveryStatus` 至少能查到账号、状态、失败分类、尝试次数、下一次恢复时间、错误原因、应用和企业关联。
- 运营端页面展示的数据来自真实 API/数据库,不是前端本地拼装;详情接口返回字段与数据库一致。
- 失败分类分布来自后端聚合,筛选后列表与统计同步变化。
- 导出文件来自真实后端接口,包含失败分类字段,内容与当前筛选结果一致。
- 页面刷新后恢复状态仍然存在,可继续用于生产排查。
- 页面解释恢复状态与逐条下游投递记录的用途差异;恢复状态和下游投递记录默认均选择近 7 天。
- 恢复状态按更新时间区间筛选,摘要、失败分类、列表和 CSV 导出使用同一时间口径;列表标题与外框保持正常内边距,最后错误/跳过原因列具备可读宽度。
- 筛选区复用平台共享查询控件宽度;关键字、日期、状态、失败分类、应用和操作按钮在桌面端按可用空间自然换行,移动端条件整行展示,不出现控件压缩、重叠、截断或按钮混入字段的问题。
### TC-GW-025 多 Gateway 恢复抢占协调
- 优先级:P0
- 前置条件:Redis 使用真实实例;至少准备两个不同 `GATEWAY_INSTANCE_ID` 的 Gateway 进程或可重复调用恢复锁逻辑的测试环境。
- 步骤:
1. Gateway-A 对同一 `cmppAccount` 发起 pending 恢复,获取 Redis token 租约锁。
2. 在 Gateway-A 未完成前,Gateway-B 对同一账号发起恢复,应被识别为 `lock_contended`
3. 等待 Gateway-A 锁过期后,Gateway-B 再次发起恢复,应能接管并获得新的锁 token。
4. 模拟 Gateway-A 迟到完成恢复。
5. 查看 Redis 锁、Gateway 恢复状态、NestJS `GatewayDownstreamRecoveryStatus` 和运营端“恢复状态管理”详情。
- 预期结果:
- 同一账号同一时间只能由一个 Gateway 实例持有恢复锁。
- 迟到的旧实例完成恢复时,因 token 不匹配不能释放新实例锁,也不能覆盖新实例恢复状态。
- 锁冲突、锁丢失等场景会以 `failureCategory=lock_contended``lock_lost` 进入真实恢复状态。
- `lockOwner/lockExpiresAt` 会回流到 PostgreSQL,并在运营端详情/列表中可见。
### TC-GW-026 长短信分片补偿审计
- 优先级:P0
- 前置条件:真实 PostgreSQL、Redis、NestJS API、Go Gateway 和上游 SMSC 模拟器均已启动;存在可用企业、应用、签名、模板、通道组和在线上游通道。
- 步骤:
1. 通过客户 CMPP 或发送接口提交一条需要 UDH 分片的长短信。
2. 确认 Gateway 向上游 SMSC 逐片提交,并在 `SubmitResult.segments[]` 中回传每个分片的 `segmentIndex/sequenceId/gatewayMessageId/submitStatus/submittedAt`
3. 查询数据库 `SmsMessageSegmentAudit`,确认同一平台短信记录下有对应分片审计行。
4. 模拟部分分片或全部分片回执,检查 NestJS 是否按 `gatewayMessageId` 回填分片回执状态。
5. 对同一短信触发重投或补偿提交,检查新 `submitId` 的分片审计是否保留历史 attempt 与 `compensationType`
6. 打开运营端短信记录详情,查看“分片补偿审计”列表。
- 预期结果:
- 分片审计来自真实 Gateway SubmitResult、NestJS API 和 PostgreSQL,不允许前端静态拼装。
- 每个分片至少记录分片序号、总片数、submitId、sequenceId、上游 MsgId、提交状态和提交时间。
- 回执按分片上游 MsgId 回填到对应审计行,迟到或失败回执不得覆盖短信最终 delivered 状态。
- 重投/补偿产生的新 submitId 与历史 submitId 可以并存审计,运营端能看到补偿归因。
- 当前第一版只要求分片级审计可追踪;按单个分片自动重投和分片级人工重投另行验收。
### TC-GW-027 共享接入号上行人工认领
- 优先级:P0
- 前置条件:真实 PostgreSQL、NestJS API、Go Gateway 和客户侧下游 CMPP 连接可用;至少两个应用共享同一接入号或同一手机号时间窗口内存在多条候选下发记录。
- 步骤:
1. 模拟一条不携带 messageId 的普通上行 Deliver,接入号或手机号时间窗口可匹配多个应用/下发记录。
2. 检查 `SmsUplinkMessage.matchStatus` 是否为 `ambiguous`,并查询 `SmsUplinkMatchCandidate` 候选。
3. 打开运营端“短信上行记录”详情,查看候选企业、候选应用、候选来源、置信度、候选下发短信和候选原因。
4. 选择正确候选执行“认领并推送”。
5. 查询 `SmsUplinkMessage``SmsUplinkMatchCandidate``CmppDownstreamDelivery` 和操作日志。
6. 若客户 CMPP 连接在线,检查 Gateway 是否尝试向认领应用下发普通上行 Deliver;若客户离线,检查待投递记录是否保留 pending/failed 重试状态。
- 预期结果:
- 多候选上行不会误推给任意客户应用,必须先进入 `ambiguous` 并保留候选。
- 候选来自真实接入号路由或手机号时间窗口下发记录,不允许前端静态生成。
- 人工认领后上行记录更新为 `matched`,写入 tenant/application/messageRecord 关联。
- 被选候选状态变为 `claimed`,其他 pending 候选变为 `rejected`,认领动作写入操作日志。
- 认领后创建真实 `CmppDownstreamDelivery(deliveryType=uplink)`,并按现有下游投递链路在线推送或离线保留重试。
### TC-GW-028 下游人工重投并发认领与中断恢复
- 优先级:P0
- 前置条件:真实 PostgreSQL、NestJS API 和 Gateway 控制面可用;准备一条 failed/pending 下游投递记录。
- 步骤:
1. 两个运营请求同时重投同一记录,并让 Gateway pending 恢复扫描同时运行。
2. 检查数据库状态、人工次数和 Gateway 控制面调用次数。
3. 另构造一条停留在 `manual_requeueing` 且超过恢复阈值的记录,运行后台扫描。
- 预期结果:
- `id + status + updatedAt` 条件更新只允许一个运营请求认领;另一个返回明确冲突。
- 认领期间状态为 `manual_requeueing`,不进入 Gateway 的 pending 拉取结果,同一轮只调用一次控制面。
- 人工次数只增加一次;进程中断的陈旧认领自动恢复为 pending,随后由 Gateway 单一路径补投。
### TC-GW-029 Gateway提交异常幂等重入队与宕机恢复
- 优先级:P0
- 前置条件:真实 PostgreSQL、Redis Stream 和 NestJS API 可用;存在 pending Gateway 提交异常记录。
- 步骤:
1. 人工重新入队,在 Redis XADD 成功后、数据库写回 requeued 前模拟进程退出。
2. 等待陈旧 requeueing 恢复扫描,再重复调用相同幂等发布。
3. Gateway 再次上报原始 streamMessageId,并在恢复期间回传 SubmitResult。
- 预期结果:
- 恢复和重复调用返回同一个 Redis Stream IDStream 只有一个 SubmitCommand。
- 数据库最终为 requeued 或被更早 SubmitResult 闭环为 resolved,人工次数只增加一次。
- 重复异常报告不得把 requeued/resolved 回退为 pending,迟到恢复不得覆盖 resolved。
### TC-SEND-021 优先队列插队发送
- 优先级:P0
- 前置条件:存在普通队列应用 `app-normal` 和优先队列应用 `app-priority`;两者企业状态、应用状态、签名、模板、报备、余额、通道组、通道连接均可用;Redis/BullMQ 使用真实本地服务。
- 步骤:
1. 使用 `app-normal` 连续提交一批普通队列短信,使普通队列形成可观察积压。
2. 在普通队列积压未清空时,使用 `app-priority` 提交少量优先队列短信。
3. 观察数据库 message_record、BullMQ job、Send Worker 日志、submit trace 和 Gateway SubmitCommand 顺序。
4. 等待两类消息处理完成。
- 预期结果:
- 普通队列和优先队列消息均写入真实数据库,记录包含 queuePriority 或等价可追踪字段。
- 优先队列消息在普通队列已有积压时更早被 Send Worker 消费并提交 Gateway。
- 优先队列不绕过模板/签名/报备/余额/风控/通道组路由/通道限速/Gateway 连接校验。
- 普通队列后续能继续恢复消费,不出现永久积压或重复提交。
- trace 中可区分队列等级、入队时间、消费时间和 submit 顺序。
## 10. 契约与队列用例
### TC-CONTRACT-001 SubmitCommand Schema 校验
- 优先级:P0
- 步骤:运行 `npm run spike:contracts`
- 预期结果:`submit-command.json` 通过 schema 校验。
### TC-CONTRACT-002 SubmitResult Schema 校验
- 优先级:P0
- 步骤:运行 `npm run spike:contracts`
- 预期结果:`submit-result.json` 通过 schema 校验。
### TC-CONTRACT-003 ReceiptEvent Schema 校验
- 优先级:P0
- 步骤:运行 `npm run spike:contracts`
- 预期结果:`receipt-event.json` 通过 schema 校验。
### TC-CONTRACT-004 UplinkEvent Schema 校验
- 优先级:P0
- 步骤:运行 `npm run spike:contracts`
- 预期结果:`uplink-event.json` 通过 schema 校验。
### TC-CONTRACT-005 SubmitCommand 队列等级字段校验
- 优先级:P0
- 前置条件:SubmitCommand 契约已扩展 queuePriority、priority 或 queueName 字段。
- 步骤:运行 `npm run spike:contracts`
- 预期结果:
- SubmitCommand 示例覆盖普通队列和优先队列。
- schema 明确允许的队列等级取值,不接受未知等级。
- NestJS 生产者和 Gateway/Worker 消费者使用同一字段语义。
## 11. 端到端 Smoke 用例
### TC-E2E-001 核心发送闭环
- 优先级:P0
- 前置条件:使用测试替身或本地 PostgreSQL/Redis 环境。
- 步骤:
1. 创建租户、应用、签名、模板、通道、路由。
2. 审核签名和模板通过。
3. 创建发送任务。
4. 发送入队。
5. 模拟 Gateway submit accepted。
6. 模拟 receipt delivered。
7. 查询 trace 和 reconciliation。
- 预期结果:
- 任务从 created/ready 流转到 finished。
- 单条短信状态为 delivered。
- trace 链路完整。
- 对账差异为 0。
### TC-E2E-002 风控人工审核闭环
- 优先级:P0
- 步骤:
1. 提交命中人工审核规则的发送任务。
2. 运营端查看审核原因。
3. 审核通过。
4. 发送入队并完成回执。
- 预期结果:
- 审核前不入队。
- 审核原因包含命中规则。
- 审核通过后进入发送链路。
### TC-E2E-003 失败退款闭环
- 优先级:P0
- 步骤:
1. 创建余额充足的发送任务。
2. 发送前冻结或 submit 成功扣费。
3. 模拟最终失败回执。
4. 查询账单流水和对账。
- 预期结果:
- 失败短信触发退款。
- 账务流水可追溯。
- 对账 diff 为 0。
## 12. 前端 Smoke 用例
### TC-WEB-001 客户端主页面加载
- 优先级:P1
- 步骤:打开客户端工作台、短信发送、批量任务、发送详情、上行短信、账单流水。
- 预期结果:
- 页面无白屏。
- 关键表格、筛选项、按钮可见。
- 控制台无阻断错误。
### TC-WEB-002 运营端主页面加载
- 优先级:P1
- 步骤:打开运营看板、发送监控、短信审核、通道管理、报备任务、短信记录、账单流水。
- 预期结果:
- 页面无白屏。
- 表格和操作按钮可见。
- 彩信相关页面仍保持第一版边界,不进入短信主链路。
### TC-WEB-003 响应式 Smoke
- 优先级:P2
- 步骤:在桌面宽屏和移动宽度打开核心页面。
- 预期结果:
- 文本不重叠。
- 表格或卡片可滚动/适配。
- 主要操作按钮不被遮挡。
## 13. 性能 Smoke 用例
### TC-PERF-001 BullMQ 500 TPS Smoke
- 优先级:P0
- 步骤:运行 `npm run spike:bullmq`
- 预期结果:
- 15000 条消息处理完成。
- endToEndTps 不低于 500。
- submitResults 和 receiptEvents 均等于 15000。
### TC-PERF-002 队列积压恢复
- 优先级:P1
- 步骤:
1. 连续提交 15000 条消息。
2. 观察处理完成时间和队列积压。
- 预期结果:
- 压测停止后队列可恢复到无积压。
- 无重复最终状态。
- 错误率满足阶段 0/8 性能报告要求。
### TC-PERF-003 混合优先级队列 Smoke
- 优先级:P0
- 前置条件:Redis/BullMQ 可用,准备普通队列和优先队列应用。
- 步骤:
1. 先提交一批普通队列消息制造积压。
2. 再提交优先队列消息。
3. 持续提交少量优先队列消息,同时观察普通队列恢复。
- 预期结果:
- 优先队列消息消费延迟明显低于已有普通队列积压。
- 普通队列不会被永久饿死。
- 端到端吞吐仍满足第一版性能 smoke 口径。
## 14. 业务闭环补充用例
### TC-CERT-001 企业认证资料提交
- 优先级:P0
- 前置条件:企业处于未认证状态,客户端企业管理员已登录。
- 步骤:
1. 打开企业认证页面。
2. 填写企业名称、统一社会信用代码、联系人、联系电话。
3. 上传营业执照和授权材料,提交认证。
4. 打开客户端工作台和企业认证详情。
- 预期结果:
- 企业认证状态从未认证变为 pending。
- 认证资料、文件对象、提交人和提交时间保存。
- 客户端可查看待审核状态,不允许重复提交相同版本资料。
- 系统日志记录企业认证提交动作。
### TC-CERT-002 企业认证审核通过后开放发送能力
- 优先级:P0
- 前置条件:企业认证状态为 pending,短信应用/签名/模板已准备好。
- 步骤:
1. 运营审核员查看企业认证资料。
2. 审核通过。
3. 客户端刷新企业认证状态。
4. 客户端创建或提交短信发送任务。
- 预期结果:
- 企业认证状态变为 approved。
- 审核记录包含审核人、审核时间、审核动作。
- 客户端可见已认证状态。
- 受认证约束的发送能力开放,发送任务可进入后续风控/计费/发送链路。
- 系统日志记录审核通过动作。
### TC-CERT-003 企业认证驳回与重新提交
- 优先级:P0
- 前置条件:企业认证状态为 pending。
- 步骤:
1. 运营审核员填写驳回原因并驳回。
2. 客户端查看驳回原因。
3. 客户端修改资料并重新提交。
4. 运营端再次审核通过。
- 预期结果:
- 驳回后状态为 rejected,驳回原因对客户端可见。
- 驳回状态下,受认证约束的发送能力被阻断,并给出认证未通过原因。
- 重新提交后状态回到 pending,保留历史审核记录。
- 最终通过后可正常发送。
### TC-CERT-004 企业停用对发送的影响
- 优先级:P0
- 前置条件:企业已认证并存在可发送资源。
- 步骤:
1. 运营端将企业状态改为 disabled。
2. 客户端尝试创建立即发送任务。
3. 客户端尝试创建定时发送任务。
4. 到达已有定时任务执行时间。
- 预期结果:
- 新建立即任务被拒绝,原因包含企业已停用。
- 新建定时任务被拒绝。
- 已存在但未执行的定时任务到点前重新校验企业状态,企业停用时不入队,任务变为 rejected/canceled。
- 系统日志记录企业停用和发送阻断。
### TC-TEMPLATE-001 多变量模板识别与顺序展示
- 优先级:P0
- 前置条件:存在 active 应用和可用签名。
- 步骤:
1. 创建模板 `尊敬的${name},您的订单${orderNo}将于${date}送达,验证码${code}`
2. 保存模板并查看变量列表。
3. 提交审核并由运营端审核通过。
4. 客户端进入发送页选择该模板。
- 预期结果:
- 系统识别 `name``orderNo``date``code` 四个变量。
- 变量不重复,展示顺序与模板中首次出现顺序一致。
- 审核通过后模板可被选择发送。
- 系统日志记录模板创建、提交审核、审核通过。
### TC-TEMPLATE-002 多变量完整填充发送成功
- 优先级:P0
- 前置条件:多变量模板审核通过,签名报备通过,账户余额充足。
- 步骤:
1. 选择多变量模板。
2. 填写全部变量:`name``orderNo``date``code`
3. 输入合法手机号并提交立即发送。
4. 模拟 submit accepted 和 delivered 回执。
5. 查询发送详情、trace 和计费记录。
- 预期结果:
- 发送内容正确替换所有变量。
- 内容长度按替换后的真实内容计费。
- 生成批量任务、手机号记录、提交记录、回执记录和计费记录。
- trace 中可看到模板、变量、messageId、submitId、gatewayMessageId。
### TC-TEMPLATE-003 多变量缺失、空值和多传
- 优先级:P0
- 前置条件:多变量模板审核通过。
- 步骤:
1. 缺少 `orderNo` 提交发送。
2.`date` 传为空字符串提交发送。
3. 额外传入未定义变量 `coupon` 提交发送。
4. 查看风控命中和客户端错误展示。
- 预期结果:
- 缺少必填变量命中模板变量异常。
- 必填变量为空按缺失或格式异常处理。
- 多传变量命中模板变量异常或被明确提示不允许。
- 任务不入队,错误原因包含变量名。
- 不生成冻结/扣费流水。
### TC-TEMPLATE-004 多变量重复出现只需填写一次
- 优先级:P1
- 前置条件:模板内容为 `${name}您好,${name}的验证码为${code}`
- 步骤:
1. 保存模板并查看变量列表。
2. 发送时只填写一次 `name` 和一次 `code`
3. 提交发送。
- 预期结果:
- 变量列表只展示一个 `name`
- 发送内容中两处 `${name}` 均被替换。
- 计费按最终内容长度计算。
### TC-TEMPLATE-005 变量值超长导致计费条数变化
- 优先级:P1
- 前置条件:模板审核通过,单价已配置。
- 步骤:
1. 使用短变量值预估费用。
2. 使用超长变量值,使最终内容从 1 条变为 2 条或更多。
3. 提交发送。
- 预期结果:
- 费用预估按最终替换内容计算。
- 发送前账户校验使用最终计费条数。
- 短信计费记录的 contentLength、billingUnits、amountCents 与最终内容一致。
### TC-IMPORT-001 CSV 导入发送成功闭环
- 优先级:P0
- 前置条件:模板审核通过,账户余额充足,准备 UTF-8 CSV 文件,包含手机号和变量列。
- 步骤:
1. 在发送页选择文件导入。
2. 上传 CSV,字段包含 `phone,name,code`
3. 系统解析并展示导入总数、有效数、无效数、重复数。
4. 确认提交发送。
5. 模拟 Gateway submit 和 receipt。
6. 查询批量任务、发送详情、trace、账单流水。
- 预期结果:
- CSV 解析成功,变量列映射到模板变量。
- 每个有效手机号生成一条短信记录。
- 无效和重复数据展示在导入结果中,不进入发送或按配置处理。
- 生成任务、明细、提交记录、回执记录、计费记录和账务流水。
### TC-IMPORT-002 TXT 导入号码发送
- 优先级:P0
- 前置条件:无变量模板或变量使用统一值。
- 步骤:
1. 上传 TXT 文件,号码以换行、逗号、空格混合分隔。
2. 预览解析结果。
3. 提交发送。
- 预期结果:
- 系统正确拆分号码。
- 去除空行和前后空格。
- 合法号码进入发送,非法号码展示原因。
- 生成批量任务和手机号记录。
### TC-IMPORT-003 GBK CSV 导入兼容
- 优先级:P1
- 前置条件:准备 GBK 编码 CSV,包含中文变量值。
- 步骤:
1. 上传 GBK CSV。
2. 预览变量值。
3. 提交发送并查看发送内容。
- 预期结果:
- 中文内容不乱码。
- 变量替换正确。
- 计费长度按正确解码后的内容计算。
### TC-IMPORT-004 导入文件超过 20 MB
- 优先级:P0
- 前置条件:准备大于 20 MB 的 CSV/TXT 文件。
- 步骤:上传文件。
- 预期结果:
- 上传或解析前被拒绝。
- 客户端展示文件大小超限。
- 不创建批量任务,不生成计费或发送记录。
- 系统日志记录导入失败原因。
### TC-IMPORT-005 导入文件中含重复、非法、黑名单号码
- 优先级:P0
- 前置条件:文件包含重复号码、非法号码、企业黑名单号码、全局黑名单号码。
- 步骤:
1. 上传文件。
2. 查看导入分析。
3. 提交发送。
4. 查看风控命中记录和发送明细。
- 预期结果:
- 导入分析展示总数、重复数、非法数、黑名单命中数。
- 重复率、非法率、黑名单率进入风控评估。
- 命中拒绝规则时任务 rejected,不入队。
- 命中人工审核规则时任务 pending_review,审核原因展示具体指标。
### TC-IMPORT-006 导入变量列缺失
- 优先级:P0
- 前置条件:模板要求 `name``code`CSV 只包含 `phone,name`
- 步骤:
1. 上传 CSV。
2. 尝试提交发送。
- 预期结果:
- 导入预览提示缺少 `code` 列。
- 不允许提交,或提交后风控变量异常直接拒绝。
- 不生成发送队列,不产生扣费。
### TC-CONTENT-001 发送内容包含控制字符
- 优先级:P0
- 前置条件:模板或变量值中包含不可见控制字符,例如 `\u0000``\u001F`
- 步骤:
1. 输入含控制字符的变量值。
2. 查看发送预览。
3. 提交发送。
- 预期结果:
- 客户端明确标识或提示非法字符位置。
- 后端校验拒绝或清洗策略明确且一致。
- 若拒绝,不创建可发送状态任务,不计费。
- 若清洗,预览内容、计费内容、实际发送内容必须一致。
- 系统日志记录非法字符校验结果。
### TC-CONTENT-002 emoji 和 UCS2 内容计费
- 优先级:P0
- 前置条件:内容或变量值包含 emoji 或非 GSM 字符。
- 步骤:
1. 输入包含 emoji 的短信内容。
2. 查看预估字数和计费条数。
3. 提交发送并查看短信计费记录。
- 预期结果:
- 系统明确展示特殊字符。
- 计费条数按第一版规则 70/67 执行,不被 emoji 拆分错误干扰。
- contentLength 与系统定义的字符统计口径一致。
- 发送记录、计费记录、trace 中内容一致。
### TC-CONTENT-003 换行、制表符和多空格展示
- 优先级:P1
- 前置条件:模板变量值包含换行、制表符或连续空格。
- 步骤:
1. 输入特殊空白字符。
2. 查看发送预览、审核详情和发送详情。
3. 提交发送。
- 预期结果:
- 页面展示不破版,特殊空白有可识别展示或被规范化。
- 计费按最终规范化后的内容计算。
- 审核详情和发送详情展示内容一致。
### TC-CONTENT-004 敏感词和非法字符同时命中
- 优先级:P0
- 前置条件:敏感词库包含 `测试敏感词`
- 步骤:
1. 发送内容同时包含敏感词和非法控制字符。
2. 提交发送。
- 预期结果:
- 任务被拒绝。
- 错误原因同时或按优先级展示敏感词、非法字符问题。
- 不入队,不冻结,不扣费。
- 风控命中或系统日志可追溯两个校验结果。
### TC-SCHEDULE-001 创建定时短信任务
- 优先级:P0
- 前置条件:发送资源审核和报备均通过,账户余额充足。
- 步骤:
1. 在发送页选择定时发送。
2. 设置发送时间为当前时间 10 分钟后。
3. 提交任务。
4. 查看批量任务列表和详情。
- 预期结果:
- 返回批量任务编号。
- 任务状态为 scheduled。
- 任务详情展示计划发送时间。
- 到点前不生成 Gateway SubmitCommand,不产生 submit 记录。
- 如采用发送前冻结,冻结流水生成;如采用到点前冻结,则无冻结流水但有费用预估。
### TC-SCHEDULE-002 定时任务到点发送并生成记录
- 优先级:P0
- 前置条件:存在 scheduled 任务,计划发送时间已到。
- 步骤:
1. 触发调度器或等待时间到达。
2. 观察任务状态。
3. 模拟 Gateway submit accepted 和 delivered。
4. 查询批量任务、发送详情、submit 记录、receipt 记录、trace、账单流水。
- 预期结果:
- 到点后任务重新校验应用、签名、模板、报备状态、账户余额和通道状态。
- 校验通过后任务进入 queued/sending。
- 按手机号生成发送记录或将已创建记录推进到 queued。
- 生成 SubmitCommand、SmsSubmitRecord、SmsReceiptRecord、SmsBillingRecord 和账务流水。
- 任务最终完成,成功数、失败数、未知数统计正确。
### TC-SCHEDULE-003 定时任务到点前取消
- 优先级:P0
- 前置条件:存在 scheduled 任务且未到执行时间。
- 步骤:
1. 客户端取消定时任务。
2. 查看任务详情和账单流水。
3. 到达原计划时间。
- 预期结果:
- 任务状态变为 canceled。
- 如已冻结费用,应生成 release 流水。
- 到点后不会入队,不生成提交记录。
- 系统日志记录取消动作。
### TC-SCHEDULE-004 定时任务到点时余额不足
- 优先级:P0
- 前置条件:创建 scheduled 任务时余额充足,到点前账户余额被其他任务消耗。
- 步骤:
1. 创建定时任务。
2. 调整或消耗账户余额至不足。
3. 到点触发调度。
- 预期结果:
- 到点前重新进行账户校验。
- 余额不足时任务不入队,状态变为 rejected/failed。
- 失败原因展示余额不足。
- 不生成扣费流水;如曾冻结则释放。
### TC-SCHEDULE-005 定时任务到点时模板或签名已失效
- 优先级:P0
- 前置条件:存在 scheduled 任务。
- 步骤:
1. 创建定时任务。
2. 到点前运营端驳回、停用或删除关联模板/签名。
3. 到点触发调度。
- 预期结果:
- 调度前重新校验模板和签名可用性。
- 关联资源不可用时任务不入队。
- 任务失败原因明确指出模板或签名不可用。
- 历史任务详情仍可展示原模板/签名快照或名称,不因删除而空白。
### TC-SCHEDULE-006 定时任务查看和筛选
- 优先级:P1
- 前置条件:存在 scheduled、queued、finished、canceled 多状态任务。
- 步骤:
1. 客户端按任务编号、应用、发送时间、状态查询。
2. 运营端按租户、应用、状态查询任务进度。
3. 打开定时任务详情。
- 预期结果:
- 查询条件准确生效。
- 定时任务详情展示计划发送时间、创建时间、创建人、号码总数、预估费用、当前状态。
- 到点执行后的状态变化在客户端和运营端一致。
### TC-SCHEDULE-007 多实例自动调度和原子认领
- 优先级:P0
- 前置条件:启动两个连接同一 PostgreSQL/Redis 的 API 实例,存在一条已到期 scheduled 任务。
- 步骤:
1. 不调用管理端手工派发接口,等待自动扫描周期。
2. 两个实例同时扫描同一任务。
3. 查询任务、冻结流水、短信记录和 BullMQ 作业。
- 预期结果:
- 到期任务自动进入 queued/sending。
- 仅一个实例原子认领成功。
- 每条短信只存在一个以消息记录 ID 为 jobId 的队列作业,余额只冻结一次。
### TC-SCHEDULE-008 调度中断、0 元任务和超时恢复
- 优先级:P0
- 前置条件:存在普通计费任务和客户单价为 0 的免费任务,调度认领超时阈值可缩短用于测试。
- 步骤:
1. 分别在冻结后、短信转 queued 后和部分作业入队后模拟进程退出或 Redis 不可用。
2. 恢复 API/Redis 并等待认领超时后再次扫描。
3. 重复执行恢复扫描。
- 预期结果:
- 陈旧的 scheduled_dispatching/scheduled_recovering 任务能够被唯一重新认领并完成入队。
- 已存在冻结流水时不重复冻结;0 元任务入队失败时保留可恢复状态而非错误终结。
- BullMQ jobId 幂等阻止重复作业,最终任务和消息状态一致。
### TC-LOG-001 登录和登出日志
- 优先级:P1
- 前置条件:存在客户端用户和运营端用户。
- 步骤:
1. 分别登录客户端和运营端。
2. 执行登出或 token 失效。
3. 查询系统日志。
- 预期结果:
- 登录日志记录用户、租户、IP、User-Agent、时间。
- 登录失败记录失败原因。
- 运营端可按用户、租户、动作查询。
### TC-LOG-002 配置变更日志
- 优先级:P0
- 前置条件:运营管理员和企业管理员均可操作配置。
- 步骤:
1. 创建、编辑、删除应用。
2. 创建、编辑、删除签名、模板、引流信息。
3. 创建、编辑、停用通道和路由规则。
4. 查询系统日志。
- 预期结果:
- 每个动作均记录 action、resource、resourceId、操作者、租户、时间。
- 日志 detail 包含关键变更字段的前后值或摘要。
- 客户端只能查看本企业相关日志,运营端可看全平台。
### TC-LOG-003 审核和报备日志
- 优先级:P0
- 步骤:
1. 执行企业认证审核、签名审核、模板审核、短信审核。
2. 生成报备任务、导出报备资料、导入回执。
3. 查询系统日志和业务审核记录。
- 预期结果:
- 审核动作有业务审核记录和系统日志两类证据。
- 报备动作有报备记录和系统日志两类证据。
- 日志可定位操作人、状态前后值和原因。
### TC-LOG-004 导入导出日志
- 优先级:P1
- 步骤:
1. 导入号码文件。
2. 导出发送明细或报备资料。
3. 导入报备回执。
4. 查询系统日志。
- 预期结果:
- 日志记录文件名、文件大小、行数、成功数、失败数、操作者、时间。
- 导出日志记录导出条件和导出文件 id。
- 导入失败也应记录失败原因。
### TC-DELETE-001 删除未被使用的签名
- 优先级:P1
- 前置条件:签名未关联模板或发送任务。
- 步骤:
1. 客户端或运营端删除签名。
2. 查询签名列表。
3. 尝试发送时选择该签名。
- 预期结果:
- 删除成功或状态变为 deleted。
- 列表默认不展示。
- 发送页不可选择该签名。
- 系统日志记录删除动作。
### TC-DELETE-002 删除已关联模板的签名
- 优先级:P0
- 前置条件:签名已关联审核通过模板。
- 步骤:
1. 尝试删除签名。
2. 如系统允许软删除,使用关联模板发起发送。
3. 查看模板列表和发送错误。
- 预期结果:
- 系统应阻止硬删除并提示存在关联模板,或执行软删除/停用。
- 被删除或停用签名不可用于新发送。
- 历史发送记录仍保留签名名称或快照。
- 系统日志记录删除失败或软删除动作。
### TC-DELETE-003 删除应用对发送的影响
- 优先级:P0
- 前置条件:应用下存在签名、模板、历史任务和 scheduled 任务。
- 步骤:
1. 删除或停用应用。
2. 尝试创建立即发送任务。
3. 到达 scheduled 任务执行时间。
4. 查询历史批量任务和发送明细。
- 预期结果:
- 新发送被阻断,原因包含应用不可用。
- 关联 scheduled 任务到点前重新校验应用状态,应用不可用时不入队。
- 历史任务和发送明细可查询,不因应用删除丢失。
- 系统日志记录应用删除/停用和发送阻断。
### TC-DELETE-004 删除模板对发送的影响
- 优先级:P0
- 前置条件:模板已审核通过并有历史任务。
- 步骤:
1. 删除或停用模板。
2. 发送页尝试选择该模板。
3. 使用已保存草稿或 scheduled 任务触发送。
4. 查询历史发送详情。
- 预期结果:
- 新发送和尚未创建真实任务的草稿不可选择已删除模板。
- 删除前已创建的 scheduled 任务到点时使用持久化快照继续入队;企业、应用或签名当前不可用时仍阻断。
- 历史发送详情仍展示原短信内容、模板名称或模板快照。
- 不影响历史计费和对账。
### TC-DELETE-005 删除引流信息字段
- 优先级:P0
- 前置条件:签名报备材料依赖某个引流信息字段。
- 步骤:
1. 运营端删除或停用引流字段。
2. 客户端编辑签名引流信息。
3. 生成或重新生成报备任务。
4. 使用该签名发送。
- 预期结果:
- 新签名资料不再要求已删除字段。
- 已存在报备材料保留历史值或标记字段已停用。
- 如通道仍要求该字段但客户资料缺失,报备任务无法通过或发送前校验失败。
- 失败原因明确指向缺少报备/引流资料。
### TC-DELETE-006 删除客户签名引流信息对报备和发送影响
- 优先级:P0
- 前置条件:签名已报备通过,且发送依赖引流信息。
- 步骤:
1. 客户端删除签名上的某项引流信息。
2. 查看签名报备状态。
3. 尝试使用该签名发送。
4. 运营端查看报备任务或报备记录。
- 预期结果:
- 删除关键引流信息后,签名报备状态应变为 waiting_material/pending 或标记需重新报备。
- 使用未重新报备通过的签名发送应被阻断或进入人工审核。
- 系统记录引流信息删除日志和报备状态变化记录。
### TC-REPORT-001 签名审核通过但未报备不能发送
- 优先级:P0
- 前置条件:签名 auditStatus=approvedreportStatus=waiting_material 或 pending。
- 步骤:
1. 客户端选择该签名和已审核模板。
2. 提交发送。
- 预期结果:
- 发送被阻断或进入人工审核,按第一版策略明确处理。
- 原因包含签名未完成通道报备。
- 不投递 Gateway SubmitCommand。
- 不扣费,或已冻结需释放。
### TC-REPORT-002 报备通过后允许发送
- 优先级:P0
- 前置条件:签名审核通过但报备未通过。
- 步骤:
1. 运营端导入报备成功回执。
2. 签名 reportStatus 变为 approved。
3. 客户端使用该签名发送。
4. 模拟 submit 和 receipt。
- 预期结果:
- 报备状态同步到签名详情和客户端列表。
- 发送可进入队列。
- 生成发送记录和计费流水。
### TC-REPORT-003 报备失败后阻断发送
- 优先级:P0
- 前置条件:签名已审核通过,报备任务导入失败回执。
- 步骤:
1. 确认签名 reportStatus=rejected。
2. 客户端使用该签名发送。
3. 运营端查看发送审核或风控记录。
- 预期结果:
- 发送被阻断,不入队。
- 客户端展示报备失败原因。
- 运营端可查询失败报备记录。
### TC-REPORT-004 报备状态从通过变为失败对 scheduled 任务的影响
- 优先级:P0
- 前置条件:签名 reportStatus=approved,存在未来执行的 scheduled 任务。
- 步骤:
1. 创建定时发送任务。
2. 到点前运营端将该签名通道报备状态改为 rejected 或 waiting_material。
3. 到点触发调度。
- 预期结果:
- 调度前重新校验报备状态。
- 报备状态不可用时任务不入队。
- 任务失败原因包含报备状态变化。
- 如已冻结费用,生成释放流水。
### TC-REPORT-005 多通道报备状态影响路由
- 优先级:P0
- 前置条件:通道 A 报备通过,通道 B 报备失败,通道组包含 A/B。
- 步骤:
1. 使用该签名发送,路由规则优先通道 A。
2. 停用通道 A 或模拟 A 不可用。
3. 系统尝试切换到通道 B。
- 预期结果:
- 通道 A 可用时正常发送。
- 切换备用通道前必须校验签名在备用通道的报备状态。
- 通道 B 报备失败时不能切换发送,应选择其他报备通过通道或失败并给出原因。
### TC-REPORT-006 引流信息字段变更触发重新报备
- 优先级:P1
- 前置条件:签名已在通道报备通过。
- 步骤:
1. 客户端修改签名引流信息中的关键字段。
2. 查看签名报备状态。
3. 运营端生成新的报备任务。
4. 新报备通过后再次发送。
- 预期结果:
- 修改关键引流信息后原报备状态失效或标记需重新报备。
- 重新报备前发送被阻断或进入人工审核。
- 新报备通过后恢复发送。
- 保留旧报备记录和新报备记录。
### TC-STATUS-001 已有历史任务不受配置删除错误覆盖
- 优先级:P0
- 前置条件:存在已完成发送任务,关联应用、签名、模板随后被删除或停用。
- 步骤:
1. 删除或停用应用、签名、模板。
2. 打开历史批量任务、发送详情、trace、对账。
- 预期结果:
- 历史任务仍可查询。
- 历史短信内容、手机号、计费条数、通道、回执、账务流水不丢失。
- trace 不因关联资源删除而报错。
- 对账结果不受配置删除影响。
### TC-STATUS-002 配置状态变化必须写入系统日志
- 优先级:P0
- 前置条件:准备应用、签名、模板、引流字段、通道、路由规则。
- 步骤:
1. 分别执行启用、停用、删除、恢复。
2. 对每次操作查询系统日志。
- 预期结果:
- 每次状态变化都有日志。
- 日志包含状态前后值。
- 日志能区分客户侧操作和运营侧操作。
- 日志 resourceId 可跳转或定位到原业务对象。
### TC-E2E-004 定时发送完整闭环
- 优先级:P0
- 步骤:
1. 企业认证通过。
2. 创建应用、签名、模板和报备材料。
3. 审核签名和模板,报备通过。
4. 充值账户。
5. 创建定时发送任务。
6. 到点触发送链路。
7. 模拟 submit accepted、receipt delivered、uplink。
8. 查询任务、发送详情、trace、账单流水、系统日志。
- 预期结果:
- 全链路状态流转完整。
- 发送和回执记录完整。
- 账务预估、冻结、扣费或释放逻辑正确。
- 系统日志覆盖认证、配置、审核、报备、发送、回执关键动作。
### TC-E2E-005 导入数据发送完整闭环
- 优先级:P0
- 步骤:
1. 使用多变量模板。
2. 上传 CSV,包含手机号和变量列。
3. 处理重复、非法、黑名单行。
4. 提交合法数据发送。
5. 模拟 submit 和 receipt。
6. 查询导入结果、批量任务、发送明细、trace、对账。
- 预期结果:
- 导入解析、变量映射、风控、计费、发送、回执、对账形成闭环。
- 被过滤或拒绝的数据有明确原因。
- 合法数据生成完整发送记录。
### TC-E2E-006 配置删除影响发送完整闭环
- 优先级:P0
- 步骤:
1. 创建并完成一条历史发送。
2. 创建一条未来定时发送。
3. 删除或停用应用、签名、模板、引流信息之一。
4. 尝试新建立即发送。
5. 等待定时任务到点。
6. 查询历史任务和日志。
- 预期结果:
- 新建发送被阻断。
- 定时任务到点重新校验并失败或取消。
- 历史发送可查询、可对账。
- 配置删除、发送阻断、定时任务失败均有日志。
### TC-DASHBOARD-001 客户端 Dashboard 今日发送数据准确
- 优先级:P0
- 前置条件:客户 A 当天存在 delivered 10 条、failed 3 条、unknown 2 条、timeout 1 条;客户 B 有任意发送数据。
- 步骤:
1. 使用客户 A 管理员登录客户端。
2. 打开客户端 Dashboard。
3. 查看今日发送量、成功量、失败量、未知量、成功率。
4. 点击今日发送量或成功率卡片跳转到发送明细。
5. 使用同样时间范围在发送明细中筛选核对。
- 预期结果:
- 今日发送量只统计客户 A 数据,不包含客户 B。
- 总量为 16,成功量为 10,失败量按 failed+timeout 口径为 4unknown 为 2。
- 成功率口径明确,若按 delivered/total,应为 62.5%。
- 卡片跳转后的列表筛选条件与 Dashboard 统计口径一致。
### TC-DASHBOARD-002 客户端 Dashboard 余额和可发送额度准确
- 优先级:P0
- 前置条件:客户 A 现金余额 10000 分;存在冻结、扣费、退款、释放流水。
- 步骤:
1. 打开客户端 Dashboard。
2. 查看现金余额和可发送额度。
3. 打开账单流水。
4. 按交易类型核对充值、冻结、扣费、退款、释放后的余额。
- 预期结果:
- Dashboard 余额与账户表和流水计算结果一致。
- 冻结金额不应被当作可用余额重复计算。
- 可发送额度等于现金余额,不叠加其他额度。
- 跳转账单流水后可核对组成明细。
### TC-DASHBOARD-003 客户端 Dashboard 待处理事项准确
- 优先级:P1
- 前置条件:客户 A 有待审核签名 2 个、待审核模板 3 个、待报备签名 1 个、pending_review 发送任务 4 个。
- 步骤:
1. 打开客户端 Dashboard。
2. 查看待审核/待处理事项数量。
3. 分别点击进入签名、模板、发送任务页面。
- 预期结果:
- Dashboard 数量与对应列表筛选结果一致。
- 只展示客户 A 的事项。
- 点击跳转后自动带入对应状态筛选。
### TC-DASHBOARD-004 运营端 Dashboard 全平台核心指标准确
- 优先级:P0
- 前置条件:准备多个客户、多通道、多状态短信记录和账务流水。
- 步骤:
1. 运营管理员打开运营端 Dashboard。
2. 查看总客户数、活跃客户数、今日发送量、成功率、失败率、待审核数量、账务收入。
3. 分别在客户列表、短信记录、审核列表、账单流水中按相同时间范围核对。
- 预期结果:
- 运营端 Dashboard 统计全平台数据。
- 各指标与明细列表聚合一致。
- 时间范围切换后所有指标同步刷新。
- 待审核数量按企业认证、签名、模板、短信审核分类可追溯。
### TC-DASHBOARD-005 运营端 Dashboard 按客户筛选准确
- 优先级:P0
- 前置条件:客户 A、客户 B 均有发送、账务和审核数据。
- 步骤:
1. 运营端 Dashboard 选择客户 A。
2. 查看发送趋势、状态分布、账务汇总、待审核。
3. 切换到客户 B。
4. 点击指标进入明细页。
- 预期结果:
- 客户筛选生效,A/B 数据互不混入。
- 明细页继承客户筛选条件。
- 账务汇总与客户账单流水一致。
### TC-DASHBOARD-006 运营端通道健康和 CMPP 连接指标展示
- 优先级:P0
- 前置条件:通道 A online 且连接数 2/2,通道 B disconnected 且连接数 0/2,通道 C auth_failed。
- 步骤:
1. 打开运营端 Dashboard 和发送监控。
2. 查看通道健康度、在线连接数、断线通道数、认证失败通道数、重连次数。
3. 点击通道健康卡片进入通道监控详情。
- 预期结果:
- Dashboard 展示的在线连接总数等于各通道 currentConnections 之和。
- 异常通道数量按连接状态准确分类。
- 明细页与 Dashboard 指标一致。
- 点击异常通道可查看错误原因和最近状态变化时间。
### TC-DASHBOARD-007 Dashboard 趋势图时间边界准确
- 优先级:P1
- 前置条件:准备跨日、跨小时发送记录,含时区边界数据。
- 步骤:
1. 在客户端和运营端分别选择今日、近 7 天、近 30 天。
2. 查看发送趋势图和成功率趋势。
3. 与数据库或明细列表按时间范围聚合结果核对。
4. 写入 UTC `01:00``01:59`(北京时间 `09:00``09:59`)的 `SmsMessageRecord.queuedAt` 样本,并分别在 PostgreSQL 会话时区为 UTC 和 `Asia/Shanghai` 时核对小时桶。
- 预期结果:
- 今日使用平台配置时区,不错算跨日数据。
- 近 7 天和近 30 天边界包含/排除规则明确。
- 趋势图每个点位与明细聚合一致。
- UTC `01:00``01:59` 的样本只计入北京时间 `09:00` 小时桶,不计入 `01:00`;结果不随 PostgreSQL 会话时区变化。
### TC-BILLING-006 运营端人工充值闭环
- 优先级:P0
- 前置条件:客户 A 已创建账户,运营管理员具备充值权限。
- 步骤:
1. 运营端进入客户详情或充值记录页面。
2. 发起人工充值,填写金额、短信条数、支付方式、备注、操作人。
3. 保存后查看充值记录。
4. 客户端查看 Dashboard 余额和账单流水。
5. 运营端查看账户余额、账单流水和系统日志。
- 预期结果:
- 生成 RechargeOrder,状态为 paid 或人工充值完成状态。
- 企业现金余额同步增加。
- 生成 account_transaction,类型为 recharge,关联 recharge_order。
- 客户端余额、账单流水即时可见。
- 运营端充值记录、账单流水、系统日志三处可追溯。
- 所有金额、余额和单价固定展示三位小数,例如 `¥1.000`
### TC-BILLING-007 人工充值金额和短信条数只填其一
- 优先级:P1
- 前置条件:客户 A 账户存在。
- 步骤:
1. 运营端只填写充值金额,不填写短信条数。
2. 再发起一笔只填写短信条数,不填写充值金额。
3. 查看账户和流水。
- 预期结果:
- 系统按填写金额增加或冲正现金余额。
- 未填写项按 0 处理,不产生脏数据。
- 流水金额和短信条数字段方向正确。
- 备注和操作人保留。
### TC-BILLING-008 人工充值撤销或冲正闭环
- 优先级:P0
- 前置条件:存在一笔人工充值,且客户尚未完全消费该充值额度。
- 步骤:
1. 运营端对人工充值发起撤销或冲正。
2. 填写冲正原因。
3. 查看账户余额、充值记录、账单流水、系统日志。
4. 客户端查看账单流水。
- 预期结果:
- 原充值记录状态变为 canceled/reversed,或生成一笔反向调整流水。
- 企业现金余额正确回退。
- 若余额已消费导致不能全额撤销,应提示不可撤销或只允许人工调整。
- 客户端和运营端均可看到冲正流水和原因。
- 系统日志记录冲正操作者和原因。
### TC-BILLING-009 人工充值权限和审批校验
- 优先级:P0
- 前置条件:存在运营管理员、运营审核员、无充值权限用户。
- 步骤:
1. 无充值权限用户访问人工充值入口。
2. 运营审核员尝试发起充值。
3. 运营管理员发起大额充值。
4. 若系统配置大额审批,执行审批通过或驳回。
- 预期结果:
- 无权限用户不能发起充值。
- 权限不足时返回明确错误并写入安全日志。
- 大额充值按审批规则进入 pending/approved/rejected。
- 审批通过后才更新账户余额,驳回不更新余额。
### TC-BILLING-010 人工充值后立即发送扣费
- 优先级:P0
- 前置条件:客户原余额不足,人工充值后余额足够。
- 步骤:
1. 客户端发送任务,确认余额不足被阻断。
2. 运营端进行人工充值。
3. 客户端重新提交同样发送任务。
4. 模拟 submit accepted 和 delivered。
5. 查询对账。
- 预期结果:
- 充值前发送失败且不扣费。
- 充值后发送可进入发送链路。
- 扣费流水与充值流水都可查询。
- reconciliation diff 为 0。
### TC-LOG-005 客户端系统日志展示范围
- 优先级:P0
- 前置条件:客户 A 和客户 B 均有登录、发送、导入、配置变更日志。
- 步骤:
1. 使用客户 A 管理员打开客户端系统日志。
2. 按动作、时间、操作者筛选。
3. 尝试通过 URL 或参数查询客户 B 日志。
- 预期结果:
- 客户端只展示客户 A 日志。
- 筛选条件准确生效。
- 日志字段包含时间、用户、动作、资源、结果、IP、User-Agent。
- 越权查询客户 B 日志失败。
### TC-LOG-006 客户端系统日志记录发送与导入
- 优先级:P0
- 前置条件:客户 A 可创建发送任务并导入号码文件。
- 步骤:
1. 客户端导入号码文件。
2. 创建立即发送任务。
3. 创建定时发送任务并取消。
4. 查看客户端系统日志。
- 预期结果:
- 导入日志记录文件名、行数、成功数、失败数。
- 发送日志记录任务编号、号码数、发送类型、结果。
- 取消定时任务记录任务编号和取消人。
- 日志中的资源 id 可定位到对应任务或导入批次。
### TC-LOG-007 运营端系统日志全平台查询
- 优先级:P0
- 前置条件:多个客户产生认证、审核、充值、通道、发送、报备日志。
- 步骤:
1. 运营管理员打开运营端系统日志。
2. 按客户、操作者、动作、资源类型、结果、时间查询。
3. 导出查询结果。
- 预期结果:
- 运营端可查询全平台日志。
- 客户筛选和动作筛选准确。
- 导出内容与当前筛选结果一致。
- 导出动作本身也写入系统日志。
### TC-LOG-008 运营端系统日志记录人工充值
- 优先级:P0
- 前置条件:运营管理员发起人工充值、冲正或调整。
- 步骤:
1. 执行人工充值。
2. 执行充值冲正或账户调整。
3. 在运营端系统日志中查询。
- 预期结果:
- 日志记录客户、金额、短信条数、订单号、流水号、操作者。
- 冲正日志记录原订单号、原因、前后余额摘要。
- 敏感字段按脱敏规则展示。
### TC-LOG-009 系统日志失败动作也必须记录
- 优先级:P0
- 前置条件:准备无权限用户、非法参数、余额不足、通道离线等失败场景。
- 步骤:
1. 触发无权限充值。
2. 触发余额不足发送。
3. 触发通道无在线连接发送。
4. 查询客户端和运营端系统日志。
- 预期结果:
- 失败动作同样记录日志。
- 日志 result/status 标识失败。
- 失败原因可读且与前端提示一致。
- 客户端只可见本客户失败日志,运营端可全平台查询。
### TC-LOG-010 高频运行事件不得放大系统日志
- 优先级:P0
- 前置条件:客户 CMPP 连接在线,Gateway 正常发送心跳并周期同步下游恢复状态。
- 步骤:
1. 建立一条客户 CMPP 连接并记录当前 `OperationLog` 数量。
2. 连续发送多次 heartbeat、Submit、Deliver 事件。
3. 连续上报仅时间、尝试次数或锁过期时间变化、业务状态未变化的恢复状态。
4. 触发连接断开,并将恢复状态从 waiting_connection 改为 running 或 failed。
- 预期结果:
- heartbeat、Submit、Deliver 仍更新连接表对应时间,但不新增系统日志。
- 周期恢复状态只更新 `GatewayDownstreamRecoveryStatus`,未发生审计字段变化时不新增系统日志。
- 连接建立/断开以及恢复状态、实例、锁持有者、失败分类或失败原因真实变化时各新增一条系统日志。
### TC-LOG-011 系统日志分页索引与归档安全
- 优先级:P0
- 前置条件:准备超过两页、覆盖 info/success/warning/error 的系统日志,并准备超过在线保留期的日志。
- 步骤:
1. 分别按级别、租户、模块、时间和关键词查询第一页、第二页。
2. 调用兼容审计接口并传入超大 pageSize。
3. 执行一次归档任务,再查询 `OperationLog``OperationLogArchive`
4. 模拟归档插入失败并重新执行。
- 预期结果:
- 级别筛选在数据库分页前生效,total、页数和当前页记录准确且排序稳定。
- 所有接口 pageSize 最大为 100,不存在无界全表返回。
- 到期日志按 `archiveMonth=YYYY-MM` 进入归档表,在线表只删除已成功归档的记录,原始 id 和详情不丢失。
- 归档使用有界小批量和 `SKIP LOCKED`;归档失败时源日志仍保留,不阻塞正常日志写入。
### TC-LOG-012 系统日志日期区间默认值与后端过滤
- 优先级:P1
- 前置条件:运营端和客户端均存在跨越7天以上的系统日志,通讯交互日志也存在跨日数据。
- 步骤:
1. 分别进入运营端“系统与操作日志”“通讯交互日志”和客户端“系统日志”。
2. 核对日期区间默认值,查询并翻页。
3. 改为自定义起止日期后再次查询;运营端同时导出系统与操作日志。
4. 点击重置。
- 预期结果:
- 三处日期区间初始和重置后均为北京时间近7天,允许通过日期控件选择任意合法区间。
- 请求真实携带`createdAtFrom/createdAtTo`,后端按北京时间当日00:00:00.000至结束日23:59:59.999过滤。
- 列表总数、分页和导出使用同一日期条件,不返回区间外数据。
### TC-CUSTOMER-001 运营端创建客户并初始化租户
- 优先级:P0
- 前置条件:运营管理员已登录。
- 步骤:
1. 运营端新建客户,填写客户名称、客户编码、联系人、手机号、邮箱、状态、备注。
2. 保存后打开客户详情。
3. 查看客户下应用、签名、模板、账户、认证资料、发送记录入口。
4. 使用该客户管理员账号登录客户端。
- 预期结果:
- 创建客户成功,同时生成或关联租户。
- 客户详情展示基础信息和业务入口。
- 客户管理员只能进入本客户租户上下文。
- 系统日志记录客户创建动作和操作者。
### TC-CUSTOMER-002 客户资料编辑影响展示但不破坏历史数据
- 优先级:P1
- 前置条件:客户已有应用、签名、模板和历史发送记录。
- 步骤:
1. 运营端修改客户名称、联系人、联系电话、备注。
2. 客户端刷新工作台和账号信息。
3. 运营端查看历史发送记录、账单流水、trace。
- 预期结果:
- 新客户资料在客户端和运营端同步展示。
- 历史发送记录、账单流水、trace 仍可查询。
- 历史记录中的 tenantId 不变化,必要时展示当前客户名称或历史快照。
- 系统日志记录修改前后关键字段。
### TC-CUSTOMER-003 客户停用阻断新发送
- 优先级:P0
- 前置条件:客户已认证且有可用应用、签名、模板、余额和 active 通道。
- 步骤:
1. 运营端将客户状态改为 disabled。
2. 客户端尝试创建立即发送任务。
3. 客户端尝试创建定时发送任务。
4. API 调用或 CMPP 接入尝试发送。
5. 查询系统日志和发送任务列表。
- 预期结果:
- 客户端、API、CMPP 接入的新发送均被阻断。
- 错误原因包含客户已停用。
- 不生成可发送状态任务,不入队,不扣费。
- 历史任务仍可查询。
- 系统日志记录客户停用和发送阻断。
### TC-CUSTOMER-004 客户停用对定时任务到点执行的影响
- 优先级:P0
- 前置条件:客户 active 时已创建未来定时发送任务。
- 步骤:
1. 创建 scheduled 任务。
2. 到点前运营端停用客户。
3. 等待或触发调度器执行。
4. 查询任务详情、账单流水和系统日志。
- 预期结果:
- 定时任务到点前重新校验客户状态。
- 客户停用时任务不入队,状态变为 rejected/canceled/failed。
- 如已冻结费用,生成 release 流水。
- 任务失败原因和系统日志均指向客户停用。
### TC-CUSTOMER-005 客户重新启用恢复发送能力
- 优先级:P0
- 前置条件:客户曾被停用,应用/签名/模板/报备/账户均可用。
- 步骤:
1. 运营端重新启用客户。
2. 客户端创建立即发送任务。
3. 模拟 submit accepted 和 delivered。
4. 查询任务、发送详情、账单流水。
- 预期结果:
- 客户状态变为 active。
- 新发送可进入风控、计费和发送链路。
- 发送记录和账务流水完整。
- 系统日志记录重新启用动作。
### TC-CUSTOMER-006 客户欠费或额度不足状态联动发送
- 优先级:P0
- 前置条件:客户现金余额不足,或运营端标记欠费。
- 步骤:
1. 客户端创建发送任务。
2. API 调用发送。
3. 运营端查看客户账户、账单流水、发送失败记录。
- 预期结果:
- 发送前账户校验失败。
- 错误原因包含余额/额度/欠费。
- 不生成扣费流水,不投递 Gateway。
- 运营端客户详情可看到欠费或余额不足状态。
### TC-CUSTOMER-007 客户租户隔离和越权访问
- 优先级:P0
- 前置条件:存在客户 A 和客户 B,各有应用、签名、模板、任务、账单流水。
- 步骤:
1. 使用客户 A 用户登录客户端。
2. 尝试通过 URL、筛选条件或 API 参数访问客户 B 的资源 id。
3. 运营端使用客户维度查询两边数据。
- 预期结果:
- 客户 A 无法访问客户 B 的任何资源。
- 返回无权限或无数据,不泄露客户 B 业务信息。
- 运营端按客户过滤时数据准确。
- 越权访问失败记录进入安全或系统日志。
### TC-CUSTOMER-008 客户删除或归档的业务影响
- 优先级:P0
- 前置条件:客户有历史任务、账单流水、应用、签名、模板和 scheduled 任务。
- 步骤:
1. 运营端删除、归档或停用客户。
2. 客户端尝试登录和发送。
3. 到达 scheduled 任务执行时间。
4. 运营端查询历史任务、账单流水、trace。
- 预期结果:
- 如系统不允许硬删除,应提示存在业务数据并要求停用/归档。
- 被归档/停用客户不能新建发送。
- 未执行定时任务不应继续发送。
- 历史任务、账单、trace 必须保留可查。
- 系统日志记录删除失败、归档或停用动作。
### TC-CUSTOMER-009 客户详情展示业务总览准确
- 优先级:P0
- 前置条件:客户 A 下存在应用 3 个、签名 4 个、模板 5 个、通道绑定 2 个、今日发送 100 条和现金余额。
- 步骤:
1. 运营端打开客户详情。
2. 查看客户业务总览:应用数、签名数、模板数、今日发送量、成功率、现金余额、待审核数。
3. 点击每个指标进入对应明细列表。
- 预期结果:
- 客户详情总览只统计客户 A。
- 指标与对应明细列表聚合一致。
- 点击跳转时自动带入客户筛选。
- 客户停用、欠费、未认证等状态在总览中有清晰标识。
### TC-CUSTOMER-010 客户维度通道绑定和连接状态展示
- 优先级:P0
- 前置条件:客户 A 绑定通道组 G1,G1 包含通道 A/B;通道 A online,通道 B disconnected。
- 步骤:
1. 运营端打开客户详情的通道或发送配置区域。
2. 查看客户绑定通道组、主备通道、通道业务状态、CMPP 连接状态。
3. 创建客户 A 发送任务。
4. 查看 trace 中实际使用通道。
- 预期结果:
- 客户详情展示客户可用通道组和各通道连接状态。
- online/disconnected 状态与通道监控页一致。
- 发送路由选择 online 且报备通过的通道。
- trace 中 channelId 与客户通道配置一致。
### TC-CUSTOMER-011 客户维度通道连接数量展示
- 优先级:P0
- 前置条件:客户 A 绑定通道 A,配置连接数 2;当前 Gateway 建立 2 条连接。客户 B 绑定通道 B,配置连接数 3,当前在线 1 条。
- 步骤:
1. 运营端打开客户列表。
2. 查看客户 A/B 的通道连接摘要。
3. 打开客户详情查看连接数明细。
4. 与通道监控页核对。
- 预期结果:
- 客户列表展示连接摘要,例如 `2/2 online``1/3 degraded`
- 客户详情展示每个绑定通道的配置连接数、当前在线连接数、异常连接数。
- 客户维度连接数与通道监控按客户/通道过滤结果一致。
- 异常连接有状态和最近错误原因。
### TC-CUSTOMER-012 客户通道连接数量调整影响后续发送
- 优先级:P1
- 前置条件:客户 A 通道 A 当前配置连接数为 1,发送正常。
- 步骤:
1. 运营端将客户 A 在通道 A 上的连接数调整为 2。
2. Gateway 重新加载配置或重启连接。
3. 查看客户详情和通道监控连接数。
4. 提交多条发送任务。
- 预期结果:
- 配置连接数展示为 2。
- Gateway 连接数最终达到 2/2 online。
- 发送提交能力或窗口容量按新连接配置生效。
- 系统日志记录连接数配置变更。
### TC-CUSTOMER-013 客户通道连接数量超限校验
- 优先级:P1
- 前置条件:通道 A 平台最大连接数为 5,已分配客户 A 3 条、客户 B 2 条。
- 步骤:
1. 尝试将客户 C 在通道 A 上配置 1 条连接。
2. 尝试将客户 A 连接数从 3 调整为 4。
3. 查看错误提示和系统日志。
- 预期结果:
- 超过通道最大连接数时保存失败。
- 错误提示包含通道最大连接数和当前已分配连接数。
- 不影响已有连接。
- 失败操作写入系统日志。
### TC-CMPP-STATUS-001 通道初始连接状态展示
- 优先级:P0
- 前置条件:运营端已创建 CMPP 通道,Gateway 未启动或未连接。
- 步骤:
1. 打开运营端通道管理和发送监控。
2. 查看通道连接状态、最近心跳时间、重连次数、错误信息。
3. 调用健康检查或监控接口。
- 预期结果:
- 通道业务状态 active 与 CMPP 连接状态分开展示。
- Gateway 未连接时连接状态显示 disconnected/unknown。
- 最近心跳为空或过期。
- 不误显示为可提交状态。
### TC-CMPP-STATUS-002 CMPP 登录成功后连接状态变为在线
- 优先级:P0
- 前置条件:模拟 SMSC 可用,通道账号密码正确。
- 步骤:
1. 启动 Gateway。
2. Gateway 连接模拟 SMSC 并完成 CMPP connect/login。
3. 运营端刷新通道详情和监控。
4. 创建发送任务并提交一条短信。
- 预期结果:
- 连接状态变为 connected/online。
- 展示连接建立时间、最近 active test 时间、窗口大小或可用窗口。
- 发送任务可被路由到该通道。
- submit accepted 后通道健康指标更新。
### TC-CMPP-STATUS-003 CMPP 登录失败展示认证错误
- 优先级:P0
- 前置条件:通道账号、密码或企业代码配置错误。
- 步骤:
1. 启动 Gateway 连接模拟 SMSC。
2. 模拟 SMSC 返回登录失败。
3. 运营端查看通道状态和错误信息。
4. 创建发送任务。
- 预期结果:
- 连接状态显示 auth_failed/login_failed。
- 错误信息包含认证失败原因或错误码。
- 发送路由不应选择该通道,除非无备用通道时任务失败并展示原因。
- 系统日志或告警记录登录失败。
### TC-CMPP-STATUS-004 Active Test 心跳超时变更连接状态
- 优先级:P0
- 前置条件:Gateway 已连接模拟 SMSC。
- 步骤:
1. 模拟 SMSC 停止响应 active test。
2. 等待心跳超时。
3. 查看通道连接状态。
4. 提交发送任务。
- 预期结果:
- 通道连接状态从 online 变为 heartbeat_timeout/disconnected。
- 最近心跳时间不再刷新。
- Gateway 进入重连流程。
- 新发送不应继续提交到该失联连接,应走备用通道或失败排队。
### TC-CMPP-STATUS-005 断线重连成功后恢复发送
- 优先级:P0
- 前置条件:通道在线,存在备用通道或队列可暂存。
- 步骤:
1. 模拟 SMSC 断开 TCP 连接。
2. 观察 Gateway 重连次数和连接状态。
3. 恢复模拟 SMSC。
4. 提交新发送任务。
- 预期结果:
- 断线后状态变为 disconnected/reconnecting。
- 重连次数增加,日志记录断线原因。
- 重连成功后状态回到 online。
- 新发送可正常 submit。
- 断线期间未确认的消息有明确重试、失败或待补偿状态。
### TC-CMPP-STATUS-006 通道连接离线时路由到备用通道
- 优先级:P0
- 前置条件:通道组包含主通道 A 和备用通道 B,A active 但连接离线,B active 且 online,签名在 B 报备通过。
- 步骤:
1. 确认 A 业务状态 active、连接状态 disconnected。
2. 确认 B 业务状态 active、连接状态 online、currentConnections 大于 0。
3. 创建发送任务。
4. 查询 submit record 和 trace。
- 预期结果:
- 路由跳过连接离线的 A。
- 选择 B 提交。
- trace 显示实际 channelId 为 B。
- 通道健康指标记录 A 不可用和 B 提交成功。
### TC-CMPP-STATUS-007 无在线通道时发送任务失败或等待
- 优先级:P0
- 前置条件:路由范围内所有通道连接状态均 disconnected/auth_failed/heartbeat_timeout。
- 步骤:
1. 创建发送任务。
2. 触发送 worker。
3. 查看任务状态、发送明细、系统日志。
- 预期结果:
- 系统不向离线连接 submit。
- 发送明细进入 failed。
- 运营端 trace 和系统日志展示“无可用在线通道”原因;客户端本期只展示失败状态,不展示通道细节。
- 不产生 submit accepted 记录,不错误扣费。
### TC-CMPP-STATUS-008 连接状态与通道启停状态组合
- 优先级:P1
- 前置条件:通道连接 online。
- 步骤:
1. 运营端将通道业务状态改为 disabled。
2. 查看连接状态是否仍可展示。
3. 创建发送任务。
4. 再将通道启用。
- 预期结果:
- disabled 通道即使连接 online,也不可被路由选中。
- 连接状态可继续用于运维观察,但发送可用性显示为不可用。
- 启用后如连接仍 online,可恢复路由;如连接已断开,需要等待重连。
- 系统日志记录启停操作。
### TC-CMPP-STATUS-008A 通道连接可用性标准
- 优先级:P0
- 前置条件:同一通道组内准备多个通道,分别设置为 online/currentConnections=1、online/currentConnections=0、auth_failed、heartbeat_timeout、reconnecting、disconnected。
- 步骤:
1. 创建发送任务。
2. 触发送 worker。
3. 查询 submit record、trace 和连接状态日志。
- 预期结果:
- 只有业务 active、连接 online、currentConnections 大于 0 且心跳未失败的通道可被选中。
- auth_failed、heartbeat_timeout、reconnecting、disconnected 和 currentConnections=0 的通道均被跳过。
- 多连接通道只要至少 1 条连接 online 且可用即可参与路由。
- 心跳连续 3 次失败后进入重连,重连成功前不可发送。
### TC-CMPP-STATUS-009 慢响应导致窗口占满和状态告警
- 优先级:P1
- 前置条件:模拟 SMSC 可配置慢 submit respGateway 有滑动窗口限制。
- 步骤:
1. 配置模拟 SMSC 延迟 submit resp。
2. 连续提交多条短信直到窗口占满。
3. 查看通道监控和队列积压。
4. 恢复 SMSC 正常响应。
- 预期结果:
- 通道状态展示窗口占用、慢响应或拥塞指标。
- 新消息排队等待,不丢失。
- 恢复后积压逐步下降。
- 超时消息按 submit timeout 处理并可追踪。
### TC-CMPP-STATUS-010 连接状态变化写入日志和监控
- 优先级:P0
- 前置条件:通道经历 online、disconnected、reconnecting、online 状态变化。
- 步骤:
1. 触发连接成功、断线、重连成功。
2. 查询通道健康指标。
3. 查询系统日志或运维日志。
- 预期结果:
- 每次连接状态变化都有时间戳。
- 健康指标记录重连次数、连接可用性、submit 成功/失败。
- 日志包含 channelId、channelCode、错误原因、恢复时间。
- 运营端监控可按通道查看状态历史。
### TC-CMPP-STATUS-011 通道连接数量配置展示
- 优先级:P0
- 前置条件:通道 A 配置最大连接数 4,期望连接数 2,窗口大小 16;Gateway 当前在线连接 2 条。
- 步骤:
1. 运营端打开通道详情。
2. 查看最大连接数、期望连接数、当前在线连接数、窗口大小、连接列表。
3. 打开发送监控通道详情。
- 预期结果:
- 通道详情展示 maxConnections、desiredConnections、currentConnections。
- 连接列表展示每条连接的连接 id、状态、登录时间、最近心跳、sequence 范围或当前 sequence。
- 发送监控与通道详情连接数一致。
### TC-CMPP-STATUS-012 增加通道连接数后 Gateway 建立新连接
- 优先级:P0
- 前置条件:通道 A 当前 desiredConnections=1currentConnections=1。
- 步骤:
1. 运营端将 desiredConnections 调整为 3。
2. Gateway 监听配置变更或重载配置。
3. 观察连接状态变化。
4. 提交批量发送任务。
- 预期结果:
- Gateway 新建连接直到 currentConnections=3。
- 三条连接均完成 CMPP 登录和 active test。
- 发送任务可按连接/窗口分摊提交。
- 通道监控展示连接数变更历史。
- 系统日志记录连接数量调整。
### TC-CMPP-STATUS-013 减少通道连接数后优雅关闭多余连接
- 优先级:P0
- 前置条件:通道 A desiredConnections=3currentConnections=3,队列中有待发送任务。
- 步骤:
1. 运营端将 desiredConnections 调整为 1。
2. Gateway 执行配置重载。
3. 观察连接关闭和发送任务处理。
- 预期结果:
- Gateway 不强制中断正在等待 submit resp 的连接,或按设计安全失败并重试。
- 最终 currentConnections=1。
- 关闭的连接有 terminate/close 日志。
- 发送任务不丢失、不重复提交。
### TC-CMPP-STATUS-014 单连接异常时连接数量降级展示
- 优先级:P0
- 前置条件:通道 A desiredConnections=3currentConnections=3。
- 步骤:
1. 模拟其中一条连接断开。
2. 查看通道详情和 Dashboard。
3. Gateway 自动重连该连接。
- 预期结果:
- 通道状态展示 degraded 或 partial_online。
- 连接数量展示为 2/3 online。
- Dashboard 异常连接数增加 1。
- 重连成功后恢复 3/3 online。
### TC-CMPP-STATUS-015 连接数量为 0 的通道不可发送
- 优先级:P0
- 前置条件:通道业务状态 active,但 desiredConnections=0 或 currentConnections=0。
- 步骤:
1. 查看通道详情和客户通道配置。
2. 创建发送任务。
3. 查看路由结果和错误提示。
- 预期结果:
- 系统明确展示该通道无在线连接。
- 路由不选择 currentConnections=0 的通道。
- 无备用通道时任务失败或等待,原因包含无在线连接。
- 不产生 submit accepted 和错误扣费。
### TC-CMPP-STATUS-016 连接数量指标与 submit 能力联动
- 优先级:P1
- 前置条件:通道 A 单连接限速 100 条/秒,连接数可配置。
- 步骤:
1. 连接数为 1 时运行性能 smoke。
2. 连接数调整为 2 并稳定 online。
3. 再次运行性能 smoke。
4. 查看 Dashboard 和通道监控。
- 预期结果:
- 平台展示理论提交能力随在线连接数变化。
- 实际 submit TPS 不超过通道配置和连接数限制。
- 连接数变化不会导致重复发送。
## 15. 测试实施步骤
系统功能测试建议分 8 步执行。第一步先做测试基线和数据准备,不直接开始点页面;原因是后续所有闭环都依赖客户、认证、应用、签名、模板、通道、账户和模拟 Gateway 的一致初始状态。
### 第一步:准备测试环境和基线数据
- 目标:让后续所有测试在同一套可复现数据上执行。
- 执行内容:
1. 启动或确认 PostgreSQL、Redis、MinIO、API、前端、Gateway、模拟 SMSC。
2. 初始化客户 A、客户 B、运营管理员、运营审核员、客户管理员、客户普通用户。
3. 初始化 active/disabled 客户、未认证/待审核/已认证/驳回企业认证资料。
4. 初始化可用应用、停用应用、待删除应用。
5. 初始化签名、引流信息、模板、多变量模板、通道、通道组、路由规则。
6. 初始化现金余额、欠费/不足余额场景。
7. 准备 CSV/TXT/GBK/大文件/非法字符/黑名单号码测试文件。
8. 确认 Gateway 模拟器可切换 online、auth_failed、heartbeat_timeout、disconnected、slow_response。
- 产出物:
- 测试账号清单。
- 测试客户和租户 id。
- 测试应用/签名/模板/通道 id。
- 测试文件目录。
- 环境健康检查截图或日志。
### 第二步:执行静态配置和权限基础测试
- 覆盖范围:
- 客户创建、编辑、启停、租户隔离。
- 登录、用户权限、客户越权访问。
- 应用、签名、模板、引流字段、通道、路由规则的基础 CRUD。
- 通过标准:
- 数据隔离正确。
- 启停/删除状态能影响后续发送。
- 系统日志记录所有关键配置变更。
### 第三步:执行认证、审核、报备闭环测试
- 覆盖范围:
- 企业认证提交、审核通过、驳回重提、企业停用。
- 签名审核、模板审核、短信审核。
- 签名引流信息和通道报备状态变更。
- 通过标准:
- 审核状态在客户端和运营端一致。
- 报备未通过或失效时发送被阻断。
- 审核记录、报备记录、系统日志三类证据完整。
### 第四步:执行发送前校验测试
- 覆盖范围:
- 多变量模板、变量缺失/多传/超长。
- 导入文件解析、重复、非法、黑名单。
- 非法字符、敏感词、内容展示和计费预估。
- 风控规则和账户余额校验。
- 通过标准:
- 所有阻断场景都不入队、不扣费,原因可读。
- 所有允许场景的计费预估与最终内容一致。
- 风控命中记录包含阈值、实际值、动作和原因。
### 第五步:执行发送链路闭环测试
- 覆盖范围:
- 立即发送。
- 定时发送创建、查看、取消、到点执行。
- 导入数据发送。
- submit result、receipt、uplink、72 小时超时。
- 通过标准:
- 批量任务、手机号记录、提交记录、回执记录、上行记录完整。
- 任务进度统计准确。
- trace 能串起 messageId、submitId、sequenceId、gatewayMessageId。
### 第六步:执行计费和对账测试
- 覆盖范围:
- 70/67 计费。
- 预估、冻结、扣费、释放、退款。
- 失败退款、超时退款。
- 账单流水和 reconciliation。
- 通过标准:
- 每条短信记录可追溯到账务流水。
- 成功、失败、超时的金额方向正确。
- 对账 diff 符合预期。
### 第七步:执行 CMPP 连接状态和通道路由测试
- 覆盖范围:
- online、auth_failed、heartbeat_timeout、disconnected、reconnecting、slow_response。
- 主备通道路由。
- 无在线通道。
- 连接状态和业务启停状态组合。
- 通过标准:
- 离线或认证失败通道不被错误提交。
- 可用备用通道能接管。
- 连接状态变化有监控、健康指标和日志。
### 第八步:执行回归验证和报告归档
- 覆盖范围:
- 自动化测试命令。
- 前端 smoke。
- 性能 smoke。
- 缺陷复测。
- 建议执行命令:
```bash
npm run spike:contracts
npm run test:api
npm run test:gateway
npm run verify:phase8
```
- 产出物:
- 测试执行记录。
- 缺陷列表和复测结果。
- 性能 smoke 结果。
- 未覆盖项和延期说明。
## 16. 回归执行建议
每次阶段回归至少执行:
```bash
npm run spike:contracts
npm run test:api
npm run test:gateway
npm run verify:phase8
```
## 2026-07-15 通道 TPS 归属与通道组成员字段清理
| 用例编号 | 场景 | 操作 | 预期结果 |
| --- | --- | --- | --- |
| TC-CHANNEL-TPS-001 | 单通道限速 | 通道 A 配置 100 TPS,持续提交超过 100 条/秒 | PostgreSQL 保存 `SmsChannel.rateLimitPerSecond=100`NestJS 以通道 A 的 ID 建立 Redis 限速桶;单个自然秒放行不超过 100 条。 |
| TC-CHANNEL-TPS-002 | 多通道独立限速 | 通道 A、B 均配置 100 TPS,并发向两个通道提交 | A、B 使用不同通道 ID 的 Redis 限速桶,各自最多 100 TPS;平台不存在共享的 100 TPS 总额度。 |
| TC-CHANNEL-TPS-003 | 多通道组共享同一物理通道 | 两个通道组同时选中通道 A 并产生发送 | 两组发送共享通道 A 的同一个 100 TPS 限速桶,合计不超过通道 A 配置;通道组成员接口和页面均无单独流速字段。 |
| TC-CHANNEL-TPS-004 | 数据库结构清理 | 执行 Prisma migration 并读取 `SmsChannelGroupItem` 结构 | `SmsChannelGroupItem.rateLimitPerSecond` 已删除,通道自身的 `SmsChannel.rateLimitPerSecond` 保留。 |
测试环境必须具备 PostgreSQL、Redis、MinIO 或等价本地服务后,才能将 E2E smoke 和真实 API HTTP 测试记为系统功能通过;缺失时对应用例标记为阻塞或未执行。
## 17. 新增和更新用例细化执行清单
本节用于细化 2026-07-02 新增的页面真实后端、Dashboard、人工充值、系统日志、客户管理和 CMPP 连接状态用例。执行时应优先使用真实 NestJS API、Prisma/PostgreSQL、Redis/BullMQ 和 Gateway 测试替身;mock、localStorage 或前端静态数组只能作为单元测试替身,不能作为业务验收通过依据。
### 17.1 通用断言规则
| 断言类型 | 检查点 |
| --- | --- |
| 数据来源 | 页面列表、详情、统计卡片、弹窗和下拉选项均必须来自真实 API 响应;网络失败时可以展示错误态或空态,但静态兜底数据不能计入通过。 |
| 租户隔离 | 客户端接口必须以当前租户为边界;通过 URL、查询参数或资源 id 访问其他租户数据时,应返回无权限、无数据或明确错误。 |
| 状态联动 | 客户、应用、签名、模板、引流信息、通道、连接状态变化后,立即发送、定时到点、导入确认发送都必须重新校验。 |
| 日志证据 | 创建、编辑、删除、启停、复制、审核、导入、导出、充值、冲正、发送阻断、连接状态变化、失败动作都必须写系统日志。 |
| 历史数据 | 软删除、停用、归档不得破坏历史发送、报备、计费、trace 和对账记录。 |
| 计费口径 | Dashboard、账单流水、短信计费记录、账户交易和 reconciliation 的金额、条数、状态口径必须一致。 |
| Gateway 边界 | 不依赖真实运营商 SMSC;CMPP 登录、心跳、断线、重连、慢响应使用 Go Gateway 本地模拟器或连接状态回写 API。 |
### 17.2 客户端用户和系统日志细化
| 用例 | 细化执行点 | 必查断言 |
| --- | --- | --- |
| TC-CLIENT-010 | 新增普通用户,检查请求体包含 tenantId、手机号、角色、状态;编辑用户基础信息;尝试把第二个用户设为企业管理员;删除普通用户。 | 新增后用户列表刷新;同租户第二个企业管理员被阻止;删除为软删除或状态不可用;每步写 `operation_logs`resource 指向 user id。 |
| TC-CLIENT-010 | 使用普通用户登录后访问用户管理页面和 API。 | 普通用户无权限或只读;无权限访问也写失败日志。 |
| TC-CLIENT-011 | 点击头像下拉,执行修改密码,使用旧密码登录,再使用新密码登录。 | 旧密码失效,新密码有效;修改密码日志不泄露明文密码;退出登录清理 token/session。 |
| TC-CLIENT-011 | 客户端系统日志准备至少 2 页数据,按动作、操作者、时间查询,查看长详情。 | 分页参数传给后端;总数、页码、页大小准确;长详情不在表格中截断,详情弹窗/卡片展示完整 JSON 摘要。 |
### 17.3 运营端真实后端页面细化
| 用例 | 细化执行点 | 必查断言 |
| --- | --- | --- |
| TC-ADMIN-014 | 按客户名称、应用名称、模板内容、审核编号、审核状态分别搜索模板审核列表。 | 每次搜索均发起 API 请求;结果只包含匹配数据;清空条件后恢复默认列表;跨租户/不存在关键字无误展示。 |
| TC-ADMIN-014 | 运营端企业模板管理新增短信模板后进入短信模板审核页查看。 | 新增模板状态直接为 approved;通过/驳回按钮禁用;客户端自行提交的模板仍可保持 pending 审核流。 |
| TC-ADMIN-014 | 对待审核模板分别执行通过、驳回。 | 审核状态更新;审核记录包含审核人、时间、原因;客户端模板列表同步;驳回模板不能发送。 |
| TC-ADMIN-015 | 运营端查看企业认证详情,核对主体信息、执照附件、对公账户验证、联系人。 | 详情字段来自 certification API;附件 id/URL 可追溯;通过/驳回同步 Tenant.certificationStatus;驳回后客户可重提。 |
| TC-ADMIN-016 | 复制通道,随后查询新通道详情、报备字段、签名报备材料。 | 新通道 code/id 唯一;CMPP 参数、限速、报备字段、材料被复制;源通道不受影响;复制日志包含 sourceChannelId 和 newChannelId。 |
| TC-ADMIN-017 | 对有关联历史的通道执行停用、启用、删除。 | 取消确认无请求或无状态变化;停用后不参与路由;删除为软删除/归档;历史发送、报备、日志仍可查。 |
| TC-ADMIN-018 | 企业应用列表展示 CMPP 连接数,打开连接详情,删除连接,复制 CMPP 参数。 | 连接数来自连接状态 API;详情含 connectionId/status/heartbeat/window/lastSubmitAt;删除连接调用真实接口;复制文本与 API 返回一致。 |
| TC-ADMIN-019 | 打开通道连接日志,按事件类型和时间查看。 | 日志包含 connect、active_test、disconnect、reconnect、auth_failed、slow_response;按时间倒序;可定位 channelId/connectionId。 |
| TC-ADMIN-020 | 企业黑名单、全局黑名单、敏感词分别执行搜索、新增、停用、删除。 | 企业黑名单必须绑定短信应用且按应用生效;搜索由 API 处理;停用/删除后发送前风控只使用 active 数据;删除不影响历史命中记录;所有动作写日志。 |
| TC-ADMIN-021 | 创建待审核企业认证、签名、模板、短信审核任务,检查铃铛总数和分类数,并观察首次加载、30 秒轮询、窗口重新获得焦点及审核完成后的网络请求。 | 总数等于分类汇总;点击分类跳转并带入筛选;审核完成后数量刷新;新增待办触发站内提醒或浏览器通知;所有全局角标刷新只请求独立待审核数量接口,不请求完整运营看板统计。 |
| TC-ADMIN-022 | 运营日志按客户、操作者、动作、资源、时间搜索,查看长详情。 | 后端分页和搜索准确;详情不截断;可查到通道复制、启停、删除、连接状态变化、安全控制变更、充值等日志。 |
| TC-ADMIN-023 | 准备多个企业产生不同的当日真实消费金额后打开企业列表。 | API 结果按 `todaySpendCents` 降序;相同金额按企业名称和 id 稳定排序;金额来自 PostgreSQL 当日短信记录聚合。 |
| TC-ADMIN-024 | 准备多个企业应用产生不同的当日真实发送数量后打开企业应用列表。 | API 结果按 `sentToday` 降序;相同数量按应用名称和 id 稳定排序;数量来自 PostgreSQL 当日短信记录聚合。 |
| TC-ADMIN-025 | 将通道真实成本分别设为 3、3.5、3.456 分并打开通道列表。 | 分别显示 `3.00 分`、`3.50 分`、`3.46 分`;仅改变展示精度,不改写数据库成本及历史提交成本快照。 |
| TC-ADMIN-026 | 新增全局黑名单和敏感词,后端时间分别使用跨自然日的 UTC 时间;在不同时区浏览器中打开列表。 | “入库时间”和“创建时间”均按 `Asia/Shanghai` 显示为 `YYYY-MM-DD HH:mm:ss`,不出现 ISO `T/Z`,且结果不随浏览器设备时区变化。 |
| TC-ADMIN-027 | 连续多轮创建无依赖签名并删除;另连续多轮创建、编辑为待审核后再删除,同时存在待审核任务提醒。 | 每轮资格预检、填写原因、确认删除均只调用一次真实删除接口;结果区显示“删除已完成”和操作单号,刷新后签名不再出现;全局审核提醒不得被误判为删除失败。 |
### 17.4 Dashboard 指标细化
| 用例 | 数据准备 | 指标断言 |
| --- | --- | --- |
| TC-DASHBOARD-001 | 客户 A 当天 delivered=10、failed=3、unknown=2、timeout=1;客户 B 有干扰数据。 | 客户端总量=16;成功=10;失败按 failed+timeout 为 4unknown=2;成功率若按 delivered/total 为 62.5%;点击卡片后的明细筛选一致。 |
| TC-DASHBOARD-002 | 现金余额 10000 分,另有冻结、扣费、释放、退款流水。 | 可用额度仅为现金余额且不重复计算冻结;账单流水 balanceAfter 与 Dashboard 一致。 |
| TC-DASHBOARD-003 | 待审核签名 2、模板 3、待报备 1、pending_review 发送任务 4。 | 待处理总数和分类数准确;点击跳转后列表筛选数量一致;只包含当前租户。 |
| TC-DASHBOARD-004 | 多客户、多通道、多状态发送和账务流水。 | 运营端统计全平台;活跃客户、今日发送、成功率、待审核、收入均可在明细页复核。 |
| TC-DASHBOARD-005 | 客户 A/B 均有发送、账务、审核数据。 | 切换客户后所有卡片、趋势、状态分布、账务汇总同步刷新;跳转明细继承客户筛选。 |
| TC-DASHBOARD-006 | 通道 A online 2/2B disconnected 0/2C auth_failed。 | 在线连接总数等于各通道 currentConnections 之和;异常通道数分类准确;点击异常通道展示错误原因。 |
| TC-DASHBOARD-007 | 准备跨日、跨小时和时区边界数据。 | 今日、近 7 天、近 30 天边界明确;趋势图每个点位与明细聚合一致;使用平台时区。 |
### 17.5 人工充值和账务细化
| 用例 | 细化执行点 | 必查断言 |
| --- | --- | --- |
| TC-BILLING-006 | 运营端人工充值现金金额,客户端查看 Dashboard 和充值记录。 | RechargeOrder 状态为 paid/manual_topupTenantAccount 现金余额同步增加;AccountTransaction 类型 recharge;充值记录“充值后余额”必须等于该订单关联 AccountTransaction.balanceAfter,不能用当前账户余额替代;运营日志可追溯。 |
| TC-BILLING-007 | 分别填写正数金额和负数金额执行充值、冲正;提交 0 或非法金额;将授信额度配置为正数、负数和 0。 | 充值正负金额方向正确;0 和非法充值金额被拒绝;三种授信值都能保存并写操作日志;数据模型和接口不存在短信套餐条数字段。 |
| TC-BILLING-008 | 对已充值记录执行撤销/冲正,分别覆盖未消费和已部分消费。 | 未消费可全额回退;已消费按规则拒绝或生成人工调整;原订单状态和反向流水清晰;日志记录原因。 |
| TC-BILLING-009 | 无权限用户、审核员、管理员分别执行充值;大额人工充值不走审批。 | 权限不足被拒绝并写失败日志;有权限用户确认后立即入账;不产生 pending 审批态;充值订单、账户余额、流水和日志同步完成。 |
| TC-BILLING-010 | 余额不足发送失败,人工充值后重试发送并模拟 delivered。 | 充值前不扣费;充值后发送成功;冻结、扣费、短信计费记录完整;reconciliation diff 为 0。 |
| TC-BILLING-011 | 分别准备 `余额+授信` 为正数、0 和负数的账户,使用相同短信费用发起发送。 | 和为正数时允许发送;和为 0 或负数时提示余额不足。判断公式为 `balanceCents + creditCents > 0`,与本次费用和套餐无关。 |
| TC-BILLING-012 | 已扣费短信收到最终失败回执;另一个消息在提交前失败并释放冻结;另准备一笔任务冻结转扣费时的批次级释放。 | 最终失败只生成一条 `refunded` 并计入“今日返还”,重复回执不重复退款;提交前失败生成 `released + relatedType=sms_message_record` 并计入“今日返还”;冻结转扣费的 `released + relatedType=sms_batch_task` 属于内部转换,不计入“今日返还”;客户端和运营端当日金额一致且保留三位小数。 |
| TC-BILLING-013 | 准备已提交扣费但 72 小时完全无回执的 `submitted` 短信,以及有 `UNKNOWN` 回执且超过 72 小时的短信;分别覆盖HTTP提交、CMPP短短信和多分片长短信,启动 API 定时扫描并模拟投递建单失败后重复扫描。 | 两类短信都转为 timeout、写入`undelivered/EXPIRED/RECEIPT_TIMEOUT`并只退款一次;HTTP产生一个明确失败Webhook,CMPP对每个请求回执的原始分片产生失败状态报告且使用各自SubmitResp Msg_Id;建单未完成时`timeoutReceiptQueuedAt`保持空并由后续扫描补齐,成功建单后不重复;任务进度刷新。 |
| TC-BILLING-014 | 在运营端充值记录中分别打开整数金额、含1至4位有效小数、负数冲正以及缺少可追溯余额的真实订单回执。 | 每行提供“查看回执”;弹窗左上只使用系统真实Logo;企业、订单号、时间、备注与数据库订单一致;可追溯订单的入账前余额等于入账后余额减本次变动;无快照时前后余额不得伪造;主金额和余额最多显示四位小数并移除末尾无意义的0;正数显示已入账,负数显示已冲正。 |
| TC-SEC-006 | 安装 API 生产依赖并执行 `npm audit`;使用缺文件、多文件、超大文件、超量字段和正常单文件调用认证后的 multipart 上传接口。 | NestJS/Multer/Hono 已升级或锁定到修复版本,生产依赖 audit 为 0;接口只接受一个不超过 20MB 的文件,并限制字段、part、字段名、字段值和 header pair 数量;异常请求返回受控 4xx,正常文件仍写入真实 MinIO 和 `FileObject`。 |
### 17.5.1 报表对账细化
| 用例 | 细化执行点 | 必查断言 |
| --- | --- | --- |
| TC-REPORT-001 | 在同一发送日准备多个企业和应用的单条、长短信,覆盖 delivered、failed、unknown;次日执行报表刷新并按日期、企业、应用查询对账单。 | 只生成 T-1 及更早完整日期;发送和成功均按 `billingUnits` 汇总;成功只包含最终 delivered;企业与应用隔离正确;API 使用 PostgreSQL 报表表和服务端分页。 |
| TC-REPORT-002 | 准备不同客户单价的短短信成功、三分片长短信仅两片成功、最终失败退款、同通道成功和跨通道补发成功短信,分别按企业应用和通道查看利润报表。 | 收入逐条等于最终成功计费条数×该短信发送时的客户单价快照后汇总,不受 charged/refunded 状态切换影响;失败和未知短信不计收入;成本严格等于各次提交的通道成本单价快照乘以该次成功分片数,失败和未知分片成本为0;通道维度收入只归属最终提交且不重复;利润=收入-成本,利润率计算正确,收入为0时显示0%;页面、汇总与 CSV 均无返还字段。 |
| TC-REPORT-003 | 首次生成后,在 T-3 短信上补录 delivered 回执并将另一条 T-2 短信最终失败退款,再执行次日定时刷新。 | 每次刷新准确覆盖 T-4、T-3、T-2、T-1;对应日期旧行在事务内重建,成功数、消费、利润同步修正;T-5 及更早报表不被本次任务改写。 |
| TC-REPORT-004 | 先按成本价发送并 accepted,再修改通道单价,随后生成和重复刷新报表。 | `SmsSubmitRecord.costUnitPrice/costAmountCents` 保存提交时快照;历史成本不随通道当前单价变化;新提交使用新单价。 |
| TC-REPORT-005 | 打开运营端菜单和两张报表,切换日期、企业、应用及通道维度并翻页。 | “报表对账”位于“数据详单”之后且包含两个二级菜单;筛选和分页调用真实 `/admin/reports/*` API;页面展示生成时间及 T+1/T-4~T-1 口径,不使用 mock、静态数组或 localStorage 数据。 |
| TC-QUALITY-001 | 为同一日期、同一维度准备 100 条 delivered 短信,构造不同的 `submittedAt/deliveredAt`,其中最慢 5 条显著偏大。 | 发送量和成功量按 billingUnits 汇总;成功率精确;平均到达时长先按组计算 P95,只平均小于等于 P95 的样本,最慢 5% 不进入均值;无有效成功时间时返回空值。 |
| TC-QUALITY-002 | 分别准备多个企业应用、通道、签名和引流信息的短信,并制造 accepted 补发及不同 Gateway 回执。 | 四个 Tab 分组正确;通道只使用对应 submit/receipt;每个 Tab 服务端按 sentUnits 降序,相同数量再按日期和名称稳定排序;T-4~T-1 重算同步更新四类质量行。 |
| TC-QUALITY-003 | 同一签名配置短 URL、包含短 URL 的长 URL、两个同长度 URL;发送正文分别命中长 URL、唯一 URL、同长度歧义和完全未命中,再对历史记录执行 migration。 | 新短信与历史短信都优先关联唯一最长 approved URL;歧义和未命中不写伪造 ID 并归入“未关联引流信息”;每条短信在引流维度只统计一次。 |
| TC-QUALITY-004 | 打开“发送质量报表”,依次切换企业应用、通道、签名、引流信息 Tab,使用日期、企业、应用、通道筛选并翻页。 | 菜单位于“报表对账”下;页面调用真实 `/admin/reports/quality`;展示发送量、成功量、成功率、P95 截尾平均时长和生成时间,不使用前端明细聚合。 |
| TC-REPORT-EXPORT-001 | 分别在对账单、利润报表、发送质量报表设置日期及维度筛选,数据超过一页后点击“导出报表”。 | 三类页面均调用各自真实 `/admin/reports/*/export` API;CSV 包含全部筛选结果而非当前页,中文可正常打开,逗号和引号正确转义。 |
| TC-ADMIN-REPORT-FIELD-UI-001 | 打开报备字段库,在宽屏与窄屏下检查概览、两类通用字段、字段卡片及筛选,并尝试删除已引用字段。 | 页面不出现横向滚动;信息区自适应排列;引用数真实展示;已引用字段删除按钮禁用;所有增删仍调用真实 API。 |
| TC-USER-BUTTON-UI-001 | 分别打开运营端和客户端用户管理页面。 | 新增用户按钮为标准小尺寸,文字与图标不换行且不挤占标题区域。 |
### 17.6 系统日志细化
| 用例 | 细化执行点 | 必查断言 |
| --- | --- | --- |
| TC-LOG-005 | 客户 A 查看日志并尝试查询客户 B 日志。 | 客户端只返回本租户日志;越权查询失败;日志包含 IP、User-Agent、result、resourceId。 |
| TC-LOG-006 | 客户端导入号码、立即发送、创建并取消定时任务。 | 导入日志含文件名、行数、成功/失败数;发送日志含任务编号、号码数、发送类型;取消日志含取消人。 |
| TC-LOG-007 | 运营端按客户、动作、资源、结果、时间查询并导出。 | 查询准确;导出内容与筛选一致;导出动作本身写日志。 |
| TC-LOG-008 | 人工充值、冲正、账户调整。 | 日志含客户、金额、订单号、流水号、操作者;敏感字段脱敏。 |
| TC-LOG-009 | 触发无权限充值、余额不足发送、无在线通道发送。 | 失败动作也写日志;result/status 标记失败;失败原因与前端提示一致。 |
| TC-LOG-010 | 保持 CMPP 在线并连续发送 heartbeat/Submit/Deliver、重复恢复状态,再触发断开和状态变化。 | 高频事件只更新状态表;连接和恢复状态关键变化才新增日志;日志量不随心跳线性增长。 |
| TC-LOG-011 | 准备多级别、多页和过期日志,验证查询上限与归档重试。 | 数据库侧筛选后分页;每页最多 100;归档成功才删除源记录;archiveMonth、原始 id 和详情完整。 |
### 17.7 客户管理细化
| 用例 | 细化执行点 | 必查断言 |
| --- | --- | --- |
| TC-CUSTOMER-001 | 运营端创建客户并初始化管理员账号、租户、账户。 | Tenant、管理员用户、TenantAccount 创建成功;客户详情业务入口可用;新管理员只能访问本租户。 |
| TC-CUSTOMER-002 | 修改客户名称、联系人、备注,查看客户端和历史数据。 | 展示同步更新;历史任务和账务不丢失;日志记录修改前后摘要。 |
| TC-CUSTOMER-003 | 停用客户后分别通过客户端、API、CMPP 接入尝试发送。 | 全部阻断;不入队、不扣费;失败原因是客户停用;历史任务可查。 |
| TC-CUSTOMER-004 | 客户 active 时创建 scheduled,到点前停用。 | 到点重校验失败;任务 rejected/canceled/failed;冻结费用释放;日志指向客户停用。 |
| TC-CUSTOMER-005 | 重新启用客户后发送。 | 客户状态 active;新发送成功进入链路;账务和日志完整。 |
| TC-CUSTOMER-006 | 现金余额不足或欠费标记。 | 发送前账户校验失败;不投递 Gateway;客户详情展示欠费或不足状态。 |
| TC-CUSTOMER-007 | 客户 A 使用 URL/API 参数访问客户 B 资源。 | 不泄露 B 数据;返回无权限或空结果;失败访问写安全日志。 |
| TC-CUSTOMER-008 | 删除/归档有历史数据的客户。 | 不允许硬删除或执行归档;新发送和未执行 scheduled 阻断;历史 trace/对账可查。 |
| TC-CUSTOMER-009 | 客户详情总览应用、签名、模板、今日发送、余额。 | 各指标与明细列表聚合一致;跳转带客户筛选;异常状态有标识。 |
| TC-CUSTOMER-010 | 客户绑定通道组,主通道 online、备通道 disconnected。 | 客户详情展示通道组和连接状态;发送路由选择 online 且报备通过通道;trace channelId 一致。 |
| TC-CUSTOMER-011 | 客户 A/B 不同连接配置和在线数。 | 客户列表摘要如 `2/2 connected`、`1/3 degraded`;详情和通道监控一致。 |
| TC-CUSTOMER-012 | 调整客户通道连接数并触发 Gateway 重载。 | desired/current 连接数最终一致;发送能力或窗口容量随配置变化;日志记录变更。 |
| TC-CUSTOMER-013 | 超过通道最大连接数分配。 | 保存失败;提示最大连接数、已分配数和可用数;不影响已有连接;失败日志存在。 |
### 17.8 CMPP 连接状态细化
| 用例 | 模拟方式 | 必查断言 |
| --- | --- | --- |
| TC-CMPP-STATUS-001 | Gateway 未启动或未回写。 | 通道业务 active 与连接 disconnected/unknown 分开展示;不可误判为可提交。 |
| TC-CMPP-STATUS-002 | 模拟 SMSC 登录成功。 | 状态 connected;连接建立时间、最近心跳、窗口可用;发送可路由到该通道。 |
| TC-CMPP-STATUS-003 | 模拟登录认证失败。 | 状态 auth_failed;错误码/原因展示;路由跳过;日志/告警记录。 |
| TC-CMPP-STATUS-004 | 模拟 active test 超时。 | 状态 heartbeat_timeout/disconnected;进入重连;新发送走备用或等待失败。 |
| TC-CMPP-STATUS-005 | 模拟 TCP 断开再恢复。 | 状态 disconnected -> reconnecting -> connected;重连次数增加;未确认消息状态明确。 |
| TC-CMPP-STATUS-006 | 主通道离线、备用在线且报备通过。 | 路由跳过主通道并选择备用;trace 展示备用 channelId。 |
| TC-CMPP-STATUS-007 | 所有通道离线或认证失败。 | 不提交到离线连接;任务 delayed/retry/failed/pending_channel;不错误扣费。 |
| TC-CMPP-STATUS-008 | 通道业务 disabled 但连接 connected。 | 不参与路由;连接状态仍可运维观察;启用后按连接状态恢复可用性。 |
| TC-CMPP-STATUS-009 | 模拟 submit resp 慢响应。 | 窗口占用、慢响应、队列积压可见;恢复后积压下降;超时可追踪。 |
| TC-CMPP-STATUS-010 | 触发 connected/disconnected/reconnecting/connected。 | 每次变化有状态历史、健康指标和系统日志。 |
| TC-CMPP-STATUS-011 | 通道 maxConnections=4、desired=2、current=2。 | 通道详情、监控、Dashboard 连接数一致;连接列表展示 connectionId、心跳、窗口、sequence。 |
| TC-CMPP-STATUS-012 | desired 1 调整为 3。 | Gateway 建立新连接至 3/3;任务可按连接/窗口分摊;日志记录调整。 |
| TC-CMPP-STATUS-013 | desired 3 调整为 1。 | 多余连接优雅关闭;未确认 submit 不丢失不重复;终态 1/1。 |
| TC-CMPP-STATUS-014 | 3 条连接中断 1 条。 | 展示 degraded 或 2/3 connected;异常连接数增加;重连恢复后 3/3。 |
| TC-CMPP-STATUS-015 | desired=0 或 current=0。 | 路由不选择该通道;无备用时任务失败或等待;原因包含无在线连接。 |
| TC-CMPP-STATUS-016 | 单连接限速 100,连接数 1 和 2 分别压测。 | 理论能力随在线连接数变化;实际 TPS 不超过限速;不重复发送。 |
| TC-CMPP-STATUS-017 | 新建/启用通道后 Gateway 未回写,连接状态停留 connecting 超过 30 秒。 | API 兜底任务将连接标记为 failedcurrentConnections=0lastError 为 `Gateway connection request timed out after 30 seconds`;连接日志包含 connect_timeout;发送路由不可选择该通道。 |
### 17.8.1 运营端与客户端移动端适配
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-RESP-001 | 分别以运营管理员和企业管理员登录,在 390×844 视口打开首页。 | 左侧栏默认不占据业务内容空间;顶部显示菜单、平台标识、通知和用户入口;页面 `scrollWidth` 不大于视口宽度。 |
| TC-RESP-002 | 点击顶部菜单,滚动长菜单,随后点击任一业务菜单;重复打开后点击遮罩、关闭按钮和按 Esc。 | 抽屉覆盖在业务内容上方并带遮罩,菜单内部可滚动;四种关闭方式均有效,路由切换后抽屉自动收起。 |
| TC-RESP-003 | 在 320、360、375、390 和 768px 宽度打开两端登录页。 | 登录面板、账号、密码、验证码和登录按钮完整处于视口内,不出现页面级横向滚动。 |
| TC-RESP-004 | 在小屏打开客户端签名与引流信息、账户账单、短信记录和模板列表。 | 通用表格或业务列表以带字段标签的纵向卡片呈现,长文本可换行,状态和操作无需横向滚动即可查看。 |
| TC-RESP-005 | 在小屏打开运营端发送质量、对账、利润报表、企业查询、审核日志和手机号段库。 | 多列筛选收敛为单列或紧凑按钮组;查询、重置、导出均可操作;页面无固定宽度导致的横向溢出。 |
| TC-RESP-006 | 在小屏打开通道报备详情、通道组新增/编辑、企业签名管理和 HTTP 接口凭据。 | 报备行按卡片重排,通道组表单与报备目标单列显示,凭据和密钥可换行,操作区可换行且不超出视口。 |
| TC-RESP-007 | 在 1280px 及以上桌面视口复核运营端和客户端。 | 保持原桌面侧栏及折叠按钮;筛选和表格仍按桌面布局展示,不因移动端规则产生回归。 |
| TC-RESP-008 | 登录客户端,在桌面侧栏和移动端抽屉中检查全部菜单。 | 不展示“彩信服务”分组,也不展示彩信签名、模板、发送、任务、详情或上行彩信入口;短信和账户等已完成功能菜单正常显示。 |
| TC-RESP-009 | 在桌面和 390px 小屏打开手机号段库,切换“手机号段/运营商区分规则”,执行关键词查询和重置。 | 页面使用系统通用控件;Tab 位于标题与筛选之间;仅展示当前 Tab 的真实总数;表格/移动卡片无横向溢出,查询和重置继续调用真实 API 查询状态。 |
### 17.9 自动化落地建议
| 层级 | 建议覆盖 |
| --- | --- |
| API Jest | 认证、字典、安全控制、通道复制/软删除、连接状态、人工充值、系统日志查询、Dashboard 聚合口径。 |
| HTTP Smoke | 客户创建、认证审核、通道复制、连接状态回写、人工充值、立即发送、定时到点、trace、reconciliation。 |
| Go Gateway | 连接状态回写契约、登录成功/失败、心跳超时、断线重连、窗口占满、连接数调整。 |
| 前端 Smoke | 客户端头像菜单、系统日志分页、运营模板审核搜索、企业认证详情、通道复制/连接日志、安全控制 CRUD、Dashboard 指标跳转。 |
| 性能 Smoke | BullMQ 500 TPS、CMPP 连接数变化后的提交能力、慢响应积压恢复。 |
### 17.9 登录和用户管理闭环
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-AUTH-001 | 打开 `/admin/login`,输入平台管理员用户名、邮箱或手机号,外加密码和正确图形验证码。 | 登录成功进入运营端;session 用户角色为 `platform_admin`;后续运营端 API 使用真实后端。 |
| TC-AUTH-002 | 使用企业管理员账号登录 `/admin/login`。 | 登录失败;返回“仅平台管理员可登录运营端”类错误;失败次数累计。 |
| TC-AUTH-003 | 打开 `/client/login`,输入已关联企业的企业管理员用户名、邮箱或手机号,外加密码和正确图形验证码。 | 登录成功进入客户端;客户端 API 自动携带当前企业 `tenantId`;Dashboard、用户、日志等仅展示当前企业数据。 |
| TC-AUTH-004 | 使用平台管理员或未关联企业的用户登录 `/client/login`。 | 登录失败;不进入客户端。 |
| TC-AUTH-005 | 同一用户连续输错密码 5 次。 | 第 5 次后用户锁定 24 小时;锁定期内正确密码也被拒绝;系统记录失败次数和锁定时间。 |
| TC-AUTH-006 | 输入错误或过期图形验证码登录。 | 返回 400 可读错误;必须刷新验证码后重试。 |
| TC-AUTH-007 | 使用运营管理员登录,确认响应、浏览器存储和 Redis;不携带 Cookie 访问运营 API。 | 登录响应和 localStorage 不含访问令牌;浏览器仅持有 HttpOnly 会话 CookieRedis 存在哈希会话记录;无 Cookie 请求返回 `401/SESSION_INVALID`。 |
| TC-AUTH-008 | 将运营端无操作参数缩短后等待超时,同时保持 Dashboard 自动轮询;再输入当前密码解锁。 | 自动轮询不续期;服务端返回 `401/SESSION_LOCKED`;页面锁屏但无需账号和验证码;当前密码正确时轮换 Session ID,旧标识失效,多标签同步解锁。 |
| TC-AUTH-009 | 将客户端无操作参数缩短并验证其阈值独立于运营端;锁定后超过锁定恢复期限。 | 客户端使用独立 120 分钟默认阈值;超过 4 小时恢复期限后密码快速解锁被拒绝,必须完整登录。 |
| TC-AUTH-010 | 持续操作至绝对期限,将默认 12 小时在测试环境缩短验证。 | 用户活动只能刷新空闲时间,不能延长绝对期限;到期返回 `401/SESSION_ABSOLUTE_TIMEOUT`,必须重新输入账号、密码和验证码。 |
| TC-AUTH-011 | 登录超过最近认证窗口后执行用户禁用、手工充值、通道修改、路由修改或报备状态修改。 | 后端先返回 `403/RECENT_AUTHENTICATION_REQUIRED`,输入当前密码后 30 分钟内自动重试;错误密码不执行原操作,数据库无副作用。 |
| TC-AUTH-012 | 分别执行主动退出、修改密码、禁用、删除和角色变更,并在另一标签页继续请求。 | Redis 会话删除或 `sessionVersion` 失效;所有标签页同步退出;旧 Cookie 均返回 401;系统日志可查询创建、锁定、解锁、再认证和退出事件。 |
| TC-AUTH-013 | 同一浏览器先登录运营端并保持一个受保护页面,再打开客户端登录页,分别提交错误账号、错误密码、错误角色和错误验证码。 | 客户端仅显示本次登录失败原因并刷新验证码;不得清除现有运营端展示会话、广播 logout 或把运营端页面跳回登录页;运营端随后请求真实受保护 API 仍成功。反向从客户端会话测试运营端错误登录结果相同。 |
| TC-USER-ADMIN-001 | 运营端新增平台管理员,填写用户名/登录账号、邮箱或手机号、初始密码。 | 创建成功;用户无 `tenantId`;可登录运营端;写 `user.created` 日志。 |
| TC-USER-ADMIN-002 | 运营端新增企业管理员但不选择企业。 | 返回 400;不创建用户。 |
| TC-USER-ADMIN-003 | 运营端新增企业管理员并选择企业。 | 创建成功;用户关联企业;可登录客户端;客户端数据按该企业隔离。 |
| TC-USER-ADMIN-004 | 运营端编辑用户、启用/禁用、删除、修改密码。 | 编辑和改密调用真实 API;启停/删除有确认弹窗;删除后列表不展示且不可登录;均写系统日志。 |
| TC-USER-CLIENT-001 | 企业管理员在客户端用户管理新增同企业用户。 | 创建成功;用户自动归属当前企业;不可创建平台管理员;写系统日志。 |
| TC-USER-CLIENT-002 | 客户端编辑、启用/禁用、删除、修改密码。 | 调用真实 `/api/client/users` API;仅影响当前企业用户;启停/删除有确认弹窗。 |
### 17.10 非彩信菜单真实后端清理
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-MOCK-CLEAN-001 | 断开 API 或让 API 返回 500,访问客户端账户余额、充值记录、批量任务、短信发送、签名、模板页面。 | 页面展示错误态或空态;不得出现前端静态余额、任务、模板、签名或最近发送记录。 |
| TC-MOCK-CLEAN-002 | 访问运营端数据统计、账务账户、发送监控、安全控制、手机号段库、报备字段库、通道组、报备任务、报备记录。 | 所有列表和卡片来自真实 API;新增动作写入数据库;后端缺失的编辑/删除能力不得用本地状态伪造。 |
| TC-UI-ENTERPRISE-SELECT-001 | 逐一打开包含企业或企业应用选择的表单和筛选项,输入部分企业/应用名称。 | 下拉面板提供搜索框并实时缩小真实 API 选项范围;清空后恢复全部选项。 |
| TC-UI-SELECT-PORTAL-001 | 分别在普通页面筛选区、卡片、标准弹窗和 XL 弹窗中展开通用 Select,并改变窗口高度、滚动页面。 | 所有下拉均由通用控件渲染到页面级 Portal,不被父容器裁剪;空间不足时自动换向,滚动或缩放后仍贴合触发控件,选项选择和点击外部关闭正常。 |
| TC-UI-TEMPLATE-RESPONSIVE-001 | 在 1024px、1366px 和宽屏视口打开企业短信模板页。 | 模板卡片自适应换列,页面不出现水平滚动,每张卡片的编辑和删除按钮直接可见。 |
| TC-ADMIN-ENTERPRISE-TEMPLATE-RESPONSIVE-001 | 在 1024px、1366px 和宽屏视口打开运营端“企业模板管理”,查看长企业名、长模板内容和包含多变量的真实记录。 | 列表行按视口自适应重排,无水平滚动;预览、编辑、删除始终可见且可操作,内容摘要不撑破容器。 |
| TC-ADMIN-ENTERPRISE-SIGNATURE-LAYOUT-001 | 在运营端“企业签名管理”打开移动/联通/电信显示“未报备(0/2)”的真实签名,分别使用 1024px 和 1366px 视口。 | 状态标签和数量可分行但各自保持完整;四个操作按钮按两列两行排列,文字不被挤成单字换行,卡片不产生水平滚动。 |
| TC-ADMIN-ENTERPRISE-SIGNATURE-COLOR-001 | 使用真实签名和通道任务分别覆盖草稿、待审核、审核驳回、未报备、报备中、资料待补充、部分通过、全部通过和报备失败。 | 总体色条依次遵循审核优先、报备汇总次优先;全部通过为绿、部分通过为蓝、处理中或待补资料为橙、失败为红、未开始或不适用为灰。三网标签使用同一语义,“报备中”不得显示成“部分通过”的蓝色。 |
| TC-ADMIN-ENTERPRISE-SIGNATURE-SELECT-001 | 在运营端打开“添加签名”,展开企业下拉并输入部分名称,选择企业后再展开企业应用;分别使用常规高度和 600px 高视口。 | 两个下拉均通过浮层完整显示在弹窗和底部操作栏之上,可搜索、滚动并选择真实 API 选项;空间不足时自动向上展开,列表不被裁剪。 |
| TC-ADMIN-REPORT-FIELD-CODE-001 | 在报备字段库分别提交 `License2026`、`license_code`、中文和空白代码,并直接调用真实新增 API 复验。 | 只有 `License2026` 写入 PostgreSQL;前端阻止非法值,API 同样返回 400,不依赖前端校验。 |
| TC-ADMIN-CHANNEL-REPORT-SIGNATURE-001 | 打开包含数据库签名 `【安徽航天信息】` 的通道报备详情及签名详情弹窗。 | 两处均只显示单层 `【安徽航天信息】`,不出现重复中括号。 |
| TC-MOCK-CLEAN-003 | 运营端创建企业、编辑企业、禁用/启用企业、删除企业,再刷新页面和重新登录客户端。 | Tenant 状态持久化;列表刷新后状态不丢;禁用/删除企业阻断客户端业务访问;动作写系统日志。 |
| TC-MOCK-CLEAN-004 | 客户端提交签名材料文件、创建模板并提交审核,运营端查看企业签名和企业模板列表。 | 文件元数据和材料关联写入后端;签名/模板进入真实审核状态;运营端列表可查到同一条记录。 |
| TC-MOCK-CLEAN-005 | 运营端短信审核通过、批量通过、驳回风控审核任务。 | 调用 `admin/risk-review/tasks` 真实接口;通过必须弹窗确认;状态刷新后仍持久化;不再显示固定手机号样例。 |
| TC-MOCK-CLEAN-006 | 运营端短信记录按手机号、状态、日期和内容查询,打开详情。 | 数据来自 `sms_message_records`;详情展示真实 messageId、状态、失败原因;无数据时为空态。 |
| TC-MOCK-CLEAN-007 | 访问明确标注待开发的彩信菜单。 | 可以显示待开发/空态;不得作为第一版短信真实功能通过依据。 |
| TC-PHONE-SEGMENT-001 | 生产库存在 50 万级手机号段时打开手机号段库,连续点击下一页、上一页,并按号段、省份、城市或运营商搜索。 | 页面数据来自真实数据库,可按服务端 `total/page/pageSize` 稳定分页和搜索;Tab 位于标题下、搜索条件上。手机号段 Tab 只显示号段总数,运营商区分规则 Tab 只显示规则总数,切换时不同时展示两个统计。 |
### 17.11 下游投递 ACK 与应用级重试策略
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-GW-ACK-001 | 客户在线时分别触发一条状态回执和一条上行短信,Gateway `SendPkt` 成功后延迟返回 `CMPP_DELIVER_RESP`。 | 写出后 `CmppDownstreamDelivery.status=awaiting_ack`;只有匹配连接、Sequence_Id、Msg_Id 且 Result=0 后才变为 `delivered`,并保存写出时间、确认时间、ACK 字段和连接 ID。 |
| TC-GW-ACK-002 | 分别返回非零 Result、不返回响应直到超时、重启 Gateway 后让旧 `awaiting_ack` 超时。 | 非零 Result 和超时不会误记为 deliveredGateway 重启后 NestJS 能恢复过期 ACK,按策略进入退避重试或最终 `rejected/unconfirmed`。 |
| TC-GW-ACK-003 | 在企业应用中分别关闭“回执自动重试”和“上行短信自动重试”,各制造一次 ACK 超时,再重新开启并创建新投递。 | 关闭只影响对应类型的新投递策略快照;离线后的首次投递仍会在重连时执行;已写出未确认的记录不自动重发;重新开启后新记录按退避策略重试。 |
| TC-GW-ACK-004 | 对 `unconfirmed/rejected/failed/delivered` 记录执行单条和批量手工重投。 | 页面提示重复处理风险并二次确认;真实调用 Gateway;`awaiting_ack` 不允许并发重投;重发复用同一业务 Msg_Id。 |
| TC-GW-ACK-005 | 客户 Submit 后由业务校验立即生成失败回执,并覆盖在线即时投递、Gateway 重启后恢复投递;另模拟客户端对 `Msg_Id=0` 返回 Result=0。 | 客户收到的第一个响应包必须是对应 `CMPP_SUBMIT_RESP`,之后 Deliver 的 `Msg_Id` 非 0 且与 SubmitResp 完全一致;重启后根据持久化 Submit Sequence_Id 重建同一 Msg_IdResult=0/Msg_Id=0 不得写为 delivered。 |
| TC-GW-ACK-006 | 对一条 Gateway 已丢失原消息映射且 payload 缺少 `submitSequenceId` 的历史状态回执执行人工重投;另对字段完整但客户离线的记录重投。 | 缺少序列号的记录由 Gateway 返回 `retryable=false/MISSING_SUBMIT_SEQUENCE_ID`NestJS 立即终结为 `failed` 并保存明确原因;客户暂时离线的记录返回 `retryable=true/CLIENT_DISCONNECTED`,按次数上限和指数退避继续处理,不得无限保持 `retryCount=0`。 |
| TC-GW-ACK-007 | 构造一条从未重投且 pending 超过 72 小时的记录,以及一条人工重投后尚未满 72 小时但原 `createdAt` 很早的记录,执行自动扫描并查看告警。 | 第一条自动转为 `failed/queue_timeout`;第二条仍保持 pending,终结时间和 10 分钟积压告警均从 `lastRetriedAt` 重新计算,刚重投后不立即告警。 |
### 17.12 签名与引流资料导入及统一通道报备
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-REPORT-MATERIAL-IMPORT-001 | 将含两行表头、文本列和营业执照/身份证等内嵌图片的 WPS 在线表格另存为 `.xlsx`,选择企业、应用和签名资料后解析。 | NestJS 读取真实工作表及图片锚点,返回列、组合表头、前十行和图片数预览;原文件写 MinIO,导入批次写 PostgreSQL;解析和提交审核均不直接修改签名、不建通道任务。 |
| TC-REPORT-MATERIAL-IMPORT-002 | 将源列映射到签名及动态报备字段后提交导入,再进入短信签名审核的“导入批次审核”页签查看100行数据并一次通过其中勾选的多行。 | 每行先以新增/修改/无效状态落待审核明细;只有通过行才创建或修改真实签名并写审核人、审核时间,随后进入待生成资料池;未选行保持待审核,页面不要求逐行打开确认。 |
| TC-REPORT-MATERIAL-IMPORT-003 | 导入引流资料,其中一行引用不存在或未审核签名;在引流审核页批量通过合法行并驳回部分行,不填写驳回原因。 | 合法行审核通过后创建/更新真实 `SmsDrainageInfo` 并进入待生成池;非法行保留行号和原因;空驳回原因可正常提交,同批其他行不受影响,也不自动创建通道报备任务。 |
| TC-REPORT-MATERIAL-IMPORT-004 | 导入文件中同时包含已存在对象的修改和不存在对象的新增,提交审核前后分别读取业务表。 | 提交审核前业务表完全不变;审核页展示新增/修改及原数据快照;通过后才应用变更,重复点击已处理行不会再次递增材料版本或重复创建对象。 |
| TC-REPORT-MATERIAL-IMPORT-005 | 分别在签名和引流审核页面按文件名、状态、时间筛选导入批次,翻页后选择整批或部分明细审核。 | 查询、总数和分页来自真实后端;批次汇总待审、通过、驳回、无效数量,刷新后保持一致。 |
| TC-REPORT-CHANNEL-FIELD-001 | 在同一通道分别打开签名和引流字段配置,添加字段、修改通道表头、上下排序、设置必填/列宽/图片宽高后保存并刷新。 | 两类配置相互独立且完整持久化;刷新后字段池、映射表头和顺序一致;重复字段、停用字段和非法尺寸由 API 拒绝或归一化。 |
| TC-REPORT-BATCH-001 | 一个应用配置两个生效通道,选择一个待报备签名创建统一批次。 | 系统从真实应用路由展开两个通道,生成两个独立通道任务和两个 `.xlsx`;每个文件表头名称、列顺序和列宽均来自对应通道配置,批次可下载两份文件。 |
| TC-REPORT-BATCH-002 | 两个通道对同一标准字段配置不同表头和顺序,并包含图片列,生成批次后分别用 WPS 打开。 | 两份工作簿各自使用对应通道映射,图片直接显示在数据行内且尺寸按通道配置;文件不是 URL 清单,文本与图片属于同一材料快照。 |
| TC-REPORT-BATCH-003 | 分别制造无生效路由、通道未配置字段、缺少通道必填图片,再创建批次。 | 对应资料不会清除待报备标记;有通道但资料不全时任务为 `waiting_material` 并记录原因;批次为部分失败,无任何假成功任务。 |
| TC-REPORT-BATCH-004 | 同一签名修改资料后再次选择生成批次。 | 材料版本递增;复用同一签名/通道任务并重置到新一轮状态,批次项目保留当次版本和快照,历史导出文件仍可追溯。 |
| TC-REPORT-BATCH-005 | 打开“待生成报备批次”,分别切换“待生成资料”和“已生成批次”,按时间范围和关键字查询并翻页。 | 两个页签均使用后端分页与时间查询;切换、重置筛选后查询条件正确,不读取上一页签的旧条件。 |
| TC-REPORT-BATCH-006 | 生成包含3条通道报备明细的批次,将其中2条任务人工改为通过后刷新已生成批次。 | 批次显示报备总数3、成功数2、成功率66.67%;不显示已导入回执或等待回执。 |
| TC-REPORT-BATCH-007 | 在桌面宽度分别查看待生成资料和已生成批次搜索区,再缩窄至平板宽度。 | 待生成资料关键字框宽度适中、资料变更时间有足够空间;已生成批次时间框保持紧凑;两个页签查询/重置按钮等宽,平板宽度自动换为两列且不横向溢出。 |
| TC-REPORT-TASK-STATUS-001 | 在报备明细页逐条修改签名或引流信息的通道状态,分别填写和不填写修改原因。 | 两种操作均成功;状态和时间轨迹写真实任务/记录,原因空时不阻断提交;页面无生成同范围任务和导入回执入口。 |
### 17.13 Gateway 提交异常与通道级 TPS 限速
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-GW-SUBMIT-EXCEPTION-001 | 制造一条超过 Gateway 最大处理次数的真实 `SubmitCommand`,打开运营端“网关异常”的“提交异常”Tab,按状态、应用、通道和关键字筛选并查看详情。 | 记录写入 PostgreSQL,页面汇总、分页和详情来自 NestJS API;手机号脱敏,命令中的密码、密钥和原始 payload 不返回浏览器,页面不使用“死信”作为业务名称。 |
| TC-GW-SUBMIT-EXCEPTION-002 | 对短信仍处于 pending/failed、通道 active 且 connected 的异常记录,输入 5~500 字原因,勾选“已确认上游未受理”并重新入队。 | 近期认证通过后服务端原子抢占记录、真实写入 Redis Stream;记录变为 requeued,人工次数、操作人、原因、Stream ID 和时间完整留痕,收到 SubmitResult 后变为 resolved。 |
| TC-GW-SUBMIT-EXCEPTION-004 | 对一条`pending`提交异常点击“已处理”,在确认弹窗中取消后再次确认。 | 取消不调用接口;确认后仅将记录原子更新为`resolved/manually_resolved`,保留原异常和命令证据并写操作日志,不写Redis Stream、不触发短信提交;非`pending`记录不展示按钮且后端拒绝并发变更。 |
| TC-GW-SUBMIT-EXCEPTION-003 | 不勾选确认、原因过短、重复点击同一记录,或分别把短信置为 accepted/submitted/delivered/unknown、把通道置为停用/断开、人工重试达到 3 次后尝试重新入队。 | API 拒绝危险或重复操作,不产生额外 Stream 命令;页面显示可读原因,操作日志不伪造成功。 |
| TC-GW-RATE-001 | 给通道 A 配置 10 TPS,连续投递 20 条;通道 B 同时配置 20 TPS 并投递,另让提交命令携带高于通道配置的数值。 | Gateway A 实际提交节奏不超过 10 TPS,B 独立按自身额度执行;消息值不能放大 A 的权威上限,同一通道跨通道组共享额度。 |
| TC-GW-RATE-002 | 超过通道 TPS 后观察 Redis Stream consumer group,并在存在等待消息时重启 Gateway。 | 超流速消息保留在 Stream pending,不直接失败;重启后通过 PEL/XAUTOCLAIM 恢复并继续按通道 TPS 排队提交,不丢失、不重复 ACK。 |
| TC-GW-RATE-003 | 启动两个共享同一 Redis 的 Gateway 消费实例,同时向同一通道发送,再向两个不同通道发送。 | 同一通道的两个实例共享 Redis 限速额度,总 TPS 不叠加;不同通道使用独立 key,不被合并成平台总 TPS。 |
| TC-GW-RATE-004 | 在存在 active 上游通道时按生产脚本顺序重启 Gateway 和 API,随后检查 Gateway 日志、连接状态与 Redis。 | Gateway 先启动,API 随后重新下发全部 active 通道连接命令;Gateway 内存连接池恢复,数据库状态反映本次真实连接结果,并生成 `rate:gateway:channel:config:<channelId>`,不沿用重启前的假 connected。 |
### 17.14 HTTP 客户接口、上行查询与 Webhook
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-HTTP-CONFIG-001 | 运营端编辑企业应用,独立开关 CMPP 与 HTTP,并配置发送/查询/回调子能力、独立 IP 白名单、QPS、投递模式和 Webhook 策略,保存后刷新。 | 配置写入 `SmsApplicationHttpConfig` 和 HTTP 白名单表;CMPP 原配置不丢失;刷新一致;关闭某项能力后对应 OpenAPI 返回稳定 403 业务码。 |
| TC-HTTP-CONFIG-002 | 打开运营端企业应用新增/编辑页,分别开关 CMPP 与 HTTP,并在桌面及 390px 小屏检查两块配置。 | CMPP 与 HTTP 以两个独立区块展示;CMPP 区不出现 HTTP 参数,HTTP 区不出现 CMPP 账号、密码或白名单;关闭某协议后仅收起该协议参数且不影响另一协议区域;小屏无页面级横向滚动。 |
| TC-HTTP-AUTH-001 | 使用正确 Access Key/Secret 按原始请求体签名,再分别修改 path、body、timestamp、nonce、来源 IP 和签名。 | 正确请求通过;篡改项返回 `application/problem+json`;过期时间、重复 nonce、白名单外 IP 和错误签名被拒绝;错误签名不得提前占用 nonce。 |
| TC-HTTP-AUTH-002 | 同一应用一秒内并发调用超过配置 QPS,再在下一秒继续调用。 | Redis 应用级额度不被多个凭据放大;超额返回 429,下一秒恢复;不依赖单进程内存计数。 |
| TC-HTTP-CREDENTIAL-001 | 客户创建第一把凭据、保存 Secret,再创建第二把完成切换并吊销第一把;刷新页面和查看数据库。 | Secret 仅创建当次可见,数据库为 AES-256-GCM 密文;列表只显示末四位;两把凭据轮换期可并存,吊销后旧凭据立即返回 401。 |
### 17.11 全平台金额四位小数精度
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-MONEY-001 | 运营端编辑企业应用,将客户单价填写为 `0.0325` 并保存,刷新列表后再次进入编辑页。 | 保存调用真实 NestJS API;数据库 `SmsApplication.customerUnitPrice=325`;列表和编辑页均展示 `0.0325`,不被舍入为 `0.03`。 |
| TC-MONEY-002 | 使用单价 `0.0325` 的应用发送 2 个计费条数。 | 预估、冻结及最终计费金额均为 `650` 金额单位,即 `0.0650 元`;返还时按相同精度原额冲回。 |
| TC-MONEY-003 | 分别设置余额、授信、充值、今日消费和今日返还为含 4 位小数的金额,查看运营端企业列表、详情、首页以及客户端首页和账单。 | 所有位置展示同一真实金额且固定为 4 位小数,不使用浮点累计或仅保留到分。 |
| TC-MONEY-004 | 打开短信详单、对账单、利润报表并导出 CSV。 | 短信详单消费金额以及利润报表收入、成本和利润均按 4 位小数显示;CSV 表头以“元”为单位,值固定 4 位小数,汇总结果与数据库整数金额单位一致。 |
| TC-MONEY-005 | 在迁移前备份数据库并记录各金额列汇总,执行四位精度迁移后复核字段类型及汇总。 | 金额列升级为 `BIGINT`;迁移后整数汇总等于迁移前的 100 倍,按新除数换算后的人民币金额完全相等。 |
| TC-MONEY-006 | 在单价、授信和充值输入中分别填写超过 4 位小数、非法字符和超出 JavaScript 安全整数范围的值。 | 前后端拒绝无效值并返回可读错误;API 不静默舍入或输出已失真的金额。 |
| TC-IF-PARAM-001 | 运营端分别打开已开通 CMPP、HTTP 的企业应用参数弹窗并一键复制;模拟 Clipboard API 在 HTTP 页面被拒绝。 | CMPP 内容展示平台公网地址和端口而非上游通道地址;HTTP 内容包含应用、能力、QPS、白名单、投递模式和文档地址;降级复制成功且有明确提示。 |
| TC-IF-PARAM-002 | 客户端查看未开通 CMPP 的应用并直接调用该应用 CMPP 参数 API。 | 页面复制按钮禁用;真实 API 返回 403,不泄露账号、密码、接入号等参数。 |
| TC-IF-PARAM-003 | 客户端在已开通 HTTP 的应用“接口对接”页复制 HTTP 参数,再关闭 HTTP 后复测。 | 开通时复制真实 HTTP 配置;关闭时按钮不可用且不生成参数文本。 |
| TC-CMPP-DOWNSTREAM-001 | 将应用最大连接数设为 2,依次建立 3 条 CMPP TCP 连接,断开其中一条后再次连接。 | 前 2 条 bind 成功,第 3 条被拒绝;断开后名额立即释放,新连接可成功;连接记录与真实 TCP 会话一致。 |
| TC-CMPP-DOWNSTREAM-002 | 已建立连接后修改应用 IP/CIDR 白名单为不包含当前来源 IP,或将最大连接数降至当前连接数以下,等待下一次心跳。 | API 拒绝连接事件,Gateway 主动关闭不符合配置的存量连接并回写断开原因;连接数不继续显示为正常。 |
| TC-HTTP-SEND-001 | 调用单条发送接口,使用真实已审核签名/模板、余额和通道路由。 | 返回 202 和平台 messageId;真实创建 API 来源批次与短信记录,执行风控、冻结/计费并进入 Redis/BullMQ/Gateway 链路;不得使用静态数组或直接伪造 delivered。 |
| TC-HTTP-IDEMPOTENCY-001 | 并发使用相同 `Idempotency-Key` 和相同 body 调用,再用相同 key 改变 body;另重复 clientMessageId。 | 只创建一条真实短信;完成后同内容重放原响应,处理中返回 409 processing;不同 body 返回 409 conflict;应用内重复 clientMessageId 被拒绝。 |
| TC-HTTP-QUERY-001 | 用本应用凭据按 messageId/clientMessageId 查询本应用和其他应用短信。 | 只返回当前应用短信状态、提交/回执时间和失败信息;其他应用记录统一 404,不泄露租户数据。 |
| TC-HTTP-UPLINK-001 | 查询默认 24 小时上行,组合手机号、接入号、关键词、时间和 cursor;构造匹配、歧义和未匹配记录。 | 只返回已匹配或人工认领到当前应用的记录;按 `(receivedAt,id)` 稳定倒序游标分页;超查询范围和非法 cursor 返回 400;歧义/未匹配不泄露。 |
| TC-HTTP-WEBHOOK-001 | 配置 HTTP 或 both 投递,分别触发终端回执、平台失败回执、自动匹配上行和人工认领上行。 | 事件只在真实记录落库后产生;HTTP 模式不创建 CMPP 投递,both 同时创建两条独立链路;eventId 唯一,payload 包含可关联 messageId/uplinkId。 |
| TC-HTTP-WEBHOOK-002 | 回调依次返回 500、429、408、400、302 和 200,并模拟超时。 | 500/429/408/网络错误按既定退避重试,400 和重定向终结,2xx 成功;每次尝试、状态码、耗时和截断响应写 PostgreSQL,可授权手工重投。 |
| TC-HTTP-WEBHOOK-003 | 保存指向 localhost、RFC1918、链路本地、共享地址、云元数据 IP、会解析到私网的域名和发生 DNS 重绑定的 URL。 | 保存或投递前被 SSRF 校验拒绝;不跟随重定向;生产 HTTPS 约束开启时 HTTP URL 被拒绝。 |
| TC-HTTP-CLIENT-001 | 客户端打开“接口对接”五个页签,切换应用、创建凭据、配置回调、查看文档与日志;API 断开后重试。 | 所有状态来自真实 API/PostgreSQL/Redis;应用卡片显示 HTTP 状态;API 失败展示错误,不使用 localStorage 或前端静态数据伪造成功。 |
| TC-HTTP-PUBLIC-ORIGIN-001 | 将管理页面部署在 `https://sms.lisglo.com`,设置 `HTTP_API_PUBLIC_ORIGIN=https://api.lisglo.com`,分别在运营端参数弹窗和客户端接口对接页查看并复制参数。 | 页面展示、复制内容和 Swagger 链接均使用 `https://api.lisglo.com`;灰云域名的四个开放接口及文档可访问,admin/client 管理接口和前端页面返回 404;不回退为管理页面域名。 |
### 17.15 手工验收瑕疵回归
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-DEFECT-001 | 分别选择 2MB 与超过 2MB 的图片、10MB 与超过 10MB 的普通文件,并绕过前端直接请求上传 API。 | 边界值可上传至 MinIO,超限在前端即时拒绝且 API 再次返回 400,MinIO 无超限对象。 |
| TC-DEFECT-002 | 新建/编辑企业,输入中文、标点和英文数字信用代码,上传长文件名执照并预览/下载。 | 非英文数字被拒绝,合法值真实入库;文件名换行且两个操作样式一致。 |
| TC-DEFECT-003 | 编辑一个 HTTP 未开通的应用,切换为开通并保存,刷新后查看/复制 HTTP 参数。 | 六项能力全部开启,回执/上行为 HTTP Webhook,配置真实写入 PostgreSQL,复制内容不显示原始枚举值。 |
| TC-DEFECT-004 | 企业应用列表保持相同条件连续点击查询/重置,打开包含长 ID 的 CMPP 连接详情;短信记录同样操作。 | 每次均有真实 API 请求且数据更新;弹窗无水平滚动,长 ID 自动换行。 |
| TC-DEFECT-005 | 通过/驳回一条待审短信并查看列表、更多信息及导航角标。 | 审核人/时间由当前会话写库,时间格式正确,列表不额外占列,角标不等待 30 秒轮询即更新。 |
| TC-DEFECT-006 | 打开真实短信详情,再新增后删除一条运营商区分规则。 | 详情分别展示 `clientSrcId` 与通道 `srcId + applicationExtension`;运营商显示中文,DELETE API 真实删库并刷新。 |
| TC-DEFECT-007 | 用登录运营用户修改企业应用及其他任一写操作,再查看系统日志;另构造失败请求。 | 成功写操作均有操作人、路径、资源和结果日志;失败请求不写伪成功日志。普通HTTP业务操作日志不保存请求体、密码或密钥;仅`cmpp_connection.connect_requested`按连接诊断要求保存客户实际提交的认证参数,且不得写入平台保存的密钥。 |
### 17.16 2026-07-20 缺陷回归
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-RECEIPT-IDENTITY-001 | 两个通道使用同一下游账号及相同通道 Msg_Id,分别向两个号码提交,再乱序返回回执。 | 以通道、通道 Msg_Id 和号码唯一关联提交记录;主记录写入正确通道、到达时间、原始状态和文本,无跨通道抢占。 |
| TC-RECEIPT-IDEMPOTENT-001 | 顺序和并发重复发送相同 DELIVRD,随后重启服务并再次发送。 | `receiptKey` 唯一约束保证只保存一次、只下发一次客户回执,且不重复计费或退款;重启后行为一致。 |
| TC-REPORT-RECALC-001 | 插入一条成功、一条失败及扣费/退款流水,执行指定日期重算两次,再查询应用和通道报表及 CSV。 | 两次结果一致;发送 2、成功 1、失败 1;收入、退款、成本和利润使用相同金额单位且 `利润=收入-成本`;平均到达时长来自真实提交/回执时间。 |
| TC-USER-SAFE-001 | 分别查询运营端、客户端用户列表和详情,并尝试跨租户访问。 | 响应不含 `passwordHash`、`sessionVersion`、密钥或认证内部字段;跨租户查询、更新、改密、禁用和删除由 API 拒绝。 |
| TC-USER-CONTINUITY-001 | 当前用户删除/停用自己,删除或降权最后一个平台管理员、删除或停用最后一个企业管理员,并创建重复用户名。 | 自删除/自停用返回403;最后一个平台管理员保护生效;最后一个企业管理员允许删除或停用;唯一冲突返回409和冲突字段,不出现500。 |
| TC-HTTP-SEND-002 | 仅传 `mobile/content`,正文使用已审核签名及 `${code}` 模板,调用公开发送接口并重放同一幂等键。 | 自动识别签名/模板并提取合法变量,经真实发送链返回 202、稳定 messageId;相同请求返回同一结果,不出现批次 404。 |
| TC-TEMPLATE-VARIABLE-001 | 提交空变量、未闭合、中文、重复、超长和非法字符变量,再查看发送候选。 | 前后端均拒绝非法变量;候选只含 approved 签名/模板,disabled/rejected 仅在历史管理视图显示。 |
| TC-REPORT-MATERIAL-SAFE-001 | 下载官方 XLSX;按筛选导出;导入空文件、错误扩展名、超限文件、含公式/脚本单元格及部分错误行文件。 | 模板和导出为真实 XLSX;危险文件在入库前拒绝,部分失败保留行级原因;日志含操作人、文件名、筛选和计数,不含敏感请求体。 |
### 17.16 客户端用户管理移动操作可达性回归
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-UIUX-P0-001 | 使用真实企业管理员登录客户端并打开`/client/users`,依次设置390×844和375×667。 | 真实`/api/client/users`返回的用户以卡片显示;编辑、改密、禁用/启用、删除形成2×2操作网格,全部位于视口和卡片裁切范围内。 |
| TC-UIUX-P0-002 | 在390和375视口测量四个操作按钮并逐项执行命中测试。 | 每项高度至少44px,中心点命中自身按钮,页面根节点无横向溢出;操作组可访问名称包含目标用户。 |
| TC-UIUX-P0-003 | 在375视口点击删除,读取确认内容后点击取消。 | 确认层显示目标用户名;取消后用户仍在列表,PostgreSQL记录保持active且没有执行删除。 |
| TC-UIUX-P0-004 | 依次设置768×1024、1366×768、1440×900并复核同一用户。 | 平板四项操作全部可见且热区≥44px;1440首屏完整;1366即使存在内部横向滚动,滚动后删除必须完整可达,且页面级无横向溢出。 |
| TC-UIUX-P0-005 | 完成五视口操作后检查浏览器控制台并执行前端/API构建与用户服务回归。 | 无新增console error/warn;前端与API build通过,用户服务测试通过,`git diff --check`通过。 |
### 17.17 用户登录标识复用、组合查询与管理员保护提示
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-USER-REUSE-001 | 新建用户名`zhaohui`,逻辑删除后再次使用同一用户名、邮箱或手机号新建用户。 | 新用户创建成功且主键与旧用户不同;旧用户及其OperationLog、审核关联保持原用户主键;登录只命中新用户。 |
| TC-USER-REUSE-002 | 两个未删除用户并发提交相同用户名、邮箱或手机号。 | PostgreSQL仅允许一个请求成功,另一个返回HTTP 409、`USER_DUPLICATE`、冲突字段和中文提示,不产生两个活动账号。 |
| TC-USER-FILTER-001 | 在运营端分别及组合填写用户姓名、登录账号、所属企业、用户角色和状态,点击查询,再点击重置;分别使用桌面和移动视口检查筛选布局。 | 每次操作请求真实`GET /api/admin/users`;条件分别生效,组合使用AND,登录账号匹配用户名/邮箱/手机号;重置返回全部未删除用户。五组条件按共享宽度自然换行,不被压缩或截断;移动端条件整行展示,查询/重置与“新增用户”分区清晰且均可操作。 |
| TC-USER-FILTER-002 | 在客户端分别及组合填写用户姓名、登录账号和状态。 | 请求真实`GET /api/client/users`;只返回当前企业管理员,无法通过查询参数跨租户或查询平台管理员。 |
| TC-USER-CONTINUITY-UI-001 | 删除、禁用或降权最后一个平台管理员,再删除或停用某企业最后一个启用管理员。 | 平台管理员操作由后端权威拦截并在确认弹窗显示建议;企业管理员操作成功且可归零;按钮结束忙碌状态,浏览器无未处理Promise。 |
| TC-USER-CONTINUITY-UI-002 | 为相同范围增加另一名启用管理员后重复删除或禁用。 | 操作成功、弹窗关闭、列表按当前已应用查询条件刷新,并写入对应OperationLog。 |
### 17.17 2026-07-21 下游连接恢复与历史回执回填
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-CMPP-DOWNSTREAM-NULL-001 | 创建一条 `status=connected`、`lastHeartbeatAt=NULL` 且 `connectedAt` 早于心跳阈值的客户接入连接,再触发新连接登记。 | 陈旧记录在连接数校验前删除,新连接不被错误的 `cmppMaxConnections` 拒绝;Gateway 能继续读取 Submit。 |
| TC-CMPP-DOWNSTREAM-NULL-002 | 创建一条刚建立、`lastHeartbeatAt=NULL` 但 `connectedAt` 尚未超过阈值的连接并执行清理。 | 新连接保留,不因首次心跳尚未写入而误删。 |
| TC-RECEIPT-BACKFILL-001 | 构造两个供应商通道共用账号,历史 DELIVRD 被写到错误通道,但同一主记录、Msg_Id、号码只有一条匹配提交记录,执行迁移两次。 | 回执改绑到唯一提交通道;主记录同步为 delivered 并写入回执状态、原始码、通道消息号和到达时间;重复执行结果不变。 |
| TC-RECEIPT-BACKFILL-002 | 构造同一历史回执能匹配零条或多条提交记录的歧义样本。 | 迁移不修改回执和主记录,保留人工核查,不以账号或模糊 Msg_Id 强行归属。 |
| TC-REPORT-BACKFILL-001 | 历史回执迁移后执行 T-4 至 T-1 重算,查询对账、利润、质量及 CSV。 | 历史成功数、收入、成本、利润和平均到达时长反映修复后的主记录与提交/回执;重复重算一致。 |
| TC-DICTIONARY-DUPLICATE-001 | 对活动或逻辑删除的全局/企业黑名单重复创建相同手机号。 | 后端返回 HTTP 409、`BLACKLIST_DUPLICATE` 和 `phoneNumber` 字段提示,不返回 500,也不创建重复数据。 |
### 17.18 双门户会话隔离、深链与锁定恢复
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-SESSION-DEEPLINK-001 | 未登录直接打开客户端13条受保护路由,完成验证码登录后逐条刷新。 | 登录页说明将恢复目标;登录后返回原深链;13条路由刷新后 URL 和客户端身份不变,数据来自真实 API。 |
| TC-SESSION-PORTAL-001 | 在同一浏览器先后登录运营端与客户端,并分别访问受保护页面。 | 浏览器同时持有独立 admin/client Cookie 和 localStorage;两端显示各自身份,不互相覆盖或错跳门户。 |
| TC-SESSION-LOGOUT-001 | 两端同时登录时退出客户端,再刷新运营端;反向重复。 | 只删除和广播当前门户会话;另一门户会话、页面与 Redis 记录继续有效。 |
| TC-SESSION-LOCK-001 | 锁定运营端会话,同时请求客户端当前会话;刷新锁定页面并输入当前密码解锁。 | 运营端返回 locked、客户端仍 active;锁定页说明解锁后返回当前页;解锁轮换当前门户 Cookie,原 URL 与业务数据恢复。 |
| TC-SESSION-COOKIE-001 | 同时携带 admin/client Cookie 请求两端接口,并仅携带错误门户 Cookie 重试。 | 中间件只读取路径对应 Cookie;错误门户 Cookie 返回401且不会尝试认证或泄露另一门户状态。 |
## 2026-07-21 UI/UX A2安全上传与日志导出用例
- `TC-UIUX-A2-UPLOAD-001`:客户端带伪造`x-tenant-id`上传允许用途文件,数据库`FileObject.tenantId`仍等于当前会话用户企业,MinIO对象可经客户端下载接口读回。
- `TC-UIUX-A2-UPLOAD-002`:任意用途、目录穿越和跨企业文件下载分别返回4xx,且拒绝发生在对象存储写入前。
- `TC-UIUX-A2-EXPORT-001`:两端按当前筛选导出真实日志,按钮在请求期间禁用;成功显示记录数、截断提示、操作单号和下载入口,重复点击不产生并发请求。
- `TC-UIUX-A2-EXPORT-002`:客户端忽略请求体租户,只导出当前企业;CSV表头不包含详情、IP、User-Agent,危险公式前缀被转义。
- `TC-UIUX-A2-EXPORT-003`:导出失败后页面保留筛选并提供原地重试;会话跳转恢复后可读取当前门户专用瞬时恢复条件,不错跳另一门户。
## 2026-07-21 UI/UX A3审核风险治理用例
- `TC-UIUX-A3-REVIEW-001`:待审签名缺应用、企业资料或资质文件时,预检返回具体`blockedReasons``allowedActions`不含`approve`,直接提交批准同样返回4xx。
- `TC-UIUX-A3-REVIEW-002`:完整待审签名/模板打开通过确认层,展示名称、ID、企业、应用、资格结果和影响;取消不改变数据库状态。
- `TC-UIUX-A3-REVIEW-003`:确认后按钮立即进入提交中并禁止重复点击;成功返回审计操作单号,AuditRecord记录当前会话审核人、前后状态和幂等标识。
- `TC-UIUX-A3-REVIEW-004`:相同幂等键重复请求返回同一操作单号及`replayed=true`,数据库只有一次状态变更;相同键用于不同决定返回409。
- `TC-UIUX-A3-REVIEW-005`:两个审核员使用同一`expectedUpdatedAt`并发决策,仅一个`updateMany`成功,另一个返回`REVIEW_VERSION_CONFLICT`且不得覆盖赢家。
## 2026-07-21 UI/UX A4报备生成风险治理用例
- `TC-UIUX-A4-REPORT-001`:已审核资料未绑定应用、应用停用或没有启用路由时调用预检;返回`eligible=false`和具体阻断原因,列表复选框及生成按钮不可用。
- `TC-UIUX-A4-REPORT-002`:应用路由到启用通道,但通道缺当前资料类型字段或资料缺必填值;预检逐通道返回缺失项,零可生成目标不得创建`ReportMaterialBatch`、任务或文件。
- `TC-UIUX-A4-REPORT-003`:完整资料打开生成确认层;显示企业、应用、资料版本、预计通道、运营商及成功/跳过计数,取消后数据库无批次、任务和文件变化。
- `TC-UIUX-A4-REPORT-004`:相同资料版本、应用、通道和运营商已存在成功批次时再次预检;返回既有批次并跳过。资料版本或路由运营商变化后使用新的业务键重新评估。
- `TC-UIUX-A4-REPORT-005`:相同幂等键并发或重试生成同一范围,仅产生一次批次并返回同一操作单;相同键改换资料范围返回409;按钮在请求中禁止重复提交。
- `TC-UIUX-A4-REPORT-006`:在1440×900、1366×768、768×1024、390×844和375×667打开确认层;页面无横向溢出,弹窗完整位于视口且成功/跳过/失败、取消和确认操作均可见,控制台无error/warn。
## 2026-07-21 UI/UX A5删除治理用例
- `TC-UIUX-A5-DELETE-001`:活动通道组引用通道时打开删除确认层;真实预检返回引用数量、组名和优先级,`allowedActions`为空,前后端均禁止删除且通道状态不变。
- `TC-UIUX-A5-DELETE-002`:签名仍被未删除模板、引流信息或未结束报备任务引用;运营端和客户端均显示租户内依赖摘要并禁止删除,客户端不能读取其他企业对象。
- `TC-UIUX-A5-DELETE-003`:模板即使存在未结束发送或批量任务也允许逻辑删除,返回操作单号;PostgreSQL模板状态为`deleted`,既有任务、消息和历史关联不变,OperationLog包含依赖快照、影响和幂等键。
- `TC-UIUX-A5-DELETE-004`:相同删除幂等键重试返回相同操作单号且不重复审计;旧版本并发提交返回409并要求重新预检;旧删除接口不能绕过治理规则。
- `TC-UIUX-A5-DELETE-005`:在1440×900、1366×768、768×1024、390×844和375×667打开依赖确认层;对象、依赖、影响和底部操作可滚动到达,无页面级横向溢出,控制台无error/warn。
## 2026-07-21 UI/UX A6人工充值治理用例
- `TC-UIUX-A6-RECHARGE-001`:两个人工充值入口分别输入金额和备注后点击取消、右上角关闭,再次打开;金额、备注、预检和幂等状态均为空,不产生订单、流水或余额变化。
- `TC-UIUX-A6-RECHARGE-002`:输入正数或负数金额进入核对;后端返回企业名称/编码/ID、当前余额、方向、变动和预计余额,页面完整展示,返回修改不入账。
- `TC-UIUX-A6-RECHARGE-003`:最终确认后只生成一个RechargeOrder、一个AccountTransaction和一个OperationLog,账户余额等于前余额加变动金额;响应显示订单号、后余额和操作单号,操作者来自当前会话。
- `TC-UIUX-A6-RECHARGE-004`:相同幂等键并发或重试同一请求返回相同订单与操作单且`replayed=true`;键用于不同企业/金额返回409。预检后账户版本变化,旧确认请求返回409且不产生部分数据。
- `TC-UIUX-A6-RECHARGE-005`:在1440×900、1366×768、768×1024、390×844和375×667打开核对层;资金摘要、返回和最终确认可滚动到达,控制台无error/warn。
## 2026-07-22 UI/UX A7公共Dialog验收用例
| 用例ID | 场景 | 验收标准 |
| --- | --- | --- |
| A7-DIALOG-001 | 打开代表Dialog | 焦点进入弹窗;dialog由可见标题命名;背景具备inert/aria-hiddenbody滚动锁定;遮罩不可聚焦 |
| A7-DIALOG-002 | 主Dialog键盘循环 | 最后一个可用控件按Tab回到第一个,首控件按Shift+Tab回到最后一个,焦点不进入背景 |
| A7-DIALOG-003 | dirty表单按Escape/取消/关闭/遮罩 | 四种入口均打开具名alertdialog,不销毁已输入草稿,父Dialog不可交互 |
| A7-DIALOG-004 | dirty确认层键盘与返回 | 确认层Tab循环;按Escape或继续编辑后确认层关闭、草稿保留、焦点返回原字段 |
| A7-DIALOG-005 | 明确放弃 | 两层弹窗关闭、草稿销毁、背景隔离和滚动锁恢复、焦点返回原触发按钮 |
| A7-DIALOG-006 | 两端五视口视觉回归 | 运营与客户端真实登录态页面在1440×900、1366×768、768×1024、390×844、375×667无裁切或横向溢出,控制台无业务error/warn |
## 2026-07-22 UI/UX A2/A3收口用例
| 用例ID | 场景 | 验收标准 |
| --- | --- | --- |
| A23-UPLOAD-001 | 客户端企业认证页选择文件 | 请求进入`/api/client/files/upload`FileObject租户来自会话;MinIO对象字节数与上传文件一致并可回读 |
| A23-UPLOAD-002 | 伪造租户、非法用途/目录、跨租户下载 | 伪造租户不生效;非法用途或目录在对象存储写入前拒绝;跨租户文件返回404 |
| A23-UPLOAD-003 | 上传成功五视口反馈 | 1440×900、1366×768、768×1024、390×844、375×667均显示完整文件名;页面无横向溢出,步骤一可见,省市选择不裁切 |
| A23-LOG-001 | 客户端真实筛选导出 | 页面显示完成数量、操作单号和下载入口;重复点击期间按钮锁定,失败时原地重试且不跳门户 |
| A23-LOG-002 | 客户端CSV字段安全 | 表头仅六列;任意OperationLog详情、来源IP、供应商或内部字段均不得进入导出内容 |
| A23-REVIEW-001 | 签名/模板点击通过 | 首先显示对象名、唯一ID、企业、应用、资格检查和影响;没有最终确认不得改变pending状态或写AuditRecord |
| A23-REVIEW-002 | 审核并发与幂等 | 使用pending+updatedAt条件更新;同键重放返回同一操作单且仅一条审计;版本变化返回冲突 |
| A23-REVIEW-003 | 审核确认层五视口 | 签名确认层截图覆盖五视口;模板覆盖桌面截图和390px DOM尺寸测量;内容与按钮可达、无横向溢出、console无业务error/warn |
## 2026-07-22 日发送配额与HTTP参数回归用例
| 用例ID | 场景 | 验收标准 |
| --- | --- | --- |
| TC-SEND-DAILY-001 | 新建应用不传dailyLimit | PostgreSQL保存100000,返回值与页面均显示100000 |
| TC-SEND-DAILY-002 | 当日剩余1条时,客户端或HTTP同时发2个号码 | 整批返回429/DAILY_SEND_LIMIT_EXCEEDED,不新建任务、短信记录、冻结或队列作业 |
| TC-SEND-DAILY-003 | 两个API实例并发争抢最后配额 | 依赖`applicationId+usageDate`唯一索引与条件upsert,只有不突破上限的请求成功 |
| TC-SEND-DAILY-004 | 多号码CMPP Submit整包超限 | 仅一个非0 SubmitResp且`result=8`、Msg_Id为0;每个号码均有`rejected/DAILY_LIMIT`主记录,无冻结、扣费、额度占用、SmsReceiptRecord和下游DELIVER投递 |
| TC-SEND-DAILY-005 | Bind后历史待回执拉取完成,再提交日限额超限包 | Bind阶段允许拉取既有pending;超限Submit不得新增pending回执或建立Msg_Id/Sequence映射,连接保持可用 |
| TC-SEND-DAILY-006 | 待审核/定时任务受理后再拒绝或取消 | 受理日额度已占用且不返还;失败、取消和最终送达统计不得反向修改日用量 |
| TC-SEND-ORDER-001 | 请求同时存在号码格式、模板和余额错误 | 按固定业务顺序先返回号码基础错误;修复号码后返回签名/模板错误,只有业务资格通过后才执行最终余额原子校验/冻结 |
| TC-SEND-ORDER-002 | 号段库无法识别但号码基础格式合法 | 不以未知号段拒绝;记录未知运营商快照并继续匹配全国或三网兼容通道,正常产生提交、消费和回执数据 |
| TC-SIGN-UTF8-001 | SQL_ASCII数据库执行历史签名黑括号规范化后出现截断UTF-8 | 字节检查准确识别非法行;补偿migration仅修复主键与损坏hex同时匹配的记录,恢复为迁移前备份中的`【航天信息信诺网】` |
| TC-SIGN-UTF8-002 | 修复后查询企业签名及关联报备数据 | `SmsSignature`全部49条可按UTF-8读取;企业签名、企业模板、报备任务、报备记录和待报备资料接口不再因PostgreSQL 22021返回500 |
| TC-SIGN-UTF8-003 | 目标签名在补偿migration前已被人工修改 | 原始hex不匹配时不得覆盖;重复执行修复SQL结果不变且不产生非法字节 |
| TC-HTTP-PARAM-002 | 首次开通HTTP后查看并复制参数 | 六项能力默认开启,回执/上行为HTTP Webhook;复制文本含AppID和“客户端自助密钥”,与真实API/DB一致 |
| TC-HTTP-PARAM-003 | 升级前已开通HTTP且Webhook能力开启,投递模式仍为cmpp | migration将对应回执/上行模式回填为http,参数复制不再显示CMPP长连接 |
## 2026-07-23 供应商连接主动心跳与自动重连用例
| 用例ID | 场景 | 验收标准 |
| --- | --- | --- |
| TC-CMPP-UP-RECONNECT-001 | 首次连接时供应商端口不可达,随后恢复 | 首次状态为failed并记录错误/下次重连;无需人工操作即建立连接,currentConnections恢复到期望值 |
| TC-CMPP-UP-RECONNECT-002 | 已连接socket被供应商关闭 | Gateway结束旧读循环、唤醒在途提交、进入reconnecting并按退避重新登录,不发生nil客户端panic |
| TC-CMPP-UP-HEARTBEAT-001 | 空闲连接正常响应ACTIVE_TEST | 平台按通道间隔主动发送请求,按Sequence_Id清除待响应项并更新lastHeartbeatAt,短信和心跳包不交叉写坏 |
| TC-CMPP-UP-HEARTBEAT-002 | 连续心跳无响应 | 达到阈值后关闭旧连接、分类为heartbeat_timeout并自动重连;单次迟到或其他Sequence响应不能误清除全部待响应项 |
| TC-CMPP-UP-RECONNECT-003 | 鉴权失败 | 通道保持failed且5分钟慢速持续重试,不刷屏、不高频触发供应商锁定;修改正确凭据后立即重连 |
| TC-CMPP-UP-RECONNECT-004 | desiredConnections大于1且部分断开 | 只补足缺失连接,未恢复到期望值前显示reconnecting,不超过配置连接数 |
| TC-CMPP-UP-DISCONNECT-001 | 手动停用或删除通道 | API发送DisconnectChannelGateway关闭全部连接并停止心跳/重连;等待多个协调周期后仍为0连接 |
| TC-CMPP-UP-DISCONNECT-002 | disabled/deleted通道存在历史connected状态 | API协调任务自动下发断开并把currentConnections归零,不恢复非active通道 |
| TC-CMPP-UP-CONFIG-001 | 修改地址、端口、凭据、版本、连接数、窗口或心跳配置 | 旧池被关闭,新配置立即生效,无需先手工停用再启用 |
| TC-CMPP-UP-RECONCILE-001 | API/Gateway/Redis依次重启及多API实例并行扫描 | 活动通道最终恢复,Redis租约保证同一协调周期每通道只有一个连接指令,BullMQ任务ID不冲突 |
| TC-CMPP-UP-RECONCILE-002 | 两个API实例同时发现缺少供应商状态行 | PostgreSQL部分唯一索引只允许一条`applicationId IS NULL + channelId + connectionId`记录;P2002一方复用赢家并继续更新 |
## 2026-07-23 通道与报表补充用例
- `TC-CHANNEL-DEFAULT-001`:新建通道不传端口、协议、业务代码时,API 分别落库 `7890`、`CMPP`、`config.serviceId=SMS`;传入 HTTP/SGIP 时仍落为 CMPP。
- `TC-CHANNEL-SERVICE-002`:业务代码超过 10 字节或包含非 ASCII 字符时后端返回 400;合法值进入真实 Gateway Submit 的 `Service_Id`。
- `TC-APP-LIMIT-003`:新建企业应用未指定每任务号码上限时落库 `10000`,超过上限的真实发送任务被后端整任务拒绝。
- `TC-SECURITY-DELETED-004`:企业黑名单、全局黑名单、敏感词列表在默认、全部状态以及显式请求 deleted 时均不返回逻辑删除记录。
- `TC-REPORT-SEGMENT-005`:构造含长短信分片、平台拦截、成功、失败和无终态记录的日报,验证 `提交=全部 billingUnits`、`发送=提交-平台拦截`、`发送=未知+成功+失败`,并验证三类 CSV 导出字段一致。
- `TC-UI-DETAIL-006`:短信详情展示发送号码,分片审计使用无需横向滚动的响应式卡片;短信记录桌面行密度提升且长内容两行截断。
- `TC-UI-NAV-007`:从企业应用、企业管理、通道组等列表进入新增/编辑页后,所属二级菜单保持 `aria-current=page` 和选中样式。
## 2026-07-24 CMPP/HTTP 通讯交互日志用例
- `TC-PROTOCOL-LOG-001`:向Gateway客户认证入口提交不存在的CMPP账号;真实接口返回业务4xx,通讯日志分别出现`received`和`failed`事件,账号可检索、耗时和安全错误可见,数据库无短信业务记录。
- `TC-PROTOCOL-LOG-002`:真实CMPP Submit获得供应商SubmitResp;通讯日志可按CMPP、通道到平台、SubmitResp及平台消息号筛选,展示上游消息号和结果码,不包含短信正文或通道密码;同一个SubmitResp只能落一条最终处理结果,不得同时出现`received`和`success`重复行。
- `TC-PROTOCOL-LOG-003`:供应商发送DELIVER状态报告;Gateway结构化日志出现收到事件,NestJS通讯日志以一条记录展示该报文及最终处理结果。构造解包失败或API拒绝时必须出现对应失败证据,不能静默返回。
- `TC-PROTOCOL-LOG-004`:通过公开HTTP API提交合法和非法请求;通讯日志展示客户到平台的受理或失败状态、请求号、完整手机号、业务码和耗时,可使用完整号码查询,鉴权头、密钥和正文不得入库。
- `TC-PROTOCOL-LOG-013`:分别产生CMPP Submit、供应商回执、上行和HTTP发送通讯日志;数据库新记录的`phoneNumber`、列表对象列、详情弹窗及完整号码关键字查询均显示/命中完整手机号,不写新的`phoneMasked`值,且短信正文、密码、密钥和鉴权头仍不入库。
- `TC-PROTOCOL-LOG-005`:平台向客户投递回执或上行Webhook并触发成功、网络失败和重试;通讯日志展示事件ID、HTTP状态或网络错误、耗时、尝试次数及最终状态,真实`HttpWebhookAttempt`状态一致。
- `TC-PROTOCOL-LOG-006`:连续运行CMPP心跳;`ProtocolInteractionLog`行数不随每个ACTIVE_TEST增长,连接状态中的最近心跳仍更新。超过配置保留期的数据被清理,业务表及操作审计不受影响。
- `TC-PROTOCOL-LOG-007`:运营端真实登录后打开系统日志,键盘切换“系统与操作日志/通讯交互日志”,筛选、分页、详情及固定操作列可用;桌面和平板/手机不产生页面级横向溢出,宽表允许容器内滚动,控制台无error/warn。
- `TC-PROTOCOL-LOG-008`:一条真实短短信取得成功状态报告后,按同一平台消息号查询应恰好看到四个供应商侧真实业务报文:`平台→通道/CMPP_SUBMIT`、`通道→平台/CMPP_SUBMIT_RESP`、`通道→平台/CMPP_DELIVER`、`平台→通道/CMPP_DELIVER_RESP`;每个报文只出现一条,箭头与抓包传输方向一致,长短信则按实际分片分别记录Submit/SubmitResp。
- `TC-PROTOCOL-LOG-009`:企业应用提交短信时,入站Submit显示“企业应用→平台”,每个实际返回的SubmitResp显示“平台→企业应用”;供应商侧统一显示“平台→供应商通道/供应商通道→平台”,不得再使用含义模糊的客户/通道箭头。
- `TC-RECEIPT-SHARED-010`:供应商账号、Gateway主机、端口、协议和CMPP版本均相同的两个物理通道连接中,回执从副连接进入、原连接存在唯一`gatewayMessageId + DestTerminalId`分片候选时,应写入原提交逻辑通道;账号或端点任一不同、或候选超过一条时不得自动匹配。
- `TC-RECEIPT-LONG-011`:两分片长短信仅收到第一片`DELIVRD`时,`SmsMessageRecord`保持`submitted`且不创建企业应用最终回执;第二片到达后两条分片审计均为`delivered`,主记录只聚合一次为`delivered`CMPP按两个原始分片各创建一条`DELIVRD`且分别使用两个SubmitResp Msg_IdHTTP只创建一个最终事件;重复回执不得重复投递、扣费或退款。
- `TC-PROTOCOL-LOG-012`:供应商长短信每个真实分片分别产生一条`平台→供应商通道/CMPP_SUBMIT`和一条`供应商通道→平台/CMPP_SUBMIT_RESP`;内部`submit-result`聚合回调不得额外落协议日志。
- `TC-RECEIPT-LONG-013`:两分片长短信主记录保存首片上游消息号,第二片返回`YL:1014`等任意非成功状态且首片未回执;系统通过第二片审计识别当前提交尝试,整条短信进入失败/补发或退款终态,不再卡在`submitted`;最终不再补发时,对两个请求回执的原始客户分片分别投递失败状态报告,Msg_Id与各自SubmitResp一致。
- `TC-DELIVERY-AUTO-014`:分别配置仅CMPP、仅HTTP、CMPP+HTTP、两者均关闭四种应用状态;回执与上行分别只产生CMPP下游记录、HTTP Webhook事件、两者各一条、均不产生。修改历史手工投递模式不得改变自动计算结果。
- `TC-HTTP-WEBHOOK-015`:运营端关闭HTTP接口后,回执和上行Webhook地址输入框仍显示且可保存;任一地址保存为空时删除对应有效端点,后续不推送该类HTTP事件,另一非空地址不受影响。
- `TC-PROTOCOL-LOG-016`:在线企业应用收到回执或上行 `CMPP_DELIVER` 并返回 `CMPP_DELIVER_RESP`;通讯日志各出现一条“平台→企业应用/DELIVER”和“企业应用→平台/DELIVER_RESP”,结果、消息号、序列号和投递记录一致,下游投递记录仍独立展示发送、ACK和重试状态。
- `TC-PROTOCOL-LOG-017`:独立协议日志Worker一次读取数量大于单次数据库写批次,且首批写库尚未完成时再次请求flush;Worker必须等待同一flush完整写完全部批次后才返回成功并ACK/XDEL对应Stream事件,处理中不得因30秒自动认领重复落库,写库失败时保留pending供重试且不得提前ACK。
## 2026-07-26 企业应用停用与回执清算专项
- `APP-DISABLE-001`:应用无待清算数据时点击停用,直接进入已停用并断开该账号全部CMPP连接。
- `APP-DISABLE-002`:存在等待供应商回执、待推送、待ACK或可重试失败记录时,停用弹窗展示真实分类数量,并提供等待与强制停用两个操作。
- `APP-DISABLE-003`:选择等待后进入`disabling`;新Submit同步返回非成功响应且不创建短信记录,历史回执仍可通过原连接或重新连接推送。
- `APP-DISABLE-004`:停用中状态悬停、聚焦时展示原因、分类数量、进入时间和72小时自动停用时间。
- `APP-DISABLE-005`:停用中点击启用恢复`active`,清除`disablingAt/autoDisableAt`,旧扫描任务不得再次将其停用。
- `APP-DISABLE-006`:选择强制停用后,未完成投递及尝试标记`abandoned`、停止重试,并断开同账号的所有CMPP连接。
- `APP-DISABLE-007`:从进入停用中满72小时仍有待清算数据时,系统自动执行强制停用;API/Gateway重启不影响截止时间。
- `APP-DISABLE-008`:停用后新到供应商回执仍更新短信终态和保存原始回执,但下游投递直接记为`abandoned`。
- `APP-DISABLE-009`:企业存在`active/disabling`应用时删除失败;全部应用为`disabled/deleted`后允许删除。
- `APP-DISABLE-010`:企业或应用已停用后,Gateway仍可读取此前已形成的pending回执,不再返回账户无效导致投递死锁。
## 2026-07-26 风控与短信人工审核专项
- `RISK-RULE-001`:规则页只展示单任务最大号码数、非工作时间营销批量和10分钟客户端任务频控;重复、非法号码比例、黑名单比例和模板变量规则不展示且不参与计算。
- `RISK-RULE-002`:同编码同时存在全局和企业应用级规则时,目标应用使用应用级阈值,其他应用继承全局;停用应用级规则后回落到全局。
- `RISK-RULE-003`:修改阈值、动作、状态、优先级和非工作开始/结束时间后重新查询与数据库一致;非法编码、负阈值、同范围重复规则和相同起止时间被后端拒绝。
- `RISK-FREQ-004`:同一应用10分钟内已有N个客户端批次时,第N+1个客户端任务命中;同期CMPP、HTTP、运营通道测试及风险预检数量不影响结果,另一应用任务也不影响。
- `PHONE-VALID-005``10000000000`视为合法基础格式并继续号段/路由处理;非1开头、非11位或包含非数字字符的号码被确定性拦截。
- `PHONE-BLOCK-006`:客户端/HTTP混合提交合法、非法、平台黑名单和企业应用黑名单号码;合法号码入队,三类拦截号码均为`submit_failed/rejected`、金额0且没有上游提交。
- `PHONE-BLOCK-007`:CMPP多目的提交混合合法、非法和黑名单号码;Submit被平台受理后,非法/黑名单号码各生成一条`REJECTD`失败回执并投递客户,合法号码继续发送。
- `TEMPLATE-VAR-008`:已人工审核模板在本次发送缺少必填变量或多传未定义变量时直接拒绝并列出变量名,不生成待人工审核任务;变量完整时正常继续。
- `SMS-REVIEW-009`:待审核列表只含`pending_review`;人工通过/驳回列表只含`reviewedById`非空记录,自动放行和自动拒绝均不出现。
- `SMS-REVIEW-010`:点击号码数量后,通过真实后端分页查看手机号码、归属地、运营商和短信状态;号码搜索与10/20/50条分页正确,接口同时兼容`reviewTaskId`和批次`riskTaskId`关联。
- `SMS-REVIEW-011`:客户端和CMPP待审核任务创建时短信记录保存`reviewTaskId`;人工通过后短信由`pending_review`转为`queued`并入队,人工驳回后转拒绝且执行既有资金释放,不能只更新审核任务。
- `SMS-REVIEW-012`:升级前历史`pending_review`异常记录保持原样,不执行数据修复或短信补发;升级后新任务不再产生审核任务与短信状态不一致。
## 2026-07-26 发送批次号与任务号命名用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-ID-NAME-001 | 查看运营端短信任务进度 | 列表、查询条件和详情均使用“发送批次号”,显示真实`SmsBatchTask.taskNo` |
| TC-ID-NAME-002 | 查看客户端批量任务、首页和发送成功提示 | 统一使用“发送批次号”,不再出现“任务编号”或“批次编号” |
| TC-ID-NAME-003 | 查看短信审核列表、详情和号码明细 | 显示真实`SmsSendTask.taskNo`并统一命名为“审核任务号”,可按该编号筛选 |
| TC-ID-NAME-004 | 查看报备任务及报备记录 | 列表、筛选和详情统一使用“报备任务号” |
| TC-ID-NAME-005 | 验证接口和数据库兼容性 | 仅修改展示文案,不改变现有ID、`taskNo`、关联关系或协议`Msg_Id` |
## 2026-07-26 企业删除拦截提示用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-TENANT-DELETE-001 | 删除仍有启用或停用中应用的企业 | 后端拒绝删除,确认弹窗保持打开,并在弹窗内显示应用数量及先停用应用的原因 |
| TC-TENANT-DELETE-001A | 分别删除账户余额为正数、负数和0的企业,并在删除检查期间并发发起充值 | 正数和负数均被后端拒绝,弹窗提示“完成余额清算后方可删除,请给企业充值到金额为0”;余额为0且无活动应用时才允许删除;账户事务锁保证删除检查与余额变更不发生竞态 |
| TC-TENANT-DELETE-002 | 删除请求处理中重复点击或关闭弹窗 | 确认、取消和关闭均被禁用,不产生重复请求 |
| TC-TENANT-DELETE-003 | 删除无阻塞依赖的企业 | 删除成功后才关闭弹窗,并刷新企业列表 |
## 2026-07-26 运营页面细节与通道重连用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-OPS-UI-001 | 查看企业签名及引流信息报备状态 | 运营商以中文显示,目标通道显示真实名称,不出现内部通道编号替代名称 |
| TC-OPS-UI-002 | 查看较长的短信上行内容 | 内容列宽不被其他列挤窄,可展示最多三行,完整内容可在详情查看 |
| TC-CHANNEL-RECONNECT-003 | 仅修改启用中通道的名称、单价、运营商或TPS | 保存成功且不创建连接中状态、不发送Gateway连接控制请求 |
| TC-CHANNEL-RECONNECT-004 | 前端提交包含未变化连接参数的完整通道表单 | 按修改前后实际值判断,不发送无效重连请求 |
| TC-CHANNEL-RECONNECT-005 | 修改网关地址、账号、连接数、窗口或心跳参数 | 保存后发送连接控制请求;停用/启用仍正确断开/连接 |
| TC-SMS-RECORD-006 | 首次进入短信记录或点击重置 | 日期默认覆盖北京时间昨天和今天,并以该范围请求真实后端 |
| TC-DOWNSTREAM-UI-007 | 查看包含多次投递的下游投递详情 | 每次投递按纵向时间线展示中文状态、时间、连接和ACK证据,窄屏无需横向滚动 |
| TC-GATEWAY-UI-008 | 查看“网关异常”的“提交异常”Tab | 标题、说明、总数、表格和分页层次清晰,不紧贴容器边框 |
| TC-REPORT-SCOPE-009 | 检查本轮报表变更范围 | T-4未知转失败未实现,日报未知口径和历史数据保持不变 |
## 2026-07-26 通道补发归因与发送详情用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-RETRY-ROUTE-001 | 直接签名短信在首通道失败,签名在同组备用通道已报备通过 | 使用短信记录`signatureId`选中备用通道;无需模板;日志记录开始、选择结果和尝试通道 |
| TC-RETRY-ROUTE-002 | 模板短信在首通道失败,备用通道不可用或未报备 | 不创建伪补发;结构化日志记录失败原因、通道组和已尝试通道,不静默吞错 |
| TC-SUBMIT-ATTR-003 | 同一短信先后经两个通道提交,旧尝试的聚合结果迟到 | Gateway携带原始`submitId`API只更新对应`SmsSubmitRecord`,不覆盖当前尝试主记录 |
| TC-SUBMIT-ATTR-004 | 滚动升级期间收到不含`submitId`的聚合或分片结果 | 唯一候选时兼容并告警;零个或多个候选时返回失败、写歧义日志且不批量更新 |
| TC-SUBMIT-ATTR-005 | 两分片长短信在通道A失败后由通道B补发 | 每个分片结果归属正确`submitId`和通道;任一迟到结果不污染另一尝试 |
| TC-SMS-DETAIL-006 | 查看先经富泷失败、再经铁布衫失败的历史短信详情 | “通道发送与回执”显示两次真实通道及各自分片回执,不把两行都显示为最终通道 |
| TC-CHANNEL-GROUP-007 | 调整通道组成员顺序、优先级、权重或主备 | 操作日志保存修改前后有序成员、通道编号和名称,可还原短信发送时配置 |
## 2026-07-26 长短信并发失败幂等用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-RETRY-RACE-001 | 三分片长短信的三个失败回执并发进入API,备用通道可用 | 三个回执和通讯报文全部保存;来源提交记录只关联一个补发记录,只发布一个Gateway命令、三个补发分片 |
| TC-RETRY-RACE-002 | 三个线程在唯一补发记录提交前后交错执行 | 只有一个线程取得`retryOfSubmitRecordId`唯一关系;其他线程返回同一下一跳`submitId`并写复用日志,不退款、不生成最终回执 |
| TC-RETRY-RACE-003 | 三个失败回执并发处理且没有可用备用通道 | 主记录最终失败;只产生一笔退款交易和一次余额增量;HTTP只生成一个最终失败事件,CMPP对三个原始客户分片各生成一条失败回执且每片只生成一次 |
| TC-BILLING-IDEM-004 | 三个线程使用同一短信退款幂等键并发退款 | 三次调用返回同一交易ID,`AccountTransaction`只有一条,账户余额只增加一次 |
| TC-BILLING-ATOMIC-005 | 同一企业同时发生扣费、退款和充值 | 账户级事务锁串行化余额变更,使用数据库原子增量;每条流水`balanceAfter`连续且最终余额与流水一致 |
| TC-DOWNSTREAM-IDEM-006 | 同一长短信终态被重复处理,企业同时启用CMPP和HTTP | CMPP每个请求回执的原始客户分片各有一条稳定`CmppDownstreamDelivery`且各只发送一次;HTTP只有一个稳定事件和一条端点投递 |
| TC-MIGRATION-IDEM-007 | 在含历史重复最终回执的预生产数据上执行migration | 历史行全部保留;每个短信只给最早一条历史回执设置唯一键,其余保持空键;新数据开始强制唯一 |
## 2026-07-27 通道报备发送统计用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-CHANNEL-REPORT-STATS-001 | 当前通道同一签名今日存在已接受成功、已接受未知、已接受失败、提交拒绝和提交超时记录 | 签名任务的“今日发送”展示四类真实数量与比例;提交拒绝/超时只计入提交失败,成功/未知/回执失败比例只以已接受数量为分母 |
| TC-CHANNEL-REPORT-STATS-002 | 同一签名有直接短信和多个引流信息,展开具体引流任务 | 签名任务汇总当前通道下该签名全部发送;具体引流任务仅统计自身,不串入同签名其他引流或直接短信 |
| TC-CHANNEL-REPORT-STATS-003 | 当前统计范围有历史成功短信但今日无成功短信 | “上次发送成功时间”显示该范围最近一次最终成功时间,不以报备时间、最后更新时间或页面当前时间代替 |
| TC-CHANNEL-REPORT-STATS-004 | 报备任务先提交、后由报备记录变为通过 | 列表和详情分别显示真实提交报备时间、最近一次报备成功时间、上次发送成功时间和今日统计;刷新后数据保持一致 |
## 2026-07-27 签名审核与运营端细节回归用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-SIGNATURE-PREFLIGHT-001 | 应用通道只配置引流必填字段,客户端提交不含固定企业资质字段的签名 | 运营审核资格检查不出现公司名称、信用代码、法人、责任人或资质文件缺失,允许通过/驳回 |
| TC-SIGNATURE-PREFLIGHT-002 | 提交快照包含签名必填文本和文件字段,分别缺失后预检 | 只按快照字段名称提示缺失;补齐`signatureReportValues`后允许通过;引流字段不参与 |
| TC-ADMIN-NAV-003 | 展开审核中心并进入风控规则 | 风控规则位于最后一项,面包屑为“审核中心 / 风控规则” |
| TC-SMS-DETAIL-004 | 查看经历首次提交和补发的短信详情,再修改应用路由 | 每次提交显示持久化通道组名称;路由修改后历史归因不变化;旧数据迁移可确认部分已回填 |
| TC-SMS-DETAIL-005 | 测试短信刚进入队列但尚无供应商回执 | 与普通待回执短信一致,不显示红色“运营端通道测试短信”失败框 |
| TC-SEGMENT-AUDIT-006 | 构造多个不同时间和同时间分片审计 | 页面自上而下按审计时间升序,同时间按分片序号和主键稳定排序,并展示审计时间 |
| TC-DASHBOARD-SIGNATURE-007 | 当日同一签名包含accepted、rejected、timeout及回执失败 | 表格独立展示提交失败;送达失败仅包含已受理后的失败,成功率分母为已受理数 |
| TC-DASHBOARD-SPEND-008 | 两企业当日分别产生计费、退款和手工充值 | 排行只汇总当前仍为charged的当日计费;充值不计消费,退款记录不计当前消费,排序与数据库一致 |
| TC-CHANNEL-TEST-AUTOFILL-009 | 浏览器保存过网关密码,打开通道编辑和测试短信弹窗 | 密码只进入网关密码字段,不自动填入测试接入号;接入号可手工正常输入 |
| TC-APP-ROUTE-WIDTH-010 | 企业应用通道组名称很长,分别使用桌面和窄屏 | 选择框及下拉选项不超出通道组卡片,长文本省略且可正常选择 |
| TC-USER-ADMIN-011 | 删除/停用企业最后一个管理员,再删除/停用平台最后一个管理员 | 企业管理员操作成功并写日志;平台管理员操作仍返回`LAST_PLATFORM_ADMIN` |
| TC-INPUT-ALIGN-012 | 打开新增用户弹窗,对比有提示和无提示的文本输入框 | 标签和输入控制区顶部对齐,提示文本仅占自身下方空间 |
## 2026-07-28 运营端列表与审核详情回归用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-REPORT-FIELD-ACTIVE-001 | 同一报备字段被一个有效通道重复配置,并被一个已删除通道引用 | 引用数按有效通道去重后为1;删除通道不计数 |
| TC-REPORT-FIELD-ACTIVE-002 | 报备字段只剩已删除通道的历史映射 | 引用数为0,字段可删除,同时清理失效映射,不影响历史通道审计数据 |
| TC-CHANNEL-REPORT-SIGNATURE-003 | 通道同时存在有效签名和已删除签名的报备任务 | 报备详情只展示有效签名,已删除签名不再进入当前列表 |
| TC-DASHBOARD-SPEND-009 | 已删除企业和有效企业当日均有charged计费记录 | 今日企业消费只显示有效企业,金额与真实计费聚合一致 |
| TC-SMS-AUDIT-LIST-010 | 打开短信审核列表及任意详情 | 列表展示企业和企业应用,不展示审核任务号、审核原因;详情仍可查看任务号、原因和号码 |
| TC-SMS-TASK-PHONES-011 | 在短信任务进度点击号码数量,搜索号码并切换页码、每页条数 | 打开真实号码列表;手机号、归属地、运营商、状态来自服务端,搜索和分页总数准确 |
| TC-DRAINAGE-FIELD-012 | 运营端新增和编辑企业签名引流资料 | 弹窗仅显示“引流url或号码”,不显示“引流信息”;保存、刷新和搜索均使用真实后端值 |
| TC-AUDIT-DETAIL-013 | 依次打开企业认证、短信、模板、签名、引流信息审核 | 查看按钮统一为“详情”;所有详情展示审核时间和审核人员用户名,自动审核与历史缺失值展示准确 |
| TC-CUSTOMER-NOTE-014 | 打开运营端企业管理 | “企业列表”下不出现“数据来自租户、账户真实接口。”研发说明 |
## 数据统计:签名通道与运营商发送质量
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-ANALYTICS-SIGNATURE-001 | 不传日期进入数据统计页 | 默认使用北京时间当天,签名列表与页面顶部统计日期一致 |
| TC-ANALYTICS-SIGNATURE-002 | 选择历史自然日后查询 | 总览、签名列表和矩阵全部切换至所选日期 |
| TC-ANALYTICS-SIGNATURE-003 | 短信正文有签名但`signatureId`为空 | 该记录不进入已登记签名统计 |
| TC-ANALYTICS-SIGNATURE-004 | 同一签名分别通过移动、联通、电信发送 | 明细按实际运营商分别形成矩阵列 |
| TC-ANALYTICS-SIGNATURE-005 | 同一通道实际发送多个运营商号码 | 同一通道行的多个运营商单元格分别展示真实数据 |
| TC-ANALYTICS-SIGNATURE-006 | 同一短信首通道失败并切换下一通道 | 业务短信只计1条,两个通道各计1次提交,通道提交总数为2 |
| TC-ANALYTICS-SIGNATURE-007 | 供应商提交拒绝或超时 | 计入提交失败,不混入已受理短信的送达失败率分母 |
| TC-ANALYTICS-SIGNATURE-008 | 已受理短信收到失败回执 | 计入该通道与运营商组合的送达失败 |
| TC-ANALYTICS-SIGNATURE-009 | 长短信全部分片成功 | 以最后成功分片时间计算该提交的到达耗时 |
| TC-ANALYTICS-SIGNATURE-010 | 关键字查询签名、企业或应用 | 后端返回匹配签名并保持总数和分页正确 |
| TC-ANALYTICS-SIGNATURE-011 | 点击“查看明细” | 打开右侧详情抽屉,展示运营商概览及通道×运营商矩阵;Esc、关闭按钮和遮罩均可关闭 |
| TC-ANALYTICS-SIGNATURE-012 | 所选日期没有已登记签名发送 | 返回真实空状态,不显示演示或历史日期数据 |
| TC-ANALYTICS-SIGNATURE-013 | 同一运营商的一条业务短信首通道失败后切换通道并最终送达 | 运营商概览计1条业务短信、最终成功率为100%;通道矩阵仍分别记录两次真实提交 |
# 列表后端分页与响应性能测试(2026-07-28)
## TC-LIST-PERF-001 短信记录真实后端分页
1. 进入运营端短信记录,选择日期并查询。
2. 验证请求携带 `page/pageSize`,响应为 `items/total/page/pageSize``items` 不超过页容量。
3. 翻到下一页,验证数据库返回目标页且页面未在浏览器缓存全量记录。
4. 验证关联提交、回执、下游投递仅属于当前页短信;CSV 下载调用独立导出接口。
## TC-LIST-PERF-002 其他运营端列表分页
逐页验证短信任务、报备任务、报备记录、企业应用、企业签名、企业模板、短信通道、上行短信和充值记录。筛选在后端生效,总数与条件一致,翻页只请求当前页;通道组不在本轮范围。
## TC-LIST-PERF-003 客户端列表分页
逐页验证短信明细、批量任务、应用、签名与引流、模板、上行短信和充值记录。验证租户边界不变、筛选回到第一页、选项接口仅返回下拉必需字段。
## TC-LIST-PERF-004 数据库索引与压缩
1. 应用分页索引 migration。
2. 对短信、任务、报备、应用、签名、模板、通道、上行和充值分页 SQL 执行计划进行检查。
3. 携带 `Accept-Encoding: gzip` 请求大于 1KB 的 JSON,验证响应 `Content-Encoding: gzip`。
## 2026-07-29 企业应用列表 Prisma 字段回归用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-APP-LIST-001 | 运营端打开企业应用列表并请求分页接口 | Prisma 查询仅排除真实存在的 `secretHash`;接口 HTTP 200,不因 DTO 字段 `passwordCipher` 触发 Prisma 校验错误 |
| TC-APP-LIST-002 | 运营端打开企业应用黑名单并加载企业应用筛选项 | 黑名单及筛选项均从真实后端返回;企业应用加载不触发 HTTP 500,列表响应不包含 `secretHash` |
| TC-APP-LIST-003 | 校验企业应用列表 Prisma `omit` 字段 | 所有 `omit` 键都存在于当前生成客户端的 `SmsApplication` DMMF 模型,模型字段变更或错误别名会使回归测试失败 |
## 2026-07-29 短信号码路由识别性能回归用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-PHONE-ROUTE-001 | 并发使用多个号码识别运营商 | 只查询一次全部启用规则;正则只编译一次,并按优先级返回移动、联通或电信业务路由 |
| TC-PHONE-ROUTE-002 | 运营商规则新增或删除后再次识别 | 写入成功后当前进程缓存立即失效,下一次识别读取真实新规则;正在完成的旧查询不得覆盖新缓存 |
| TC-PHONE-ROUTE-003 | 号码同时命中 7 位、5 位和 3 位号段 | 单次 `prefix IN (...)` 查询全部候选,选择最长的 7 位号段省份 |
| TC-PHONE-ROUTE-004 | 号码不命中任何号段 | 只执行一次号段查询并返回省份未知,不产生 7 位至 3 位的 5 次往返 |
| TC-PHONE-ROUTE-005 | 已完成首次识别的短信进入失败补发 | 复用短信记录持久化的运营商和省份,不再查询规则和号段;既有通道组、报备及全国/省份路由规则不变 |
## 2026-07-29 运营看板与运营商筛选用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-DASHBOARD-HOURLY-001 | 北京时间当天仅部分小时存在短信记录 | 今日发送趋势固定展示 24 个小时;有数据小时显示真实提交总条数和最终成功条数,其余小时补 0 |
| TC-DASHBOARD-HOURLY-002 | 同一小时包含成功、失败、未知短信 | 提交总条数包含全部业务短信,成功条数只包含最终状态 `delivered` 的短信,两条折线均来自后端 PostgreSQL 聚合 |
| TC-DASHBOARD-AUDIT-SPEED-003 | 当天五类审核存在不同数量和处理时长 | “审核处理速度”按企业认证、短信审核、模板、签名、引流信息展示已处理数量及审核完成时间减提交时间的平均分钟数 |
| TC-DASHBOARD-AUDIT-SPEED-004 | 某类当天无审核或历史记录缺少可配对提交时间 | 该类数量显示 0;无有效样本时平均时长为空,不使用 0 时长伪造结果,负时长不参与统计 |
| TC-ANALYTICS-CARRIER-ORDER-014 | 后端以电信、移动、联通顺序返回运营商概览 | 弹窗始终按移动、联通、电信展示,未识别项如有数据排在三大运营商之后 |
| TC-SMS-RECORD-CARRIER-007 | 分别选择移动、联通、电信并查询和翻页 | 请求携带真实 `carrier` 条件;当前页、总数和 CSV 导出均只包含所选运营商及兼容历史值 |
| TC-SMS-RECORD-CARRIER-008 | 选择未识别 | 返回运营商为空或非三大运营商标准/兼容值的真实短信记录,不把移动、联通、电信混入结果 |
| TC-SMS-RECORD-CARRIER-009 | 点击重置 | 运营商恢复“全部”,日期等既有默认条件保持原规则,并从第一页重新请求后端 |
## 2026-07-29 短信审核列表布局回归用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-SMS-AUDIT-LAYOUT-001 | 桌面端打开短信审核列表 | 每行分别以一个格子展示发送企业/企业应用、提交时间/审核来源、号码数量/状态,六列结构对齐且信息完整 |
| TC-SMS-AUDIT-LAYOUT-002 | 查看包含较长短信正文的审核任务 | 短信内容列宽不小于 440px,正文获得明显更大的展示空间,不被其他元信息列无意义挤压 |
| TC-SMS-AUDIT-LAYOUT-003 | 点击合并格中的“查看列表”并操作待审核任务 | 真实号码分页弹窗正常打开;详情、勾选、批量通过和驳回入口不受布局调整影响 |
| TC-SMS-AUDIT-LAYOUT-004 | 在窄窗口打开短信审核列表 | 表格保持信息格内部上下层级,宽度不足时允许容器横向滚动,不发生文字重叠或操作按钮遮挡 |
## 2026-07-30 号码发送频次风控用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-PHONE-FREQ-001 | 同一应用、同一号码在同一北京时间自然日依次提交 11 条业务短信 | 前 10 条通过号码频控,第 11 条直接拒绝;触发记录保存阈值 10、触发值 11 和当日周期起止 |
| TC-PHONE-FREQ-002 | 同一应用、同一号码在固定 5 分钟周期依次提交 6 条,第 6 条同时未达到日阈值 | 前 5 条通过,第 6 条仅命中 5 分钟规则并直接拒绝;同周期继续提交仍拒绝且不重复生成活跃触发记录 |
| TC-PHONE-FREQ-003 | 在北京时间 12:04:59 提交至阈值,12:05:00 再提交;另在 23:59:59 达到日阈值后次日 00:00:00 提交 | 5 分钟计数在 12:05:00 进入新周期;日计数在次日 00:00:00 进入新周期,均不是从上次提交时刻滚动计算 |
| TC-PHONE-FREQ-004 | 同一号码分别在应用 A、应用 B 提交,或同一企业的两个应用提交 | 两个应用分别计数,一方命中不会拦截另一方 |
| TC-PHONE-FREQ-005 | 为应用 A 分别配置日阈值 3、5 分钟阈值 2,并保持应用 B 无覆盖 | 应用 A 各自使用个性化阈值;应用 B 继续使用全局 10 条/日和 5 条/5 分钟兜底 |
| TC-PHONE-FREQ-006 | 批量任务含一个已命中号码和一个未命中号码 | 只将命中号码保存为`submit_failed/PHONE_FREQUENCY_LIMIT`且金额为 0;未命中号码正常入队,计费、冻结和日配额只按可发送号码计算 |
| TC-PHONE-FREQ-007 | 发送长短信并发生多个上游分片及失败补发 | 初次业务号码提交只计 1 条;分片、重投和补发不增加号码频次计数 |
| TC-PHONE-FREQ-008 | 提交非法号码、黑名单号码,或任务先被内容/任务级风控整体拒绝 | 这些号码不占用号码频次;数据库状态计数不增加 |
| TC-PHONE-FREQ-009 | 多个并发请求以同一应用、同一号码冲击阈值 | PostgreSQL 原子计数不丢失、不重复放行;超过阈值的请求直接拒绝,并且同周期只有一条活跃触发记录 |
| TC-PHONE-FREQ-010 | 运营在触发记录填写原因后执行解除并清零 | 当前规则的活跃关联解除、计数清零并增加代次;历史命中保留操作人、时间和原因,另一条频控规则不受影响 |
| TC-PHONE-FREQ-011 | 人工解除后在原周期再次连续提交至超阈值 | 按清零后的计数重新计算,再次超阈值时生成同周期新一代触发记录,不与历史唯一键冲突 |
| TC-PHONE-FREQ-012 | 在触发记录页按应用范围、部分号码和拦截中/已到期/已解除筛选并翻页 | 条件、总数和目标页均由真实后端及 PostgreSQL 返回;刷新页面结果保持,不依赖 Mock 或 localStorage |
| TC-PHONE-FREQ-013 | 新增或编辑号码频控规则,尝试阈值 0、小数或动作“人工审核” | 后端拒绝非法配置;有效规则的动作始终为直接拒绝,周期固定为北京时间自然日或固定 5 分钟 |
## 2026-07-30 平台级号码频控白名单用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-PHONE-WL-001 | 将一个已产生频控计数和活跃命中的号码新增为启用白名单 | 该号码在所有企业应用及两类频控规则下的计数清零,活跃命中标记为已解除,历史命中保留 |
| TC-PHONE-WL-002 | 启用白名单号码分别通过两个企业应用连续提交超过24小时和5分钟阈值 | 两个应用均不产生频控计数或命中,提交仍继续经过号码格式、黑名单、内容、余额及其他风控 |
| TC-PHONE-WL-003 | 停用或删除白名单后再次提交 | 停用/删除事务清零全部应用的旧状态;事务完成后的第一条业务短信从1开始计数 |
| TC-PHONE-WL-004 | 将白名单号码A修改为号码B | A、B在所有应用及两类规则下的状态均清零;B按白名单豁免,A恢复受频控约束 |
| TC-PHONE-WL-005 | 新增重复号码、非法号码或空用途说明 | 后端拒绝请求且不写入白名单、频控状态或审计成功记录 |
| TC-PHONE-WL-006 | 查询启用、停用和已删除白名单并翻页 | 后端数据库筛选和分页总数准确;默认列表排除已删除历史,指定已删除状态可查询 |
| TC-PHONE-WL-007 | 删除白名单但未填写删除原因 | 后端拒绝删除;原白名单状态和频控状态保持不变 |
| TC-PHONE-WL-008 | 一批大量号码中仅部分号码在白名单 | 后端分块批量查询白名单,无逐号码N+1查询;仅非白名单号码进入原子频控计数 |
## 2026-07-30 客户端工作台与短信发送体验用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-CLIENT-HOME-001 | 当前企业存在已通过认证、3个有效签名 | 账户状态显示“已认证”,企业主体显示真实企业名称,签名数量显示3,不展示账户启停状态或“当前租户” |
| TC-CLIENT-HOME-002 | 当前企业不存在任何已通过认证 | 账户状态显示“未认证”,其他账户和企业数据仍正常展示 |
| TC-CLIENT-HOME-003 | 分别准备待审核模板、签名和客户端待审核批量任务 | 三个卡片分别显示各自真实数量;点击后进入模板、签名和批量任务菜单 |
| TC-CLIENT-HOME-004 | 当天多个北京时间小时存在短信记录 | 客户端趋势固定展示00:00~23:00提交量和成功量;UTC 01:00记录归入北京时间09:00 |
| TC-CLIENT-SIGNATURE-005 | 筛选条件为空时后台更新签名报备状态,再点击重置 | 页面回到第一页并重新请求后端,展示更新后的报备、审核和引流信息 |
| TC-ADMIN-AUDIT-006 | 首次打开或重置企业认证审核、模板审核页 | 默认筛选“待审核”,后端请求只返回对应待审核记录 |
| TC-CLIENT-SEND-007 | 选择模板后将正文分别编辑为70、71、134和135个Unicode字符 | 单号码预计计费条数依次为1、2、2、3;总预计条数随有效号码数同步变化 |
| TC-CLIENT-SEND-008 | 查看短信发送单价 | 单位显示“元/条”,不显示“元/人” |
| TC-CLIENT-SEND-009 | 后端返回企业账户余额不足或其他提交失败 | 页面中央错误弹窗展示真实错误信息,不只在页面顶部显示 |
| TC-CLIENT-SEND-010 | 打开定时发送日期控件 | 存在“今天”按钮,北京时间当天有浅色背景;选择今天后提交值显式携带`+08:00` |
| TC-CLIENT-SEND-011 | 成功提交真实任务 | 成功弹窗展示后端任务编号和号码数;继续发送可清空全部表单,查看任务进度可定位批量任务 |
## 2026-07-30 R0 渐进式拆分安全护栏用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-REFACTOR-R0-001 | 执行 `node tools/quality/verify-refactor-r0.mjs` | 8 个稳定门面、4 组跨进程契约和 8 项关键特征测试均存在;任一项丢失时非零退出 |
| TC-REFACTOR-R0-002 | 执行 Gateway 队列契约校验 | SubmitCommand、SubmitResult、ReceiptEvent、UplinkEvent 四类真实消息样例全部通过 |
| TC-REFACTOR-R0-003 | 运行 SendChain 与 Billing 特征测试 | 并发抢占、重试、最终回执、下游重排、冻结/扣费/释放/退款和幂等重放行为保持 |
| TC-REFACTOR-R0-004 | 运行 Gateway 全量测试与 `go vet` | CMPP 2.0/3.0、SubmitResp、Deliver ACK、超时、自动重连和 tracker 行为保持 |
| TC-REFACTOR-R0-005 | 检查 R0 代码差异 | 不移动或修改任何生产代码;仅新增路线图、责任索引、门禁清单、契约清单和验证脚本 |
| TC-REFACTOR-R0-006 | 后续拆分开始前执行发布门禁 | 能明确目标域、唯一结构修改会话、稳定门面、事务、表、队列、副作用、停止条件和回滚依据 |
## 2026-07-31 R1 前端 API 兼容门面拆分用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-REFACTOR-R1-001 | 执行 `node tools/quality/verify-admin-api-r1.mjs` | 183个运营端方法、60个客户端方法、7个会话方法和9个HTTP核心函数全部存在,拆分前后实现哈希一致 |
| TC-REFACTOR-R1-002 | 对全部前端源码执行 TypeScript 检查 | 现有页面继续从`@/api/adminApi`导入,类型和方法不丢失,无需批量修改页面 |
| TC-REFACTOR-R1-003 | 执行 Vite 生产构建 | 新领域模块全部进入生产依赖图,构建成功且没有循环依赖或重复导出错误 |
| TC-REFACTOR-R1-004 | 打开本地运营登录页并刷新验证码 | 页面非空、标题和表单正常;验证码真实API返回新算式;控制台无相关warning/error |
| TC-REFACTOR-R1-005 | 模拟或触发401、SESSION_LOCKED和RECENT_AUTHENTICATION_REQUIRED | 继续使用同一HTTP核心处理退出跳转、会话锁定和最近认证重试,不允许各业务域自行实现 |
| TC-REFACTOR-R1-006 | 检查文件上传、Blob导出和查询参数 | 文件大小校验、multipart、租户头、Blob响应及`all`/空值过滤规则与拆分前一致 |
| TC-REFACTOR-R1-007 | 运行R0门禁、API全量测试和Gateway全量测试 | R1没有改变后端、数据库、Redis Stream或CMPP协议行为 |
## 2026-07-31 R2 运营查询服务拆分用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-REFACTOR-R2-001 | 执行`node tools/quality/verify-operations-r2.mjs` | 29个公开方法、3个私有方法、9个查询契约和36个辅助函数全部存在,拆分前后签名及实现哈希一致 |
| TC-REFACTOR-R2-002 | 控制器继续注入并调用`OperationsService` | 路由、参数、返回结构不变,控制器不直接依赖七个内部查询类 |
| TC-REFACTOR-R2-003 | 查询短信记录第一页5条 | PostgreSQL真实总数与分页items独立返回,客户端安全视图继续剔除通道成本、提交和内部路由信息 |
| TC-REFACTOR-R2-004 | 查询北京时间小时发送趋势 | UTC存储值先按UTC解释再转换为`Asia/Shanghai`,不受数据库会话时区影响 |
| TC-REFACTOR-R2-005 | 查询签名通道发送质量 | 分页、运营商固定顺序、业务短信条数和最终成功率口径保持 |
| TC-REFACTOR-R2-006 | 查询系统日志并导出CSV | 关键字、级别、模块、时间范围、CSV转义、时间格式和客户端企业隔离保持 |
| TC-REFACTOR-R2-007 | 查询下游投递、恢复状态和详情 | 告警窗口、分页、应用汇总、失败分类和导出字段保持,不触发重投 |
| TC-REFACTOR-R2-008 | 执行Operations定向及API全量测试 | 页面查询、真实数据库、客户端安全映射和下游恢复既有行为全部通过 |
## 2026-07-31 R3 短信配置兼容门面拆分用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-REFACTOR-R3-001 | 执行`node tools/quality/verify-sms-config-r3.mjs` | 51个公开方法、21个内部方法、19个DTO/查询契约和27个辅助声明全部存在,领域归属正确,迁移前后实现一致 |
| TC-REFACTOR-R3-002 | 检查运营端、客户端和Gateway控制器导入 | 控制器继续只注入`SmsConfigService`DTO从独立`contracts`导入,不再从实现类文件导入 |
| TC-REFACTOR-R3-003 | 按当前企业查询应用、签名、引流信息和模板 | 继续读取真实PostgreSQL;客户端租户边界、分页和历史数据可见性与拆分前一致 |
| TC-REFACTOR-R3-004 | 创建或编辑应用并验证CMPP账号、接入号和路由配置 | CMPP账号与接入号唯一性、密码规范、路由规则事务和操作日志保持原行为 |
| TC-REFACTOR-R3-005 | 执行应用停用、72小时扫描、连接超时和下游断连测试 | 停用状态机、未决投递处理、Gateway断连调用、自动扫描和审计保持原行为 |
| TC-REFACTOR-R3-006 | 新建、编辑、提交及审核签名、引流信息和模板 | 报备字段快照、审核状态、审核人、驳回原因、操作日志及删除治理接口保持 |
| TC-REFACTOR-R3-007 | 执行短信配置与审核治理定向测试 | 既有68项测试全部通过,覆盖客户端租户边界、停用扫描、审核和报备资料校验 |
| TC-REFACTOR-R3-008 | 执行R0R3门禁、API全量、前端构建及Gateway全量测试 | 数据库schema、migration、Redis Stream、CMPP协议、页面API契约和其他业务行为不因R3改变 |
## 2026-07-31 R4 报备资料与企业签名页面拆分用例
| 用例编号 | 场景 | 预期结果 |
|---|---|---|
| TC-REFACTOR-R4-001 | 执行`node tools/quality/verify-report-materials-r4.mjs` | 12个公开方法、11个内部方法、10个契约和32个辅助函数完整存在,领域归属与迁移前实现一致 |
| TC-REFACTOR-R4-002 | 控制器和其他模块继续注入`ReportMaterialsService` | 路由、DTO、请求和响应不变;控制器DTO改从独立contracts导入,内部领域服务不暴露给调用方 |
| TC-REFACTOR-R4-003 | 查询待生成资料、导入配置、导入审核批次和已生成批次 | 真实PostgreSQL分页、关键字和时间筛选保持,不创建批次、文件或操作记录 |
| TC-REFACTOR-R4-004 | 分析并提交Excel导入、逐行或批量审核 | 公式防护、图片提取、字段映射、暂存、审核人、原快照和错误隔离保持 |
| TC-REFACTOR-R4-005 | 使用同一幂等键预检并生成报备批次 | 批次预检、事务认领、完成/失败记录、通道导出文件和任务轨迹保持幂等 |
| TC-REFACTOR-R4-006 | 执行`node tools/quality/verify-enterprise-signatures-r4.mjs` | 原20个函数、签名/引流表格JSX、8个真实API调用和25个页面状态保持,页面容器只负责查询和协调 |
| TC-REFACTOR-R4-007 | 在企业签名页查询、展开签名、编辑签名/引流资料并查看报备弹窗 | 组件拆分后筛选、分页、展开、上传、保存、删除治理及通道状态操作保持真实后端链路 |
| TC-REFACTOR-R4-008 | 执行报备资料定向测试、API全量、前端构建和Gateway测试 | 既有测试全部通过,数据库schema、migration、Redis Stream、CMPP协议和其他页面不因R4改变 |
## 2026-07-31 R5 通道服务兼容门面拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R5-001 | 执行`node tools/quality/verify-channels-r5.mjs` | 37个公开方法、14个内部方法、17个契约和60个辅助声明完整存在,领域归属和迁移前实现一致 |
| TC-REFACTOR-R5-002 | 检查控制器、模块和既有测试调用 | 继续只依赖稳定`ChannelsService`DTO从独立contracts导入,路由、参数和响应结构不变 |
| TC-REFACTOR-R5-003 | 编辑名称、说明、成本等非连接参数 | 不调用Gateway断开/连接;只有连接参数实际变化且通道启用时才执行既有重连逻辑 |
| TC-REFACTOR-R5-004 | 执行通道连接、断开、状态同步和超时处理测试 | Gateway控制路径、Redis队列与Stream、定时器、慢重连和状态审计顺序保持 |
| TC-REFACTOR-R5-005 | 检查测试短信入口但不发送真实短信 | 手机号规范化、单次提交`maxAttempts=1`及结果口径保持;未获单独授权不得调用 |
| TC-REFACTOR-R5-006 | 查询和维护通道组、成员及路由规则 | 顺序、权重、主备、运营商/省份兼容性、补发和操作日志语义保持 |
| TC-REFACTOR-R5-007 | 查询报备字段、任务、导出、回执和记录 | 真实PostgreSQL分页、状态汇总、文件字段及历史记录保持,不因只读查询生成文件或写操作记录 |
| TC-REFACTOR-R5-008 | 执行Channels定向测试、API全量及R0~R5完整门禁 | 既有测试全部通过,数据库schema、migration、Redis Stream、Gateway、CMPP协议和其他业务不因R5改变 |
## 2026-07-31 R6 Gateway 入站服务拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R6-001 | 执行`go run tools/quality/verify-inbound-r6.go` | 迁移前93个声明在9个领域文件中全部存在,文件归属和实现哈希一致,`server.go`保持稳定入口 |
| TC-REFACTOR-R6-002 | 使用CMPP 2.0、2.1和3.0账号登录 | 版本协商、AuthSource、密码校验、企业代码、最大连接数和连接状态回调保持 |
| TC-REFACTOR-R6-003 | 分别提交单号码、多号码、8位及16位UDH长短信 | 每个目标号码保留独立内部消息映射;客户端每次Submit只收到一次SubmitResp,内容解码和Msg_Id保持 |
| TC-REFACTOR-R6-004 | Submit业务拒绝或API失败 | 同步返回原错误Result,不生成待投递失败回执,不把SubmitResp误记为成功 |
| TC-REFACTOR-R6-005 | Submit成功后立即存在排队回执 | Submit屏障保证SubmitResp先写出,回执Deliver不得抢先;原始Sequence_Id和Msg_Id映射可用于恢复 |
| TC-REFACTOR-R6-006 | 下发回执或上行并收到CMPP_DELIVER_RESP | 按连接、Sequence_Id和Msg_Id精确确认;成功、拒绝、超时及协议日志回调口径保持 |
| TC-REFACTOR-R6-007 | 当前进程找不到消息会话 | 只按原始Submit映射恢复,不允许退化为任意同账号连接;不可恢复时返回既有失败分类 |
| TC-REFACTOR-R6-008 | 多Gateway实例同时扫描待恢复投递 | Redis presence、恢复锁、退避、waiting_connection及完成状态保持,不重复投递 |
| TC-REFACTOR-R6-009 | 执行入站定向、Gateway全量测试和`go vet ./...` | 入站32项及Gateway所有package通过,没有竞态表现、编译错误或静态检查问题 |
| TC-REFACTOR-R6-010 | 执行API全量、前后端构建及R0~R6门禁 | 既有381项API测试和全部门禁通过,数据库schema、migration、Redis Stream及其他业务不因R6改变 |
## 2026-07-31 R7 Gateway 上游管理拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R7-001 | 执行`go run tools/quality/verify-upstream-r7.go` | 迁移前68个声明在9个领域文件中全部存在,接收者、文件归属和实现哈希一致,Manager入口保持 |
| TC-REFACTOR-R7-002 | 通过控制接口连接、重复连接及断开通道 | 连接池按通道唯一注册;配置变化才替换池;手工断开关闭stopCh并阻止后续自动重连 |
| TC-REFACTOR-R7-003 | 配置多物理连接和不同窗口大小并并发获取 | 轮询使用可用连接,每个连接独立占用和释放窗口,窗口满时等待且不突破Submit超时 |
| TC-REFACTOR-R7-004 | 供应商端点连接失败后恢复 | 临时网络错误按既有上限退避自动重连;鉴权失败使用5分钟慢重试;恢复后清零重连状态 |
| TC-REFACTOR-R7-005 | 心跳请求成功、响应不匹配或连续超时 | 只清除匹配Sequence_Id;超过阈值关闭连接、唤醒未决提交并进入重连状态机 |
| TC-REFACTOR-R7-006 | 分别向CMPP 2.0和3.0通道提交短信 | 使用对应Submit报文、企业代码、Src_Id、MsgFmt和接收号码;SubmitID及回调字段保持 |
| TC-REFACTOR-R7-007 | 提交UCS2长短信并逐分片返回不同结果 | 拆分、UDH、分片顺序、逐片回调、首Sequence_Id/Msg_Id及聚合停止条件保持 |
| TC-REFACTOR-R7-008 | 收到状态报告、普通上行及乱序长上行 | 回执状态映射、Submit tracker关联、内容解码、长上行组装和API事件保持 |
| TC-REFACTOR-R7-009 | 记录Submit和Deliver协议日志 | 只记录既有安全字段、方向、结果和长度,不泄露密码或完整敏感内容 |
| TC-REFACTOR-R7-010 | 执行上游定向、Gateway全量测试和`go vet ./...` | 上游18项及Gateway全部package通过,连接、重连、窗口、心跳和回执行为不变 |
| TC-REFACTOR-R7-011 | 执行API全量、前后端构建及R0~R7门禁 | 既有381项API测试和全部门禁通过,数据库、Redis Stream、通道配置及业务规则不因R7改变 |
## 2026-07-31 R8 发送链纯逻辑拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R8-001 | 执行`node tools/quality/verify-send-chain-r8.mjs` | 24个DTO/事件/队列契约和64个迁移纯声明实现哈希一致;98个编排方法及数据库、队列、重试和分片审计副作用仍由`SendChainService`持有 |
| TC-REFACTOR-R8-002 | 检查运营端、客户端和Gateway事件控制器 | 路由、参数和响应保持;控制器继续注入`SendChainService`DTO改从独立contracts导入 |
| TC-REFACTOR-R8-003 | 给定已按数据库优先级排序的省内和全国通道候选 | 过滤排除、未报备、运营商不兼容及不可连接通道后,优先选择匹配省份,省内不可用时使用全国兜底 |
| TC-REFACTOR-R8-004 | 分片审计尚未收齐、全部成功、存在明确失败或全部为未知 | 未收齐不产生最终成功;全部预期分片成功才成功;任一明确失败优先;收齐但无明确成功/失败时保持未知口径 |
| TC-REFACTOR-R8-005 | 比较上游端点并重复生成回执事件键 | 账号、主机、端口、协议和CMPP版本全部相同才视为同一端点;相同回执输入稳定生成相同事件键 |
| TC-REFACTOR-R8-006 | 运行纯逻辑与既有SendChain定向测试 | 省内/全国选择、分片最终状态、端点身份和事件键新增8项测试通过;既有104项发送链特征测试保持 |
| TC-REFACTOR-R8-007 | 对真实本地PostgreSQL执行只读核验 | 使用真实短信、分片审计和通道连接数据调用纯函数;无可用分片样本时明确记为不适用,不用mock或造数冒充通过 |
| TC-REFACTOR-R8-008 | 执行API全量、前后端构建、Gateway检查及R0~R8门禁 | 389项API测试和全部门禁通过;不改变schema、migration、事务范围、查询、日志字段、队列消息、CMPP协议或业务数据 |
## 2026-07-31 R9 发送入口与提交编排拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R9-001 | 执行`node tools/quality/verify-send-chain-r9.mjs` | 45个迁移方法在五个职责文件中的实现哈希保持,`SendChainService`98个稳定方法及内部兼容门面逐项委托 |
| TC-REFACTOR-R9-002 | 创建客户端批量任务或确认号码文件导入 | 非法、重复及黑名单号码先被剔除且不计频控;剩余号码按企业应用隔离执行任务风控、号码频控、日限额和余额预占 |
| TC-REFACTOR-R9-003 | 通过HTTP API提交模板短信 | 模板、签名、变量、企业和应用校验保持;每个号码独立消息记录,仍进入同一批量入口,不形成静态或旁路实现 |
| TC-REFACTOR-R9-004 | CMPP单号码、多号码和长短信入站 | 每个目标号码独立内部记录;同一业务号码只计一次频控和日限额,分片不重复计数;原SubmitResp和Msg_Id恢复语义保持 |
| TC-REFACTOR-R9-005 | 审核通过或拒绝待审核任务 | 通过时恢复消息并按内部批次逐一入队;拒绝时释放未扣预占并生成既有平台失败回执;不重复处理已完成任务 |
| TC-REFACTOR-R9-006 | 两个调度扫描器并发认领到期任务或恢复陈旧认领 | PostgreSQL条件更新保证只冻结和入队一次;入队失败保持可恢复状态,不丢失零资费任务 |
| TC-REFACTOR-R9-007 | Worker处理排队消息并发布Gateway提交 | 通道路由、报备校验、限速、Submit记录事务、BullMQ命令、Redis Stream消息和日志字段保持原顺序及内容 |
| TC-REFACTOR-R9-008 | 替换稳定门面的入队、调度、限速或队列方法后调用上层入口 | 新实现的内部跨方法调用仍经过稳定门面,既有测试缝和可观察边界不被绕过 |
| TC-REFACTOR-R9-009 | 检查R10事故高风险方法归属 | Gateway结果、分片提交/回执、最终聚合、补发、退款和下游投递仍保留在`SendChainService`R9不得提前迁移 |
| TC-REFACTOR-R9-010 | 对真实本地PostgreSQL调用任务查询和导入预检 | 使用真实服务与黑名单查询;任务、短信、频控状态和账户流水调用前后不变,不发送或创建短信 |
| TC-REFACTOR-R9-011 | 执行SendChain定向、API全量、前后端构建、Gateway及R0R9门禁 | 112项定向和389项API测试通过;schema、migration、Redis契约、CMPP协议及其他业务不因R9改变 |
## 2026-07-31 R10 发送完成链编排拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R10-001 | 执行`node tools/quality/verify-send-chain-r10.mjs` | 41个迁移方法在七个职责文件中的实现哈希保持;内部完成链门面和`SendChainService`98个稳定方法逐项委托 |
| TC-REFACTOR-R10-002 | Gateway逐分片返回提交成功、拒绝或异常 | 每个预期分片只形成对应审计;提交结果按既有聚合规则更新,不把SubmitResp误认为最终送达 |
| TC-REFACTOR-R10-003 | 重复接收相同上游回执事件 | 稳定事件键和数据库唯一约束保证收件箱、分片审计与最终回执幂等,不重复扣费或投递 |
| TC-REFACTOR-R10-004 | 当前补发尝试和迟到旧尝试分别返回回执 | 只有当前尝试能够推进最终状态;迟到旧尝试保留历史但不得覆盖当前结果 |
| TC-REFACTOR-R10-005 | 分片未收齐、全部成功、明确失败或全部未知 | 未收齐不提前成功;全部成功才最终成功;明确失败优先;未知按既有超时和失败口径处理 |
| TC-REFACTOR-R10-006 | 两个执行者并发抢占同一失败短信补发 | 来源提交唯一关系、事务条件更新和P2002唯一冲突处理保证最多创建一个新提交尝试 |
| TC-REFACTOR-R10-007 | 重复执行成功扣费、失败退款或预占释放 | 账务使用原稳定幂等键,同一业务事件只产生一次账户流水,余额和预占不重复变化 |
| TC-REFACTOR-R10-008 | 创建、认领、发送并ACK最终CMPP/HTTP回执 | 内部每短信只有一个最终业务结论;CMPP按原始客户分片投递并逐片去重,HTTP按消息投递并去重;attempt记录、ACK确认、超时恢复和失败分类保持 |
| TC-REFACTOR-R10-009 | 人工重排失败下游投递或恢复陈旧认领 | 使用稳定重排键和原状态条件,已完成或正由其他执行者处理的记录不得重复投递 |
| TC-REFACTOR-R10-010 | 执行回执超时扫描 | 仅处理满足既有时间和状态条件的当前记录;转为明确`EXPIRED`失败并为CMPP逐分片、HTTP逐消息建立可重试下游回执,建单标记未完成时后续扫描可恢复;扫描并发保护和内部终态聚合保持 |
| TC-REFACTOR-R10-011 | 检查七个完成链领域的持久化操作 | 不存在删除历史事故记录的`deleteMany`路径;提交、回执、attempt、死信和账务历史继续保留 |
| TC-REFACTOR-R10-012 | 对真实本地PostgreSQL查询R10八类表 | 查询前后计数完全一致;无分片或attempt样本时如实记为0,不造数、不发短信、不触发补发或重投 |
| TC-REFACTOR-R10-013 | 执行SendChain定向、API全量、前后端构建、Gateway及R0R10门禁 | 112项定向和389项API测试通过;schema、migration、事务语义、Redis契约、CMPP协议及其他业务不因R10改变 |
## 2026-07-31 R11 页面域与专属样式拆分用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-REFACTOR-R11-001 | 执行`node tools/quality/verify-admin-channels-r11.mjs` | 稳定页面入口不超过300行;五个聚焦模块、真实API调用、交互文案和页面CSS归属完整 |
| TC-REFACTOR-R11-002 | 打开运营端短信通道管理页 | 页面使用真实API返回通道、连接状态和质量数据;标题、筛选区、表头、行操作和分页正常渲染 |
| TC-REFACTOR-R11-003 | 输入通道名称后查询并执行重置 | 查询向真实后端传递筛选条件,列表和总数同步更新;重置恢复全部筛选和真实列表 |
| TC-REFACTOR-R11-004 | 打开编辑通道弹窗后取消 | 原通道名称、运营商、单价、地区、CMPP和心跳参数正常回填;取消不调用保存接口 |
| TC-REFACTOR-R11-005 | 打开连接日志并筛选 | 真实连接状态和日志数据正常展示;关键词只过滤当前结果,不改变通道或连接状态 |
| TC-REFACTOR-R11-006 | 检查发送测试弹窗但不提交 | 手机号、短信内容、接入号、计费条数和结果区域保持;未获授权不得点击最终发送按钮 |
| TC-REFACTOR-R11-007 | 检查复制、启停、删除和添加入口但不确认 | 所有既有入口和确认提示保持;页面拆分不会旁路原API或自动执行写操作 |
| TC-REFACTOR-R11-008 | 检查`global.css`、`admin.css`与页面CSS | 通道页专属选择器只存在于`AdminChannelsPage.css`;共享`.channel-confirm`由admin层托管,移动端连接摘要规则保持 |
| TC-REFACTOR-R11-009 | 在默认桌面与375×812视口检查页面 | 页面非空、无框架错误覆盖、控制台无相关warning/error;窄屏继续使用既有横向表格浏览方式 |
| TC-REFACTOR-R11-010 | 执行前端生产构建、API/Gateway全量及R0~R11门禁 | 真实后端契约、数据库、Redis Stream、Gateway和CMPP协议不因前端结构迁移改变 |
| TC-REFACTOR-R11-011 | 执行`node tools/quality/verify-admin-sms-task-progress-r11.mjs` | 稳定页面入口不超过220行;六个聚焦模块、真实任务/号码/终止API、交互文案和页面CSS归属完整 |
| TC-REFACTOR-R11-012 | 打开运营端短信任务进度页 | 页面使用真实API返回客户批量任务、企业和应用筛选项;批次号、企业应用、提交时间、号码数、进度、状态和分页正常渲染 |
| TC-REFACTOR-R11-013 | 输入不存在的发送批次号查询,再重置并查询 | 不存在条件返回真实空列表;重置清空全部条件,再次查询恢复真实任务和总数 |
| TC-REFACTOR-R11-014 | 打开真实任务详情 | 提交、发送、计费和成功率指标以及模板、进度、运营商和省份聚合保持原口径,不在前端伪造数据 |
| TC-REFACTOR-R11-015 | 打开号码列表并按部分手机号查询 | 调用真实批次号码分页接口;手机号、归属地、运营商和短信状态与后端一致,筛选后总数同步变化 |
| TC-REFACTOR-R11-016 | 打开终止确认后取消 | 确认文案和已提交部分提示保持;取消不调用终止接口、不改变任务状态 |
| TC-REFACTOR-R11-017 | 检查`global.css`、`admin.css`与短信任务页面CSS | 页面详情、运营商卡片和移动端专属选择器只存在于页面CSS;报备/下游等运营页面共用的筛选、表格、标识和卡片选择器由admin层托管 |
| TC-REFACTOR-R11-018 | 在默认桌面与375×812视口检查短信任务页面 | 页面、详情弹窗和窄屏卡片均非空且无框架错误覆盖;控制台无warning/error,长表格保持既有可浏览方式 |
| TC-REFACTOR-R11-019 | 执行前端生产构建、API/Gateway全量及全部R0R11门禁 | 389项API测试、Prisma/API构建、Gateway测试/vet和依赖门禁通过;短信、任务、数据库和协议行为不因页面结构迁移改变 |
| TC-REFACTOR-R11-020 | 执行`node tools/quality/verify-admin-sms-records-r11.mjs` | 稳定页面入口不超过220行;四个聚焦模块、五个真实API调用、交互文案、专属与共享CSS归属完整 |
| TC-REFACTOR-R11-021 | 打开运营端短信记录页 | 默认日期范围、企业/应用/运营商/状态选项、内容与通道筛选、后端导出入口、记录列表和分页正常渲染 |
| TC-REFACTOR-R11-022 | 清空默认日期并查询全部真实记录 | 后端返回实际记录与总数,前端不使用静态数组;超过25条时真实分页总页数和上下页状态正确 |
| TC-REFACTOR-R11-023 | 输入完整或部分手机号查询 | 查询参数传给真实记录API,结果、总数和分页同步收窄;不存在的号码显示真实空状态 |
| TC-REFACTOR-R11-024 | 展开运营商筛选 | 固定提供全部、移动、联通、电信、未识别,选择后使用后端`carrier`条件查询 |
| TC-REFACTOR-R11-025 | 打开真实记录的发送详情 | 最终/提交/回执状态、号码归属、接入号、短信内容、通道尝试及回执时间/码与后端数据一致 |
| TC-REFACTOR-R11-026 | 查看有分片与无分片的详情 | 分片审计调用真实接口;有数据按时间、分片序号和ID排序,无数据明确显示暂无分片审计,不造数 |
| TC-REFACTOR-R11-027 | 检查后端CSV导出边界 | 导出继续调用`exportOperationMessages`并使用当前筛选条件,不退化为仅导出当前页的浏览器静态数据 |
| TC-REFACTOR-R11-028 | 检查`global.css`、`components.css`与短信记录页面CSS | 页面列表、详情、路由、分片和响应式选择器只存在于页面CSS;共享弹窗标题和空状态由components托管,弱化文本样式仍在global |
| TC-REFACTOR-R11-029 | 在默认桌面与375×812视口检查短信记录页面 | 筛选区、记录卡片、详情弹窗和分页非空且无框架错误覆盖;控制台无相关warning/error,窄屏字段不重叠 |
| TC-REFACTOR-R11-030 | 执行前端生产构建、API/Gateway全量及全部R0R11门禁 | 389项API测试、Prisma/API构建、Gateway测试/vet和依赖门禁通过;短信记录、回执和协议行为不因页面拆分改变 |
| TC-REFACTOR-R11-031 | 执行`node tools/quality/verify-admin-enterprise-applications-r11.mjs` | 稳定页面入口不超过300行;六个聚焦模块、六类真实API调用、交互文案、筛选状态分层和页面CSS归属完整 |
| TC-REFACTOR-R11-032 | 打开运营端企业应用管理页 | 页面使用真实分页API返回应用、企业、今日发送、到达率、单价、客户连接状态和应用状态,不使用静态数组 |
| TC-REFACTOR-R11-033 | 输入不存在的企业或应用名称查询,再重置 | 查询条件传给真实后端,列表和总数同步变为空;重置恢复全部条件、第一页和真实应用列表 |
| TC-REFACTOR-R11-034 | 点击添加应用并取消 | 弹窗通过真实企业接口加载未删除企业;未选择企业时下一步禁用,取消不导航、不创建应用 |
| TC-REFACTOR-R11-035 | 打开CMPP连接详情 | 当前连接数、配置连接数、AppID、连接状态和真实已连接会话保持;无会话时显示真实空状态 |
| TC-REFACTOR-R11-036 | 打开CMPP或HTTP参数弹窗后关闭 | 参数由真实详情接口返回;标题、企业/应用上下文和复制入口保持,关闭不修改接口凭据或应用配置 |
| TC-REFACTOR-R11-037 | 打开启用、停用或删除确认后取消 | 停用先调用真实影响预检;等待清算与强制停用文案、未决项统计和确认边界保持,取消不调用状态变更接口 |
| TC-REFACTOR-R11-038 | 检查短信/彩信页签 | 短信应用显示真实表格与分页;彩信继续明确为后端能力待确认,不用mock或静态数据伪造功能 |
| TC-REFACTOR-R11-039 | 检查`global.css`、`admin.css`、`components.css`、`shell.css`与企业应用页面CSS | 筛选、连接、参数和新增提示专属选择器只存在于页面CSS;共享筛选/确认由admin托管,弹窗标题/表单布局由components托管,section布局由shell托管 |
| TC-REFACTOR-R11-040 | 在默认桌面与375×812视口检查企业应用页面 | 页面、筛选、横向表格和安全只读弹窗非空且无框架错误覆盖;控制台无相关warning/error |
| TC-REFACTOR-R11-041 | 执行前端生产构建、API/Gateway全量及全部R0R11门禁 | 389项API测试、Prisma/API构建、Gateway测试/vet和依赖门禁通过;企业应用、连接、数据库和协议行为不因页面拆分改变 |
| TC-REFACTOR-R11-042 | 执行`node tools/quality/verify-foundation-styles-r11.mjs` | 76个设计令牌、13组reset/base规则、逐规则声明哈希、选择器所有权和当前`tokens → reset → shell → global → admin → client → components → AppRoutes`依赖顺序完整 |
| TC-REFACTOR-R11-043 | 检查`tokens.css`、`reset.css`和`global.css`职责 | tokens只保留`:root`设计令牌;reset只含元素级基础规则;原global不再重复拥有这些规则,AppShell、组件及页面类未在本步骤迁移 |
| TC-REFACTOR-R11-044 | 执行前端TypeScript及Vite生产构建并检查产物CSS位置 | 新增reset入口进入生产CSS依赖图,实际产物按tokens、reset、global、components/页面依赖顺序拼接;CSS总体体积和既有单chunk提示无异常增长 |
| TC-REFACTOR-R11-045 | 打开已登录运营端代表页面 | 页面背景、字体、标题、链接、按钮、输入框、下拉框、禁用态、表格和弹窗保持,真实API数据正常渲染 |
| TC-REFACTOR-R11-046 | 打开客户端登录页 | Logo、标题、说明、账号/密码/验证码输入、登录按钮和链接保持;不提交登录表单、不改变会话 |
| TC-REFACTOR-R11-047 | 使用键盘聚焦可交互控件 | `:focus-visible`继续显示令牌化焦点环;普通焦点不出现浏览器默认outline,禁用控件仍为不可操作光标 |
| TC-REFACTOR-R11-048 | 在默认桌面与375×812视口检查运营端和客户端代表页面 | 页面非空、无框架错误覆盖或页面级横向溢出,排版和控件没有因reset加载顺序产生跳变;控制台无相关warning/error |
| TC-REFACTOR-R11-049 | 执行API/Gateway全量、Prisma、安全门禁、全部R0~R11结构门禁和`git diff --check` | 389项API测试、API构建、Gateway测试/vet及全部门禁通过;数据库、Redis、CMPP和业务行为不因基础CSS迁移改变 |
| TC-REFACTOR-R11-050 | 执行`node tools/quality/verify-app-shell-styles-r11.mjs` | 118组壳层规则、44个壳层类、九组通用布局选择器、三类响应式/动效边界和样式所有权完整 |
| TC-REFACTOR-R11-051 | 检查`main.tsx`及生产产物CSS | 依赖顺序为`tokens → reset → shell → global → admin → client → components → AppRoutes`,壳层代表规则位于各页面域和components之前 |
| TC-REFACTOR-R11-052 | 检查`global.css`、`shell.css`和组件样式职责 | AppShell和通用布局原语只由shell托管;在第六步时复用的`.icon-button`、页签、表格、表单和弹窗尚未迁移,第七步迁移后由components托管,页面域样式仍不越界 |
| TC-REFACTOR-R11-053 | 在已登录运营端桌面宽屏点击收起/展开导航 | 主区列宽在标准侧栏和76px折叠栏间切换;完整/紧凑Logo、菜单图标和活动态正常,无内容遮挡 |
| TC-REFACTOR-R11-054 | 在已登录运营端打开并关闭通知及用户菜单 | 弹层定位、层级、计数和空状态保持;只读开关弹层不触发退出、审核、配置或其他写操作 |
| TC-REFACTOR-R11-055 | 在375×812视口打开并关闭移动导航 | 顶栏显示移动入口,侧栏以抽屉和遮罩呈现;关闭按钮/遮罩可收起,页面无横向溢出 |
| TC-REFACTOR-R11-056 | 在系统减少动画偏好下检查侧栏 | 侧栏过渡被关闭,布局和可操作性不变 |
| TC-REFACTOR-R11-057 | 无可用运营端登录态或遇到验证码 | 不伪造会话、不读取浏览器存储、不绕过验证码;将真实点击验收标记为受阻并保留代码级结果 |
| TC-REFACTOR-R11-058 | 执行前端生产构建、API/Gateway全量、Prisma、安全门禁、全部R0~R11结构门禁和`git diff --check` | 29个API套件/389项测试、API构建、Gateway测试/vet及全部门禁通过;数据库、Redis、CMPP和业务行为不因壳层CSS迁移改变 |
| TC-REFACTOR-R11-059 | 执行`node tools/quality/verify-shared-components-r11.mjs` | 259组规则、291个选择器、14组通用类族、桌面/780px所有权和Button/Input/Select/Table/Modal真实绑定完整 |
| TC-REFACTOR-R11-060 | 检查`global.css`与`components.css`职责 | 纯通用表格、表单、弹窗、页签、图标按钮和表格辅助类只由components托管;页面域复合选择器不被误迁 |
| TC-REFACTOR-R11-061 | 检查组件级联和入口加载顺序 | 兼容规则位于规范组件规则之前,响应式规则位于对应桌面规则之后;最终`tokens → reset → shell → global → admin → client → components → AppRoutes`顺序完整 |
| TC-REFACTOR-R11-062 | 在已登录运营端打开代表性表格并检查空/有数据状态 | 真实后端数据、表头、行、操作区、分页和空状态保持;移动端卡片标签和字段值不重叠 |
| TC-REFACTOR-R11-063 | 打开并关闭普通、宽版和XL代表弹窗 | 遮罩、标题、关闭按钮、正文滚动、页脚操作和宽度保持;仅打开/取消不调用写接口 |
| TC-REFACTOR-R11-064 | 检查代表性表单、单选、页签和图标按钮 | 输入、选择、双列表单、单选行、活动页签、图标按钮及焦点/禁用/悬停状态保持 |
| TC-REFACTOR-R11-065 | 在375×812视口检查表格、表单和弹窗 | 表格使用既有移动卡片布局,表单双列改为单列,弹窗不超出视口,操作按钮可见且页面无横向溢出 |
| TC-REFACTOR-R11-066 | 在PostgreSQL停止但API/Redis仍运行时用有效运营会话恢复 | 会话中间件查用户时应暴露数据库连接异常;当前实现会返回500,不能误归因为前端会话拆分,后续可单独评估health与错误映射增强 |
| TC-REFACTOR-R11-067 | 恢复PostgreSQL后检查会话边界 | 真实Prisma用户查询恢复;无cookie访问`/api/admin/auth/session`返回401,运营端跳转登录页而非500;不得绕过验证码伪造登录态 |
| TC-REFACTOR-R11-068 | 执行前端生产构建、API/Gateway全量、Prisma、安全门禁、全部R0~R11结构门禁和`git diff --check` | 29个API套件/389项测试、API构建、Gateway测试/vet及全部门禁通过;业务、数据库、Redis、Gateway和CMPP行为不因通用组件CSS迁移改变 |
| TC-REFACTOR-R11-069 | 执行`node tools/quality/verify-admin-shared-styles-r11.mjs` | 117组规则、141个选择器、11项跨页面使用下限、admin/client所有权和780px/360px响应式边界完整 |
| TC-REFACTOR-R11-070 | 检查`main.tsx`及生产CSS依赖图 | 最终加载顺序为`tokens → reset → shell → global → admin → client → components → AppRoutes`admin/client域位于global之后、通用组件之前 |
| TC-REFACTOR-R11-071 | 检查`global.css`与`admin.css`所有权 | 纯admin共享选择器只由admin托管;global只保留带单页面上下文的覆盖规则,client源码不引用admin所有权类 |
| TC-REFACTOR-R11-072 | 打开审核中心的企业、短信、模板、签名和引流审核页 | 审核筛选卡、响应式网格、查询/重置操作和审核操作布局保持,真实后端数据与原API不变 |
| TC-REFACTOR-R11-073 | 打开任务进度、报备记录及下游记录代表页面 | 共用筛选区、任务表格卡、批次标识、企业信息、分页和详情入口保持,真实分页与筛选参数不变 |
| TC-REFACTOR-R11-074 | 打开全局黑名单、企业黑名单和敏感词页面 | 安全页标题、筛选、表单、表格及移动端布局保持;只读验收不新增、删除或导入数据 |
| TC-REFACTOR-R11-075 | 打开用户、号段和引流字段等系统管理代表页面 | 系统工具栏、表格卡、弹窗双列表单和操作区保持;打开后取消,不执行创建、编辑或删除 |
| TC-REFACTOR-R11-076 | 打开质量、利润和对账统计页 | 三类统计筛选网格及查询按钮在桌面和780px下保持,仍调用真实统计接口,不使用静态数据 |
| TC-REFACTOR-R11-077 | 在375×812视口检查审核、任务、安全和系统代表页面 | 筛选区转为单列或既有紧凑布局,按钮宽度、表格/卡片和弹窗不发生页面级横向溢出 |
| TC-REFACTOR-R11-078 | 执行前端生产构建、API/Gateway全量、Prisma、安全门禁、全部R0~R11结构门禁和`git diff --check` | 29个API套件/389项测试、API构建、Gateway测试/vet及全部门禁通过;业务、数据库、Redis、Gateway和CMPP行为不因admin共享CSS迁移改变 |
| TC-REFACTOR-R11-079 | 执行`node tools/quality/verify-client-shared-styles-r11.mjs` | client唯一共享规则、两页面使用下限、三组跨门户兼容边界和五类单页面保留边界完整 |
| TC-REFACTOR-R11-080 | 核对client/admin源码类引用 | `.eyebrow`至少由客户端首页和账单页使用且运营端不引用;没有为了扩大迁移量而错误处理单页面类 |
| TC-REFACTOR-R11-081 | 检查`global.css`与`client.css`所有权 | 纯`.eyebrow`声明只由client托管;`.overview-hero .eyebrow`页面覆盖继续留在global |
| TC-REFACTOR-R11-082 | 检查跨门户兼容类 | `.sms-send-title`、`.system-page-toolbar`和`.system-table-card`继续留在global,客户端与运营端系统日志页面均不丢失样式 |
| TC-REFACTOR-R11-083 | 打开客户端首页和账户账单页 | eyebrow颜色、字号、字重和间距保持;真实首页与账单API数据正常渲染 |
| TC-REFACTOR-R11-084 | 打开签名、发送、企业认证、发送详情和模板代表页面 | 各单页面样式仍由原global规则托管,页面结构、真实接口和交互不因第九步改变 |
| TC-REFACTOR-R11-085 | 在375×812视口检查首页、账单及一个单页面代表 | 标题、卡片、表格和操作区无新增横向溢出,控制台无相关warning/error |
| TC-REFACTOR-R11-086 | 执行前端生产构建、API/Gateway全量、Prisma、安全门禁、全部R0~R11结构门禁和`git diff --check` | 29个API套件/389项测试、API构建、Gateway测试/vet及全部门禁通过;R11九步完成且业务行为不因client共享CSS迁移改变 |
## 2026-08-03 工作台金额与审核筛选回归用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-CLIENT-DASHBOARD-012 | 使用客户端企业登录短信服务工作台,对比 Dashboard API、数据库当天消费聚合和页面金额卡 | “今日消费金额”位于“今日返还金额”之前,展示当前企业北京时间当天真实消费金额;刷新后与 API/数据库一致,不使用静态值或浏览器缓存计算 |
| TC-AUDIT-FILTER-014 | 依次打开企业认证、短信、模板、签名、引流信息五个审核页面,选择同一提交日期区间并查询 | 五页均显示日期区间控件;请求携带开始/结束日期,列表只返回 PostgreSQL 中提交时间位于北京时间闭区间内的记录 |
| TC-AUDIT-FILTER-015 | 在签名和引流信息审核页切换到“导入批次审核”,按提交时间查询并翻页 | 导入批次真实分页 API 同时携带日期条件,当前页和总数均受日期范围约束,不在前端仅过滤当前页 |
| TC-AUDIT-FILTER-016 | 分别只选择开始日、只选择结束日、选择跨日范围,再输入非法日期或开始日晚于结束日直接调用 API | 单边范围可正确查询;完整范围包含开始日 00:00:00 和结束日 23:59:59.999;非法或倒置范围返回受控 400,不执行无界误查询 |
| TC-QUERY-LAYOUT-009 | 在风控规则页检查规则范围、平台白名单和号码频次触发记录查询区,并执行查询与重置 | 普通控件使用统一标准宽度,条件可换行但不占满整行;查询/重置按钮等宽;重置后白名单恢复全部有效记录,触发记录恢复“拦截中”并重新请求真实后端 |
| TC-QUERY-LAYOUT-010 | 在五个审核页面及导入审核页签检查普通控件、日期区间和查询/重置按钮,并切换桌面与375×812视口 | 普通控件宽度一致,日期区间明显更宽,查询/重置按钮宽度一致;窄屏转为整行且无横向溢出、遮挡或弹层裁切 |
## 2026-08-03 引流信息识别与统计用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-DRAINAGE-DETECT-001 | 在引流识别规则页新增、编辑、停用规则并刷新 | 所有操作调用真实后端并持久化到 PostgreSQL;版本递增、状态生效并留下操作日志,刷新后不丢失 |
| TC-DRAINAGE-DETECT-002 | 分别测试协议 URL、裸域名、短链接、IP:端口/路径及中文标点相邻链接 | 均识别为含引流,命中类型为 URL,保存原始内容位置;检测不会改写短信原文 |
| TC-DRAINAGE-DETECT-003 | 输入使用中文句号代替域名点号的URL以及普通邮箱地址 | 中文句号域名仍命中;完整或带空格规避的邮箱不被当作引流URL或手机号 |
| TC-DRAINAGE-DETECT-010 | 分别在协议URL、裸域名或路径后加入空格、制表符、换行、全角空格及后续字符,并输入空格拆分域名 | URL命中原文和位置均在首个空白前结束,空白后字符不属于前一个链接;空格拆分域名不被拼接恢复,短信原文不被改写 |
| TC-DRAINAGE-DETECT-004 | 测试`+86 138 0013 8000`、`138-0013-8000`及中文标点拆分手机号 | 均识别为手机号引流,原文片段可在短信记录中正确高亮 |
| TC-DRAINAGE-DETECT-005 | 测试`0108888-8888 转 123`等固话 | 区号括号、分隔符和分机号均可识别为固定电话引流 |
| TC-DRAINAGE-SEND-001 | 使用待审核、驳回或未报备的既有引流资料分别创建客户端批次和 CMPP 入站任务 | 不产生`DRAINAGE_NOT_APPROVED`,不因引流资料状态拒绝或转人工;其他发送校验仍正常执行,禁止用真实短信完成自动测试 |
| TC-DRAINAGE-RECORD-001 | 查询含引流、不含引流和未检测三类短信记录并导出 CSV | PostgreSQL 分页和总数按筛选值返回;含引流原文使用提示色和片段高亮;CSV“是否含引流”与数据库一致 |
| TC-DRAINAGE-STATS-001 | 打开签名发送质量明细并切换“整体统计/按引流切分” | 整体矩阵显示全部通道×运营商真实提交;切分矩阵分别显示含引流、不含引流、未检测,分组计数之和等于整体计数 |
| TC-DRAINAGE-DASHBOARD-001 | 对比运营看板两个签名统计表与数据库当天数据 | “今日签名发送统计”包含全部短信;“含引流”表只包含`hasDrainageContent=true`,历史 null 不计入含引流 |
| TC-DRAINAGE-SAFETY-001 | 保存超长、非法标志、后行断言、反向引用或嵌套量词规则 | API 返回受控参数错误,不保存可能在发送入口造成灾难性回溯的规则 |
## 2026-08-03 CMPP逐分片回执与超时失败回执用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-RECEIPT-FRAGMENT-001 | 客户提交三分片长短信,每片`Registered_Delivery=1`,供应商三片分别返回成功、成功、失败 | 内部主记录只形成一个最终业务结论;下游产生3条CMPP状态报告,各自Msg_Id等于对应SubmitResp Msg_Id,状态/原始码/时间来自对应上游分片;HTTP只产生1个消息级最终事件 |
| TC-RECEIPT-FRAGMENT-002 | 三分片中第二片`Registered_Delivery=0`,其余两片为1 | 数据库保留三片的真实请求值;下游只为第一、三片建立CMPP状态报告,第二片不生成;不影响内部整条短信状态和HTTP最终事件 |
| TC-RECEIPT-FRAGMENT-003 | 对同一长短信终态并发处理三次并重放重复上游回执 | 每个原始客户分片最多一条`CmppDownstreamDelivery`,唯一键分别含分片序号;已建立分片不重复发,HTTP稳定事件不重复,退款和补发仍只有一次 |
| TC-RECEIPT-FRAGMENT-004 | 客户在线时分别向同一长短信的两个分片推送回执 | Gateway发送的两个`CMPP_DELIVER`回执内容分别携带两个不同的原SubmitResp Msg_Id,不因在线会话按业务消息查找而都复用第一片Msg_Id |
| TC-RECEIPT-TIMEOUT-005 | HTTP消息超过72小时无明确回执,首次Webhook建单失败,下一轮扫描恢复 | 主记录只转一次`timeout`并只退款一次;失败时`timeoutReceiptQueuedAt`为空,后续扫描补建`undelivered/EXPIRED/RECEIPT_TIMEOUT`事件后写入标记,HTTP最终事件只有一个 |
| TC-RECEIPT-TIMEOUT-006 | CMPP长短信超过72小时无明确回执,其中部分片已有真实回执,其余片缺失 | 已有结果的分片保留自己的最终状态;缺失片收到明确`EXPIRED`失败回执;每片使用各自原SubmitResp Msg_Id并可分别ACK,重复扫描不重复发送 |
## 2026-08-06 供应商整条级回执与网关异常中心用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-RECEIPT-MODE-001 | 新建或编辑通道,不设置长短信成功回执口径;两分片长短信只收到第一片成功 | 后端按`per_segment`默认值保存;真实回执和第一片审计落库,第二片仍无回执,主记录保持`submitted`,不提前退款、补发或推送最终成功 |
| TC-RECEIPT-MODE-002 | 将测试通道设置为`message_level`,两分片当前提交尝试只收到一条明确成功回执 | 只新增一条真实`SmsReceiptRecord`;缺失分片审计被标记`delivered`且`compensationType=supplier_message_level_receipt`,主记录形成一次成功终态,并按客户原始`Registered_Delivery`逐片幂等建立CMPP回执或建立一个HTTP事件 |
| TC-RECEIPT-MODE-003 | 在`message_level`通道中,对含明确失败分片、历史提交尝试或单分片短信输入成功回执 | 明确失败不被覆盖,历史尝试不改变当前终态,单分片不产生推断分片;不得重复计费、退款、补发或下游投递 |
| TC-RECEIPT-CONFLICT-001 | 整条级成功已经形成`delivered`后,同一提交尝试又收到明确失败回执,并重复输入同一矛盾事件 | 原始失败回执和分片证据保留;主记录仍为`delivered`,不补发、不退款、不向客户推送失败;`SmsReceiptAnomaly`按稳定键只有一条记录并累加发生次数 |
| TC-GATEWAY-EXCEPTION-UI-001 | 打开运营端“网关异常”,切换“提交异常”和“回执异常”Tab并刷新、筛选、翻页 | 菜单新名称和两个Tab正常展示且原路由可访问;两个Tab分别调用真实提交死信API和回执异常API,筛选、汇总、总数和分页与PostgreSQL一致,不使用mock、静态数据或localStorage |
| TC-GATEWAY-EXCEPTION-UI-002 | 阅读两个Tab标题说明并打开两类详情 | “提交异常”明确说明死信不等于供应商拒绝/送达失败及重入队风险;“回执异常”明确说明其为终态冲突摘要,并指向真实回执记录和通讯交互日志,详情不泄露通道密码或鉴权信息 |
## 2026-08-09 休眠唤醒与会话锁定恢复用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-AUTH-014 | 在运营端短信记录页长时间无操作或让桌面进入锁定/休眠,超过运营端空闲期限后唤醒浏览器并观察网络请求,再输入当前密码解锁 | 锁定后短信记录路由暂停,全局`pending-audits`轮询停止,唤醒产生的焦点事件不继续请求受保护接口;解锁成功后返回短信记录路由并重新请求真实短信记录、企业和应用选项,页面无连续401 |
| TC-AUTH-015 | 让旧会话活动时间超过空闲期限并进入完整登录页,在不刷新浏览器标签的情况下使用正确账号、密码和验证码重新登录 | 登录成功立即建立新的前端活动起点;新会话不会在1至2秒内调用`/auth/session/lock`,可正常打开短信记录并调用真实后端 |
| TC-AUTH-016 | 分别由前端空闲计时、服务端`SESSION_LOCKED`响应和另一标签页锁定事件触发运营端锁屏,再由当前或另一标签页解锁 | 三种入口均同步锁屏、暂停业务路由和角标轮询;解锁后统一恢复,重复锁定/解锁事件幂等,不产生额外业务写入 |
## 2026-08-09 签名删除预检与多通道报备汇总用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-DELETE-SIGNATURE-004 | 对仅存在`approved`、`abandoned`等已结束报备任务,且无模板、引流信息或其他活动依赖的签名执行删除预检 | 已结束报备任务不出现在“未结束报备任务”中,删除预检允许继续;历史任务和记录仍保留 |
| TC-DELETE-SIGNATURE-005 | 运营端对仍存在`pending`、`waiting_material`、`reporting`或`exporting`任务的签名执行删除预检 | 预检列出真实未结束任务ID和状态,出现“同时结束关联的报备任务”必选项;未勾选不能确认,勾选后可继续 |
| TC-DELETE-SIGNATURE-006 | 签名同时关联未删除模板、引流信息和未结束报备任务 | 分别出现三个级联勾选项;少勾选任意一项时确认按钮不可用且后端直接调用也拒绝,全部勾选后才可确认 |
| TC-DELETE-SIGNATURE-007 | 客户端删除存在未结束报备任务的签名 | 页面只展示统一的结束报备说明和勾选项;API及页面均不出现任务ID、状态、通道等内部详情;全部关联项勾选后允许确认 |
| TC-DELETE-SIGNATURE-008 | 全部勾选后删除同时关联模板、引流信息和过程态报备任务的签名 | 同一`Serializable`事务内模板、引流信息和签名均逻辑删除,任务置为`abandoned`;每条任务及子对象均有真实审计记录,历史消息、计费、审核和报备记录保留 |
| TC-DELETE-SIGNATURE-009 | 关联模板仍存在未结束发送或批量任务 | 即使勾选“同时删除关联的模板”仍由真实活动任务阻止删除,不中断或丢失正在处理的数据 |
| TC-DELETE-CHANNEL-010 | 通道仅关联未结束报备任务,没有活动组、直接路由或连接 | 出现“同时结束关联的报备任务”必选项;勾选后任务置为`abandoned`并写记录,通道逻辑删除,受影响有效签名按剩余有效通道重算汇总 |
| TC-DELETE-CHANNEL-011 | 通道仍存在活动通道组、直接路由或活动网关连接 | 报备任务勾选项不能绕过其他硬依赖,后端拒绝删除并返回真实阻断原因 |
| TC-DELETE-REASON-012 | 分别在运营端和客户端删除无硬依赖的通道、签名、模板,删除原因留空或填写内容 | 留空时允许删除;填写时原文进入审计详情,三类对象均不再要求至少4个字符 |
| TC-DELETE-TEMPLATE-013 | 模板关联任意终态或过程态的发送审核任务和批量任务 | 单独删除模板不查询也不依赖任务是否结束;模板逻辑删除成功,既有任务和历史关联不变 |
| TC-DELETE-TEMPLATE-014 | 使用已逻辑删除的模板创建新发送任务 | 后端拒绝创建,不产生批量任务、消息或计费记录 |
| TC-DELETE-TEMPLATE-015 | 已接受的定时任务到点前,其模板被逻辑删除,企业、应用和签名仍有效 | 任务按已持久化内容快照冻结费用并入队,不因模板当前`deleted`状态失败 |
| TC-DELETE-TEMPLATE-016 | 已接受的定时任务到点前,其签名变为未通过或删除 | 仍按签名安全规则阻断调度,不冻结费用、不入队,任务和消息记录真实标记失败原因 |
## 2026-08-09 通道组删除风险展示与历史保留用例
| 用例编号 | 场景 | 预期结果 |
| --- | --- | --- |
| TC-CHANNEL-GROUP-DELETE-001 | 打开同时关联正常应用、已删除应用、多个通道和`queued`提交记录的通道组删除弹窗 | 后端按不同应用ID去重并保留审计统计;弹窗只展示关联正常企业应用、组内通道、等待供应商提交结果三项真实数量,标题、数量单位、说明和按钮文案与需求一致 |
| TC-CHANNEL-GROUP-DELETE-002 | 同一正常企业应用存在多条通道组关联 | “关联正常企业应用”只计1个,不按关联规则条数重复累计 |
| TC-CHANNEL-GROUP-DELETE-003 | 关联记录指向状态为`deleted`或已不存在的企业应用 | 两类均不计入正常应用,删除弹窗不展示“关联已删除企业应用”;后台审计快照仍可保留其真实数量 |
| TC-CHANNEL-GROUP-DELETE-004 | 通道组存在正常/已删除应用关联、组内通道或等待供应商提交记录后确认删除 | 所有业务依赖只展示不阻止;后端将通道组状态置为`deleted`并写操作审计,不物理删除关联和历史记录 |
| TC-CHANNEL-GROUP-DELETE-005 | 删除通道组后查询通道组列表并发送新短信 | 默认列表不再显示该组,新短信选路不再选择该组 |
| TC-CHANNEL-GROUP-DELETE-006 | 删除通道组后查询历史发送/回执/审计,或按历史通道接入号处理上行 | 组内通道、应用关联、发送、回执和审计数据仍存在,历史链路可追溯 |
| TC-CHANNEL-GROUP-DELETE-007 | 删除影响数据仍在加载或加载失败 | 加载期间不允许盲目提交;失败时明确展示接口错误,不使用静态数量或本地伪数据 |
| TC-SIGNATURE-REPORT-AGG-001 | 同一签名两个目标通道分别为`approved`和`failed` | 签名整体及对应多目标汇总为“部分成功”,页面显示部分通道通过;失败通道及原因仍可查看,不显示整体报备失败 |
| TC-SIGNATURE-REPORT-AGG-002 | 同一签名两个目标通道分别为`pending`和`failed` | 签名整体保持“报备中”,不因一个通道失败提前结束;失败通道明细继续展示 |
| TC-SIGNATURE-REPORT-AGG-003 | 同一签名所有当前目标通道均为`failed/rejected` | 签名整体为“报备失败”;各通道失败事实和原因均保留 |
## 2026-08-09 发送质量矩阵与成功率色阶用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-ANALYTICS-SIGNATURE-004 | 打开签名通道发送质量明细并切换到“按引流切分”,检查多个通道及三网组合 | 每个通道固定依次展示“含引流、不含引流、未检测”三行,固定依次展示“移动、联通、电信”三列;缺少真实提交的组合显示`0`,其他组合与真实API数据一致 |
| TC-ANALYTICS-SIGNATURE-005 | 分别构造或选择成功率为`0、0.1、25、25.1、50、50.1、75、75.1、95.9、96`的签名统计结果,检查列表、明细总览、运营商概览和矩阵 | 数字颜色依次落入红、橙、橙、黄、黄、蓝、蓝、绿、绿、深绿;所有签名质量展示位置使用同一边界函数,统计值不被前端改写 |
| TC-CHANNEL-QUALITY-COLOR-001 | 在短信通道管理列表和通道报备详情检查上述成功率边界 | 送达成功率数字使用与签名质量相同的六档色阶;列表与详情对同一成功率显示一致 |
| TC-CHANNEL-QUALITY-COLOR-002 | 选择提交失败、回执未知或送达失败比例与数量均非零的通道,检查通道管理列表和报备详情 | 三类非成功指标的比例与数量均为黑灰色,不显示红色、橙色或成功率色阶;真实比例、数量及后端数据保持不变 |
## 2026-08-09 运营端菜单与查询控件细节用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-ADMIN-NAV-006 | 展开“审核中心”和“安全控制”,再打开风控规则页面 | “审核中心”不再显示风控规则,“安全控制”显示且可正常进入;页面面包屑为“安全控制 / 风控规则”,路由和真实规则数据不变 |
| TC-MONITOR-CARRIER-003 | 打开发送监控,检查移动、联通、电信、三网及未知运营商通道 | 已知运营商均显示中文;未知新增值保留后端原值,不显示空白,也不修改通道配置 |
| TC-REPORT-BATCH-008 | 打开待生成报备批次并切换两个页签 | 页签标题仅显示“待生成资料”和“已生成批次”,不含括号及数量;列表分页总数、筛选和真实API请求保持正常 |
| TC-SMS-RECORD-CHANNEL-003 | 打开短信记录通道下拉,输入通道名称或编码搜索并选择后查询、翻页和导出 | 下拉选项来自真实通道接口并支持搜索;查询和导出传递选中通道的精确`channelId`,结果、总数和CSV均只包含该通道记录;重置恢复全部通道 |
## 2026-08-09 CMPP客户连接请求诊断日志用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-CMPP-CONNECT-LOG-001 | 使用正确账号从允许IP发起CMPP 3.0连接,再查询系统与操作日志 | 认证成功;产生一条`cmpp_connection.connect_requested`,资源为`cmpp_downstream_connection`,日志`ipAddress`等于真实TCP来源IP,详情保存账号、AuthenticatorSource、时间戳、`cmpp30`、原始版本值、应用ID和authenticated结果 |
| TC-CMPP-CONNECT-LOG-002 | 从不同IP分别使用未知账号、错误AuthenticatorSource、未在白名单的IP或已停用应用发起连接 | 每次连接均按原认证规则拒绝,同时各自持久化失败日志;未知账号日志仍保存来源IP和请求账号,失败原因与真实拒绝原因一致,不因没有企业ID而丢失 |
| TC-CMPP-CONNECT-LOG-003 | 在系统与操作日志找到上述动作,核对IP列并点击“查看详情” | IP列有值;弹窗展示请求IP、Source_Addr、AuthenticatorSource、时间戳、协议版本、结果及失败原因。标准CMPP请求的密码字段明确显示“不传明文密码”,不得展示平台保存的密钥 |
| TC-CMPP-CONNECT-LOG-004 | 通过兼容Gateway调用显式携带`password`字段进行认证测试 | 日志详情原样保存并展示该请求字段;该兼容行为不改变标准CMPP只传AuthenticatorSource的协议事实,也不把平台配置密钥写入日志 |
## 2026-08-09 报表筛选结果全量汇总用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-REPORT-SUMMARY-001 | 在对账单准备超过一页的多日、多企业应用数据,分别按日期、企业和应用搜索并翻页 | 顶部提交、发送、未知、成功、失败合计等于PostgreSQL中全部筛选结果;翻页不改变汇总,改变筛选条件后同步刷新 |
| TC-REPORT-SUMMARY-002 | 在利润报表分别选择企业应用和通道维度,准备多行金额且至少一行收入为0 | 量类与金额类均按完整筛选结果求和;只展示收入、成本和利润金额合计,不展示返还合计;综合利润率=合计利润/合计收入,不是行利润率求和或平均,合计收入为0时为0% |
| TC-REPORT-SUMMARY-003 | 在发送质量报表的企业应用、通道、签名、引流信息四个Tab分别搜索和翻页 | 汇总条数来自真实后端全量聚合;综合成功率=合计成功/合计发送,不累加或平均各行成功率;汇总区不对平均到达时长求和 |
| TC-REPORT-SUMMARY-004 | 调用三个报表列表API,对比`items`当前页、`total`、`summary`和相同条件CSV | `summary`与CSV完整结果口径一致且不受`page/pageSize`影响;无匹配数据时所有合计和综合率均为0 |
## 2026-08-09 新建企业省市字典用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-ENTERPRISE-REGION-001 | 在`PhoneSegment`中准备多省多地市且含重复行,调用`GET /api/admin/dictionaries/administrative-regions` | API从真实PostgreSQL查询`province/city`,返回去重、去空值并按中文排序的省份—地市数组,不返回前端静态数据 |
| TC-ENTERPRISE-REGION-002 | 打开运营端新建企业,依次选择两个不同省份并查看地市下拉 | 省份选项来自真实字典API;地市只显示当前省的对应值,切换省份后旧地市立即清空;保存后省市真实写入企业档案 |
| TC-ENTERPRISE-REGION-003 | 编辑一个已存省市值暂未出现在当前号段字典的历史企业 | 页面将档案原值补入当前选项并正常显示,未主动修改时不会被清空 |
| TC-ENTERPRISE-REGION-004 | 断开字典API后打开新建企业 | 页面明确提示省市字典加载失败,不显示Mock、localStorage或旧的写死选项 |
## 2026-08-10 通道运营商多选验收用例(本地自动化与浏览器验收完成)
> 2026-08-09暂缓需求已重新纳入签名清退预警前置设计并完成本地兼容实现。以下仍是完整验收口径;自动化、真实本地数据库、构建和授权后的本地浏览器结果见本节末尾,未发送真实短信或向外部Webhook投递验收消息。
| 用例编号 | 操作 | 未来预期结果 |
| --- | --- | --- |
| TC-CHANNEL-CARRIER-MULTI-001 | 对包含`mobile/unicom/telecom/all`及已删除通道的生产数据副本执行兼容迁移 | 单运营商值分别迁移为单元素集合,`all`迁移为移动、联通、电信全选;记录数、通道ID、状态和历史关联不变,不根据名称或通道组使用情况推断并缩减能力 |
| TC-CHANNEL-CARRIER-MULTI-002 | 新建或编辑通道,分别勾选一个、两个、三个和零个运营商 | 一个、两个、三个非空组合均可真实保存并回填;零个被前后端拒绝;页面不再提供独立“三网”选项,三个全选等价于旧`all` |
| TC-CHANNEL-CARRIER-MULTI-003 | 将支持移动和联通但不支持电信的通道分别加入三类通道组并发送对应运营商短信 | 仅允许加入移动、联通通道组;电信组前后端均拒绝;发送链不会把电信短信选到该通道,通道组、路由规则和短信实际运营商仍为单值 |
| TC-CHANNEL-CARRIER-MULTI-004 | 取消通道已被活动通道组引用的运营商,再尝试保存 | 后端返回对应真实通道组及影响并阻止保存,不自动删除成员、路由、报备任务或历史数据;解除活动引用后才允许取消 |
| TC-CHANNEL-CARRIER-MULTI-005 | 多运营商通道参与移动、联通、电信发送及成本统计 | 三个运营商继续共用通道唯一单价,客户计费和平台成本不因多选被重复计算;本需求不产生分运营商价格 |
| TC-CHANNEL-CARRIER-MULTI-006 | 对旧单网、三网通道的签名任务执行自动转换,并检查报备记录和三网汇总 | 签名任务按“签名 × 通道 × 运营商”保存和汇总;旧单网任务生成一个运营商任务,旧三网任务生成三个;旧状态为已通过时全部适用运营商均为已通过且通过时间为migration执行时间,其他状态原样继承;旧任务保留并转为`legacy_split`,引流信息报备维度和页面不变 |
| TC-CHANNEL-CARRIER-MULTI-007 | 分阶段部署兼容底座后写入仅支持两个运营商的通道,再执行回滚演练 | 只能回滚到能够读取运营商集合的兼容版本;仅识别旧单值的代码不得重新上线并将双运营商数据误判为三网或单网 |
## 2026-08-10 运营商级签名报备验收用例(本地自动化与浏览器验收完成)
| 用例编号 | 操作 | 未来预期结果 |
| --- | --- | --- |
| TC-SIGNATURE-CARRIER-REPORT-001 | 为支持移动和联通的同一通道创建同一签名的报备任务 | 分别产生移动、联通两个独立任务;不产生电信任务;同一签名、通道、运营商不能重复创建当前任务 |
| TC-SIGNATURE-CARRIER-REPORT-002 | 分别修改三个运营商任务状态 | 只改变目标运营商状态并写对应任务记录;签名三网摘要按真实任务分别汇总,不由通道级状态复制 |
| TC-SIGNATURE-CARRIER-REPORT-003 | 任务首次通过、退出通过、再次通过 | `approvedAt`分别记录每次连续通过周期的开始时间;退出通过时旧时间不再作为当前监控起点,全部历史变化保留在记录表 |
| TC-SIGNATURE-CARRIER-REPORT-004 | 打开签名页、任务页和通道报备详情 | 三个入口展示并操作同一份运营商级任务;运营商、状态、当前通过时间、操作轨迹一致 |
| TC-SIGNATURE-CARRIER-REPORT-005 | 查看自动转换后的旧三网通道已通过任务 | 移动、联通、电信分别存在运营商级已通过任务,通过时间统一为migration执行时间;旧通道级任务保留为`legacy_split`且不再参与页面待办或发送兼容读取 |
| TC-SIGNATURE-CARRIER-REPORT-006 | 重复执行历史自动转换,且部分运营商级任务在转换前已经存在 | 重复执行不重复创建任务;已有运营商任务的状态、通过时间和操作轨迹均不覆盖,只补齐缺少的适用运营商,随后将旧任务转为`legacy_split` |
| TC-SIGNATURE-CARRIER-REPORT-006A | 打开签名清退预警页并检查前后端管理接口 | 页面不存在“历史待确认”页签、数量、表格和确认弹窗;后端不再暴露历史任务列表与确认接口,前端不再发起对应请求 |
| TC-SIGNATURE-CARRIER-REPORT-006B | 在企业签名页面将没有运营商级任务的目标保存为“已通过” | 创建真实运营商级任务,`approvedAt`取保存时刻;重复保存已通过状态保持当前连续通过时间,不要求额外填写历史时间 |
| TC-SIGNATURE-CARRIER-REPORT-007 | 兼容期发送一条目标运营商短信 | 优先使用运营商级通过任务;只有未拆分历史任务才走受控兼容资格并留下可统计命中记录 |
| TC-SIGNATURE-CARRIER-REPORT-008 | 历史未拆分数和兼容资格命中数不为0时尝试启用严格门禁 | 后端或发布门禁阻止切换;清零后才允许严格按“签名 × 通道 × 运营商”选路 |
| TC-SIGNATURE-CARRIER-REPORT-009 | 通道断连、提交超时、补发并切换通道 | 每次重新选路都校验目标运营商报备;不选择未报备通道,也不因其他运营商已通过而放行 |
| TC-SIGNATURE-CARRIER-REPORT-010 | 回归引流信息报备创建、状态修改、详情和历史 | 继续按“签名 × 引流信息 × 通道”工作,不出现运营商字段或新增运营商任务,历史数据不变 |
## 2026-08-10 签名清退预警验收用例(本地自动化与浏览器验收完成)
| 用例编号 | 操作 | 未来预期结果 |
| --- | --- | --- |
| TC-SIGNATURE-RETIREMENT-001 | 配置三网通用X/Y规则,并为一个企业应用或通道配置特殊规则 | 特殊规则优先于通用规则;保存规则版本,修改后的规则从下一检测日生效 |
| TC-SIGNATURE-RETIREMENT-002 | 同一签名只有移动运营商报备通过 | 只生成移动监控维度;联通、电信不进入名单,不要求三网全部通过 |
| TC-SIGNATURE-RETIREMENT-003 | 报备通过不足X个完整自然日后执行检测 | 不预警;达到X个北京时间完整自然日后才按`T-X`至`T-1`判断 |
| TC-SIGNATURE-RETIREMENT-004 | 同一业务短信在同一通道因断连或超时产生多次提交 | 提交尝试如实展示多次,通道清退活跃量按`messageRecordId + channelId`只计一次,企业活跃量也只计一次 |
| TC-SIGNATURE-RETIREMENT-005 | 同一业务短信从通道A补发到通道B | 企业活跃量只计一次;A、B各自通道活跃量分别计一次;最终成功仍按真实最终回执展示 |
| TC-SIGNATURE-RETIREMENT-006 | 同一检测维度连续多日低于阈值,随后恢复,再次低于阈值 | 连续低量属于同一预警周期并保存每日快照;恢复后关闭周期;再次低量创建新周期 |
| TC-SIGNATURE-RETIREMENT-007 | 重复执行同一检测日任务或两个实例并发执行 | 数据库唯一约束保证快照、周期、未读消息和Webhook均不重复 |
| TC-SIGNATURE-RETIREMENT-008 | 设置自定义临时抑制并跨越到期日 | 抑制期间继续生成检测快照但不产生未抑制提醒或Webhook;到期后的下一检测日自动恢复 |
| TC-SIGNATURE-RETIREMENT-009 | 设置永久抑制后从“抑制管理”取消 | 二次确认、原因和操作日志完整;下一检测日恢复,不补发被抑制期间的历史通知 |
| TC-SIGNATURE-RETIREMENT-010 | 检查右上角计数并将消息标记已读 | 数字只等于今日未读且未抑制数;已读、已抑制及历史日期消息不计入 |
| TC-SIGNATURE-RETIREMENT-011 | 配置多个企业微信和飞书Webhook并触发企业、通道预警 | 企业预警按企业汇总,通道预警按检测批次汇总;地址加密、脱敏,投递异步、幂等、有限重试并保留投递日志 |
| TC-SIGNATURE-RETIREMENT-012 | 配置非法协议、内网地址或不可达Webhook | 非安全目标被阻止;合法但不可达目标按上限重试并终结失败,不阻塞检测事务,也不伪造成功 |
| TC-SIGNATURE-RETIREMENT-013 | 切换页面日期并检查两类30日方格 | T随日期变化,展示`T-1`至`T-30`;企业按签名×运营商,通道按签名×通道×运营商,数据来自真实后端 |
| TC-SIGNATURE-RETIREMENT-014 | 查看尚未报备、报备前、零提交和非零成功率日期 | 尚未报备或报备前显示“不适用”,零提交显示灰色,其他数据按现有六档色阶,悬停数量和成功率与真实聚合一致 |
| TC-SIGNATURE-RETIREMENT-015 | 打开改版后的签名质量检测页面 | 企业应用排行、通道占比、当天发送量和当天成功率已删除,其余保留模块和真实查询不回归 |
| TC-SIGNATURE-RETIREMENT-016 | 检查顶部任务入口和预警入口 | 原待审核入口改为任务图标但计数、弹层和跳转完整;新增预警铃铛进入预警列表,两个计数互不混用 |
| TC-SIGNATURE-RETIREMENT-017 | 分别在北京时间04:00前后、08:00前后运行自动任务,并模拟服务跨过两个时点后重启 | 04:00只生成幂等检测快照且冻结规则版本和消息正文,不产生站内消息/Webhook;08:00才幂等创建站内消息并生成Webhook投递;晚启动按时点顺序补偿且不重复;页面和管理API均不存在手动检测入口 |
| TC-SIGNATURE-RETIREMENT-018 | 打开签名质量检测页,并分别翻动企业、通道热力图 | “签名通道发送质量”位于两张热力图之前;两张热力图各按10个维度分页,页码相互独立,翻页不改变另一张页码,30日列仍可横向滚动且数据与真实API一致 |
| TC-SIGNATURE-RETIREMENT-019 | 签名刚报备通过、尚未满足观察窗口,次日有真实发送数据并执行04:00检测 | 生成状态为“观察中”的单日检测快照,热力图展示真实受理条数,但不创建预警周期、站内消息或Webhook;满足观察窗口后才按窗口累计量判断预警 |
| TC-SIGNATURE-RETIREMENT-020 | 准备多个签名维度的T-1至T-30快照且合计不同,打开企业和通道热力图 | 每行展示30日受理短信合计,按合计降序排列;分页基于排序后的结果,单元格仍展示各自然日数据 |
| TC-UI-MONEY-001 | 遍历运营端和客户端包含余额、单价、消费、返还、充值、成本、收入和利润的页面 | 只读金额整数部分沿用主文字颜色,小数点及小数部分使用统一淡色;负号、币种符号和单位位置正确,输入框、复制值和CSV仍为完整纯文本数值 |
| TC-CLIENT-LOGIN-ANIMATION-001 | 打开客户端登录页并保持页面可见,再切换后台或启用减少动态效果 | Canvas动画在登录框背景平滑运行、不遮挡表单、不响应敏感输入;页面隐藏或组件卸载时停止帧循环,减少动态效果下显示静态背景 |
| TC-ENTERPRISE-SIGNATURE-STYLE-001 | 打开企业签名管理列表 | 企业名称和企业应用名称使用常规字重,签名名称及状态层级保持原样 |
| TC-SIGNATURE-CARRIER-REPORT-011 | 打开企业签名“报备状态”弹窗,并准备三网各有多个目标通道 | 移动、联通、电信按三列独立区域同时展示;通道不再铺成一条长列表;每个区域可独立滚动,状态保存仍提交真实“签名×通道×运营商”任务并共用修改原因 |
| TC-UI-CARRIER-TAG-001 | 检查通道、签名质量、清退预警和手机号段等运营商标签 | 移动为`#E8F1F7/#2F6F91/#C9DDE9`,联通为`#F6EAEA/#875758/#E8CECE`,电信为`#F0ECF7/#73538F/#DDD1EA`(背景/文字/边框);三者复用全局胶囊组件,业务状态标签不被误改 |
| TC-RECHARGE-RECEIPT-002 | 在1366×768桌面视口打开普通充值和冲正回执 | 本次金额区缩小,Logo、企业、明细、备注、说明和完成按钮无需滚动即可完整看到;异常长备注允许弹窗内容区滚动且真实文本不截断 |
| TC-CHANNEL-SORT-001 | 准备超过一页且今日提交量不同的通道并翻页 | 后端先按北京时间今日提交尝试数降序排列全部筛选结果,再分页;同量按通道名称、ID稳定排序,不出现仅当前页前端排序 |
| TC-CHANNEL-QUALITY-ZERO-001 | 查看今日提交数为0的通道 | 提交失败、送达成功、回执未知、送达失败四个比率均显示深灰色`-`且不带百分号;对应数量仍为0 |
| TC-CHANNEL-LAYOUT-001 | 查看短信通道列表 | 运营商低饱和胶囊位于通道信息列最底部横排;独立列标题为“成本费率”,费率固定4位小数且整数、小数同字号同色 |
| TC-UI-MONEY-002 | 检查运营端、客户端各金额页面及运营看板今日消费、企业应用单价 | 金额整数和小数同字号同色;末尾小数全为0时不显示,非零小数最多4位并移除末尾0;今日消费和应用单价恢复正常主数字深色样式;成本费率固定4位作为例外 |
| TC-SIGNATURE-RETIREMENT-019 | 检查两张热力图日期、行首和悬停信息 | 日期从左到右为`T-1`至`T-30`;行首不常驻企业和企业应用,悬停签名可看到企业、企业应用;通道维度仍能识别通道和运营商 |
| TC-SIGNATURE-RETIREMENT-020 | 分别在企业、通道热力图搜索企业、企业应用、签名并清空 | 每张热力图只过滤自身真实维度并回到第一页;三类关键字均可命中,清空恢复,另一张热力图的关键字和页码不变 |
| TC-SIGNATURE-RETIREMENT-021 | 悬停报备前、无快照、零量和非零量格子 | 报备前显示不适用;无快照说明当日无检测;真实快照明确显示提交条数、上游接受条数、发送成功条数和成功率,发送成功等于真实最终送达而非受理成功 |
| TC-SIGNATURE-RETIREMENT-022 | 所选日期构造正文以规范`【签名】`开头的短信:当前企业应用签名库存在同名记录、签名库不存在、仅其他企业应用存在同名记录、正文没有规范开头签名 | 只有当前企业应用签名库不存在的规范正文签名进入未报备模块;已有同名系统签名不受通道或运营商报备状态影响,其他应用同名签名不能替代当前应用记录,无规范签名正文不伪造成签名行 |
| TC-SIGNATURE-RETIREMENT-023 | 在未报备签名模块按企业、企业应用、签名搜索并翻页 | 后端搜索、总数、每页10行和分页结果一致;列表展示签名、企业、实际企业应用和未报备短信条数,修改主统计日期后按新的北京时间自然日重新查询 |
| TC-SIGNATURE-RETIREMENT-028 | 同一企业应用在所选北京时间自然日提交正文以`【湘银物业】`开头的短信,消息未关联`signatureId`且有效签名库无同名记录;另准备已有签名但缺少通道报备、其他应用同名签名、正文无规范开头签名三组对照数据 | 仅正文签名在当前企业应用签名库不存在的消息进入“未报备签名”,并按正文签名和实际企业应用聚合;已有系统签名但缺通道/运营商报备、其他应用的记录和无规范签名正文不得误判 |
| TC-SIGNATURE-RETIREMENT-029 | 生产量级数据中存在多个企业、应用和未登记正文签名,打开签名质量检测页并查询未报备签名 | PostgreSQL按企业、应用、正文签名完整分组,接口返回200;不发生`42803`分组错误,列表总数、分页和各组短信条数与独立SQL一致 |
| TC-SIGNATURE-RETIREMENT-024 | 首次打开预警页面,随后选择历史日期区间 | 页签和区块标题均为“预警消息”;默认开始、结束均为今日且只返回今日消息,历史区间返回对应历史消息,每页10条并显示真实总数 |
| TC-SIGNATURE-RETIREMENT-025 | 分别或组合选择企业、企业应用、签名关键字、通道及日期区间并翻页 | 后端同时应用全部条件,列表、总数和页码一致;条件变化查询后回到第1页,企业应用选项受企业筛选约束 |
| TC-SIGNATURE-RETIREMENT-026 | 点击消息“抑制”,分别选择临时截止日期和永久抑制并填写原因 | 只出现平台自研弹窗;临时模式要求未来截止日期,永久模式不显示日期,两种模式原因必填,保存调用真实抑制接口且刷新当前筛选页 |
| TC-SIGNATURE-RETIREMENT-027 | 在抑制管理点击“取消抑制”,填写或不填写原因 | 只出现平台自研弹窗;未填原因不能确认,填写后调用真实取消接口并刷新消息及抑制列表,不出现浏览器`prompt/confirm` |
| TC-REPORT-RECORD-LAYOUT-001 | 在报备记录页面查看长备注和短备注 | 备注列桌面宽度不小于320px,使用统一长文本换行样式;宽表允许内部横向滚动,备注不被其他固定列挤成窄竖列,详情仍展示全文 |
| TC-DEPLOY-HEALTH-001 | 发布重启后模拟API初始化超过3秒但在60秒内恢复,并分别模拟API或Gateway持续60秒不可用 | 前者由部署脚本逐秒重试并正常完成,不触发误回滚;后者在60秒后明确失败并保留发布前数据库、源码和环境恢复资产,不把端口尚未就绪当作构建或migration失败 |
| TC-DEPLOY-NGINX-001 | 分别在Ubuntu默认`nginx.conf`已有全局`gzip on`和完全没有gzip配置的环境执行两次标准发布 | 已有配置时平台生成文件保持为空并复用发行版配置;缺失时写入平台配置;两种环境连续执行两次`nginx -t`均通过且不存在重复gzip指令 |
### 2026-08-10 本地执行状态
- 已通过真实本地PostgreSQL迁移和数据约束检查、Prisma校验及85条迁移状态、API全量35个suite/448项测试、专项服务52项测试、API TypeScript构建、前端生产构建、4份Gateway队列结构契约和`git diff --check`;自动转换SQL已对真实本地数据库执行并重复执行验证幂等,不使用Mock、静态数据或localStorage。
- 通道能力集合、通道组兼容、运营商级报备、历史任务自动转换、发送资格兼容双读、每日检测幂等、规则版本、预警周期、抑制和Webhook安全边界已有自动化或数据库证据;严格运营商级发送门禁默认不启用,必须在兼容命中清零后另行切换。
- 未向外部Webhook投递验收消息,未发送、补发或重投真实短信。经用户授权使用本地专用平台管理员验收:预警页面只保留“预警消息、检测规则、Webhook、抑制管理”4个页签,不存在“历史待确认”页签和残留提示;切换检测规则页签成功,控制台error/warn为0。页面继续显示04:00自动检测、08:00发消息口径且不存在手动检测按钮。
## 2026-08-09 通道组按通道筛选用例
| 用例编号 | 操作 | 预期结果 |
| --- | --- | --- |
| TC-CHANNEL-GROUP-FILTER-001 | 打开通道组管理页并展开“通道”下拉 | 通道组和通道真实API并行加载;下拉显示全部真实通道的名称和编码,已删除通道标记“已删除”,未加入任何组的通道也不被隐藏 |
| TC-CHANNEL-GROUP-FILTER-002 | 在通道下拉中输入完整或部分通道名称、编码 | 下拉只显示标签包含关键字的真实通道选项;无匹配时显示“无匹配选项” |
| TC-CHANNEL-GROUP-FILTER-003 | 选择某通道 | 只展示`items.channelId`包含该通道的通道组,不展示仅运营商相同但未配置该通道的组;总数和分页与筛选结果一致 |
| TC-CHANNEL-GROUP-FILTER-004 | 同时输入通道组名称并选择通道 | 按名称包含与成员通道两个条件取交集,条件变更后回到第一页 |
| TC-CHANNEL-GROUP-FILTER-005 | 点击“重置” | 通道组名称和通道条件同时清空,恢复全部未删除通道组并回到第一页 |
# 下游投递后台重投任务专项用例(2026-08-12)
| 编号 | 场景 | 预期 |
|---|---|---|
| TC-DOWNSTREAM-REQUEUE-TASK-001 | 当前筛选条件预检 | 后端按企业、应用、类型、状态、日期、关键词和 `snapshotAt` 返回真实命中、可重投、跳过及状态分布;分页不影响数量。 |
| TC-DOWNSTREAM-REQUEUE-TASK-002 | 创建任务 | 原因少于 5 字拒绝;物化 `pending/failed/unconfirmed/rejected/delivered`;客户端已确认记录在预检中计为可重投并保留 `previousStatus=delivered``awaiting_ack` 不进入执行。 |
| TC-DOWNSTREAM-REQUEUE-TASK-003 | 快照边界 | 创建任务后新增或筛选条件外记录不进入任务。 |
| TC-DOWNSTREAM-REQUEUE-TASK-004 | 并发与幂等 | `taskId+deliveryId` 唯一;重复扫描、API 重启及并发任务不会重复调用 Gateway。 |
| TC-DOWNSTREAM-REQUEUE-TASK-005 | ACK 闭环 | Gateway 写出后项目进入等待 ACK;`Result=0` 成功,拒绝/超时计失败并按阈值自动暂停。 |
| TC-DOWNSTREAM-REQUEUE-TASK-006 | 状态变化跳过 | 创建任务时不是 `delivered`、执行前才收到成功 ACK 的记录,或已被其他操作认领时不调用 Gateway,记录明确跳过原因;快照原状态就是 `delivered` 的记录允许调用 Gateway。 |
| TC-DOWNSTREAM-REQUEUE-TASK-007 | 任务控制 | 待执行/执行中任务可暂停、继续、终止;终止不撤回已写出消息。 |
| TC-DOWNSTREAM-REQUEUE-TASK-008 | 审计 | 创建、暂停、继续、终止和自动暂停记录操作人、筛选快照、原因和结果。 |
| TC-DOWNSTREAM-PAGE-SIZE-001 | 分页数量 | 可选 10/25/50;切换回第一页,后端返回对应条数,总数和筛选条件保持一致。 |
## 下游投递后台重投任务安全整改专项用例(2026-08-13)
| 编号 | 场景 | 预期 |
|---|---|---|
| TC-DOWNSTREAM-REQUEUE-TASK-009 | 单一状态严格预检 | 选择待投递后,命中数、状态分布和可重投数只基于 `pending`;企业、应用、类型、日期、关键词同时生效。 |
| TC-DOWNSTREAM-REQUEUE-TASK-010 | 预检签名绑定 | 篡改筛选、快照、操作人、签名或使用过期凭证均拒绝;合法凭证由后端按原快照物化任务项。 |
| TC-DOWNSTREAM-REQUEUE-TASK-011 | processing 租约恢复 | API 在认领后中断,租约过期后项目回到队列并重新复核;已成功项不重复调用 Gateway。 |
| TC-DOWNSTREAM-REQUEUE-TASK-012 | 每应用原子限速 | 多任务、多实例和重叠扫描同时执行时,每个应用每秒消耗不超过配置值;不同应用互不阻塞。 |
| TC-DOWNSTREAM-REQUEUE-TASK-013 | 离线等待与恢复 | 客户无 connected 连接时进入等待连接,不增加失败/跳过;连接恢复后回队列继续。 |
| TC-DOWNSTREAM-REQUEUE-TASK-014 | ACK 阈值与清零 | 写出进入等待 ACK 不清零;ACK 超时/拒绝按应用累加,达到阈值自动暂停并审计;有效 ACK 才清零。 |
| TC-DOWNSTREAM-REQUEUE-TASK-015 | 列表完整分页 | 任务列表支持状态和分页,第 11 条以后可访问,中文状态、创建人、原因、进度和各结果数准确。 |
| TC-DOWNSTREAM-REQUEUE-TASK-016 | 完整任务项查询 | 任务项支持分页、结果及关键词查询,等待连接/外部 ACK/本任务 ACK、跳过、失败和未处理均中文展示并保留原因。 |
| TC-DOWNSTREAM-REQUEUE-TASK-017 | 终止并发边界 | 终止后未认领和等待连接项置为未处理;处理中或已写出项不撤回;执行器不再认领新项。 |
| TC-DOWNSTREAM-REQUEUE-TASK-018 | 已确认记录批量重投 | 以状态 `delivered` 预检并创建任务,核对任务项原状态后执行;页面显示重复投递风险,真实任务项进入等待 ACK/成功闭环;同一任务已成功项不重复调用 Gateway。 |
| TC-DOWNSTREAM-REQUEUE-TASK-019 | 创建弹窗与列表留白 | 桌面及窄屏打开创建弹窗和后台任务列表,输入不足5字及合法原因 | 原因使用统一多行输入组件,必填、错误、说明、字数和焦点态清晰;任务列表与卡片边缘保持设计间距,行内容不贴边、不裁切,移动端留白同步收敛。 |
# 2026-08-13 HTTP 与 Gateway 报文容量专项用例
| 用例编号 | 优先级 | 验证内容 | 预期结果 |
| --- | --- | --- | --- |
| TC-TRANSPORT-SIZE-001 | P0 | 模拟 NestJS 返回约128KiB的合法待投递回执JSON,由Gateway通用API传输方法读取并反序列化 | 响应完整解析,字段长度与服务端输出一致,不出现64KiB截断或JSON语法错误 |
| TC-TRANSPORT-SIZE-002 | P0 | 模拟NestJS返回超过4MiB的响应 | Gateway停止读取并返回`api response exceeds 4194304-byte limit`容量错误,不返回`unexpected end of JSON input`,不把不完整数据当作成功结果 |
| TC-HTTP-BODY-001 | P0 | 分别向普通JSON接口和`/api/client/send/imports/preview`提交约3MiB合法JSON | 普通接口在Controller前返回413;导入接口成功解析且保留rawBody,证明25MiB解析器只对导入路由生效 |
| TC-HTTP-BODY-002 | P1 | 分别测试普通JSON 2MiB边界、导入JSON 25MiB边界及业务层原始正文20MiB边界 | 边界内请求正常进入业务校验;超过解析器边界返回413;超过20MiB原始导入正文返回明确业务错误且不创建发送任务 |
| TC-NGINX-BODY-001 | P1 | 检查预生产有效Nginx配置及域名路由 | `sms.lisglo.com`请求体上限不低于30MiB并承载私有导入接口;`api.lisglo.com`不暴露私有导入路由且其现有上限不影响单条公网HTTP API |
# 2026-08-13 运营端信息密度与运营商标签统一专项用例
| 编号 | 场景 | 步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-BILLING-RECEIPT-OPERATOR-001 | 人工充值回执展示操作人员姓名 | 使用有`operatorId`的真实人工充值记录查询充值列表并打开回执 | API按用户表返回`operatorName`,回执显示姓名而非用户ID;无操作人的历史记录显示“系统”,关联用户确已不存在时显示“未知操作人员” |
| TC-DASHBOARD-SIGNATURE-REMOVE-001 | 删除看板签名统计模块并统一金额样式 | 打开运营看板,检查指标卡与后续模块 | 两个“今日签名发送统计”模块均不存在;今日消费金额与今日发送总量主数字字号、字重和颜色一致;今日活跃签名仍来自真实接口 |
| TC-ENTERPRISE-APP-WIDTH-001 | 企业应用关键列缩窄 | 在桌面大屏打开企业应用管理并读取表头列宽 | 状态、到达率、单价列宽均约为原宽度80%,字段与操作均未隐藏,横向滚动需求减少 |
| TC-UI-CARRIER-TAG-002 | 全局运营商数据展示复用通用标签 | 抽查通道/通道组、监控、报备、企业签名、短信审核、批次号码、发送记录和客户端发送详情 | 移动、联通、电信均使用全局低饱和胶囊及统一色值;有运营商集合的三网通道显示三个标签,历史通道级字段显示中性“三网”;筛选选项、图表图例与导出文本保持纯文本 |
## Prometheus 系统监控专项用例(2026-08-14
| 用例编号 | 场景 | 操作 | 预期结果 |
|---|---|---|---|
| TC-INFRA-MON-001 | 运营端权限与原生页面 | 登录运营端,打开“系统管理 → 系统监控”,检查页面和浏览器网络请求 | 页面使用平台导航、组件和样式;只请求平台`/api/admin/infrastructure-monitoring/overview`,不加载iframe,不从浏览器访问9090/9100,不出现第三方Logo或登录页 |
| TC-INFRA-MON-002 | 未登录访问 | 清除运营端Session后直接访问系统监控API和页面 | API按现有Session中间件拒绝,页面进入运营端登录流程;Prometheus数据不得绕过运营端权限公开 |
| TC-INFRA-MON-003 | 当前硬件指标真实值 | 在同一采样窗口分别请求平台监控API和Prometheus固定查询 | CPU、内存、根文件系统、网络、负载、运行时长与Prometheus结果在采样误差内一致,响应不包含Prometheus地址或PromQL |
| TC-INFRA-MON-004 | 指标缺失 | 临时禁用某个Node Exporter采集器或查询一个不存在的指标后请求页面 | 对应指标为`null`并显示“暂无真实指标”,其他指标继续展示;不得显示0或生成趋势线 |
| TC-INFRA-MON-005 | Prometheus不可用 | 停止本地测试Prometheus或将测试环境指向拒绝连接端口,请求监控API | API返回`available=false`和安全错误摘要,页面显示“监控数据不可用”并清空陈旧指标,不显示Mock或上次数据 |
| TC-INFRA-MON-006 | 查询超时 | 让测试Prometheus响应超过5秒 | 请求被AbortSignal终止,接口有限时间返回不可用状态;API进程不积累悬挂请求 |
| TC-INFRA-MON-007 | 时间范围白名单 | 分别请求`1h`、`24h`、`7d`、`30d`和注入PromQL字符串 | 前三种成功且step分别为60/300/1800秒;非法值返回400,不能进入Prometheus查询 |
| TC-INFRA-MON-008 | 趋势切换 | 页面依次选择近1小时、近24小时、近7天 | 每次只发一个新范围请求;图表时间轴、点数和当前范围同步更新,切换期间防止重复触发 |
| TC-INFRA-MON-009 | 自动与手动刷新 | 保持页面可见超过30秒,再隐藏页面并点击手动刷新 | 可见时按30秒刷新;隐藏后停止;重新可见后立即刷新;手动刷新保留范围且不会并发重复请求 |
| TC-INFRA-MON-010 | 核心服务状态 | 核对`cmpp-api`、`cmpp-gateway`、PostgreSQL、Redis、MinIO、Nginx的systemd状态与页面 | active显示正常,明确0显示异常,指标不存在显示未知;Redis兼容`redis.service`与`redis-server.service`别名 |
| TC-INFRA-MON-011 | 活动告警 | 触发一条warning和一条critical测试规则并等待Prometheus进入firing | 页面显示真实名称、严重性、开始时间、持续时间、当前值和阈值;概览计数准确,恢复后活动列表移除 |
| TC-INFRA-MON-012 | 综合状态 | 分别构造无告警、warning、critical和Prometheus不可用状态 | 综合状态依次为正常、警告、严重、未知;critical优先于warning,不按前端瞬时指标重复计算 |
| TC-INFRA-MON-013 | 并行查询与响应上限 | 检查后端请求时序,并用7天范围请求最大趋势 | 瞬时、趋势、服务、告警查询并行;每序列约不超过340点,响应不包含原始Prometheus响应体 |
| TC-INFRA-MON-014 | 监听与公网暴露 | 在服务器执行`ss -lnt`并从外部探测9090、9100 | Prometheus和Node Exporter仅监听127.0.0.1或明确内网地址;公网9090/9100不可连接,运营端仍能经平台API读取指标 |
| TC-INFRA-MON-015 | 响应式与无障碍 | 在1536×1024、1280×800和390×844打开页面,操作范围和刷新按钮 | 桌面信息层级符合设计稿;窄屏无内容重叠和页面横向溢出;按钮有可读名称,活动范围和告警严重性不只依赖颜色表达 |
| TC-INFRA-MON-016 | 配置和部署幂等 | 在测试服务器重复执行监控安装脚本和配置校验 | 不重复创建系统用户,不开放公网端口;配置通过`promtool check config/rules`,服务保持activeCMPP API/Gateway不因安装被重启 |
| TC-INFRA-MON-017 | 业务数据隔离 | 运行监控24小时并检查PostgreSQL业务库和指标标签 | 监控时序只保存在Prometheus TSDB,业务PostgreSQL无高频指标写入;标签、日志和API响应不含手机号、短信正文、账号或密钥 |
| TC-INFRA-MON-018 | systemd PromQL转义兼容 | 使用真实Prometheus执行API生成的服务状态查询,并检查自动化请求参数 | 查询文本向Prometheus传递双反斜杠转义的`\\.`正则,API返回`available=true`及真实服务状态;不得因`unknown escape sequence`把整页降级 |
| TC-INFRA-MON-019 | 页面标题去重 | 打开系统监控页并检查平台页头和内容区 | 平台通用页头保留“系统监控”,内容区不再出现重复大号标题;说明、状态、范围和刷新操作完整可用 |
| TC-INFRA-MON-020 | API内部指标 | 回环请求API metrics,再发起成功与失败的固定路由请求 | 请求量、状态码、延迟桶、堆内存和事件循环指标变化;route为路由模板,不含实体ID或查询串 |
| TC-INFRA-MON-021 | Gateway内部指标 | 请求`127.0.0.1:8090/metrics`,交叉核对连接池和Redis Stream | 上下游连接、Submit计数/耗时、worker up、pending、lag和最旧pending年龄与真实状态一致 |
| TC-INFRA-MON-022 | 服务Exporter目标 | 安装PostgreSQL、Redis、Nginx Exporter并开启MinIO原生指标 | Prometheus六个新服务target均up;数据库、Redis、MinIO、Nginx指标与各服务本地命令在采样误差内一致 |
| TC-INFRA-MON-023 | Exporter端口隔离 | 执行`ss -lnt`并从LAN/公网探测9464、9187、9121、9113、9090、9100 | 全部只监听127.0.0.1或::1Nginx业务站点不代理metrics端点 |
| TC-INFRA-MON-024 | 阈值持续窗口 | 在隔离节点分别制造瞬时和持续的CPU/API错误/队列延迟 | 瞬时尖峰不告警;达到阈值与`for`窗口后进入pending/firing,恢复后移除 |
| TC-INFRA-MON-025 | 低流量错误率保护 | 5分钟内只产生1次API请求且返回500 | 因未达至5次错误的最低样本量,不产生5xx比例告警 |
| TC-INFRA-MON-026 | 高基数和敏感字段防护 | 检查API/Gateway/Exporter全量metrics文本及Prometheus label names/values | 不存在手机号、短信正文、message/submit/task/channel实体ID、凭据、原始URL或SQL文本 |
| TC-INFRA-MON-027 | Recording Rules查询收敛 | 刷新系统监控页并检查Prometheus请求 | 服务卡片只读取`cmpp:service_*`固定聚合,不按卡片开放任意PromQL;缺失指标显示“待采集” |
| TC-INFRA-MON-028 | 监控开销对比 | 在同等请求压力下对比开启前后API/Gateway CPU、RSS、P95和吞吐 | 无高基数增长、无业务PostgreSQL高频写入;开销超出预算时暂停发布并调整采集/桶配置 |
| TC-CMPP-PERF-OBS-001 | API入站分段耗时 | 在隔离测试环境提交覆盖成功、同步拒绝、长短信分片和异常的CMPP Submit,抓取API回环metrics | 输出固定`cmpp_api_cmpp_inbound_stage_duration_seconds`直方图;查询、分片、预检、模板、各持久化、检测、风控频次、计费、入队、完整提交及总耗时按实际路径增长,结果仅为`success/error` |
| TC-CMPP-PERF-OBS-002 | Gateway入站分段耗时 | 在隔离测试环境发送合法与非法Submit并抓取Gateway回环metrics | `decode/api_roundtrip/response_write/handler_total`分别增长;失败路径也记录对应阶段,不因指标异常吞掉原协议错误 |
| TC-CMPP-PERF-OBS-003 | Gateway供应商下发分段耗时 | 在隔离测试环境构造Stream等待、限速等待、连接窗口等待、供应商慢响应和API慢回调 | `stream_wait/rate_limit_wait/connection_wait/supplier_rtt/api_callback`可独立区分;`supplier_rtt`在API回调变慢时不等量增长 |
| TC-CMPP-PERF-OBS-004 | 观测标签边界 | 检查API/Gateway新增指标文本和Prometheus时序标签 | 只出现固定`stage/result/le`;不得出现手机号、企业/应用/通道/连接/消息/Submit/任务ID、短信正文或凭据,未知阶段不生成时序 |
| TC-CMPP-PERF-OBS-005 | 纯观测语义回归 | 对比启用埋点前后的同一组CMPP Submit结果、数据库记录、扣费冻结、队列命令及回执 | SubmitResp状态、Msg_Id、多号码独立记录、同步拒绝、异步回执、幂等键和业务调用顺序均不改变;埋点不写PostgreSQL/Redis |
| TC-CMPP-PERF-OBS-006 | 发送Worker分段耗时 | 在隔离测试环境完成正价短信发送并抓取Worker回环metrics | 11个固定阶段按实际路径增长,结果仅为`success/error/skipped`;各阶段count与Worker结果可对账,直方图不含业务实体标签 |
| TC-CMPP-PERF-OBS-007 | BullMQ与Worker槽位 | 在空闲、入压、排空三个时点抓取Worker metrics并交叉核对BullMQ | waiting/active/completed/failed/delayed/prioritized、configured/in_flight和completed/failed/skipped均为真实值,排空后waiting/active归零 |
| TC-CMPP-PERF-OBS-008 | Worker数据库连接池等待 | 让发送并发超过Worker数据库池,在压测窗口逐秒抓取metrics | `cmpp_worker_database_pool_connections{state=max|total|idle|waiting}`反映客户端池;waiting峰值可被采到,结束后归零,不通过提高连接上限掩盖等待 |
| TC-CMPP-PERF-OBS-009 | PostgreSQL归一化热SQL | 测试环境启用并重置`pg_stat_statements`后执行正价六通道压力,再按total执行时间排序 | 可得到归一化SQL的calls/total/mean/rows且不含实参;开放会话累计、账户锁、提交记录和状态写入可分别归因 |
| TC-CMPP-PERF-OBS-010 | 正价六通道诊断档 | 快照后设置0.0325元单价、三运营商规则和六通道主动双活,执行smoke及100条/秒30秒并监控至排空 | 入口、三运营商、六账号、供应商首次提交、计费、Stream、数据库和恢复配置均可对账;未达到完整100条/秒时停止升档,不以SubmitResp冒充全链吞吐 |
| TC-CMPP-PERF-V2-001 | 持续补位无批次屏障 | 工作池并发设为2,先投递一个阻塞任务和一个快速任务,再投递第三个任务 | 快速任务结束后第三个任务立即开始,不等待第一个慢任务结束;读取批次不形成整批`Wait`屏障 |
| TC-CMPP-PERF-V2-002 | 单消息独立ACK | 同一批次投递一快一慢两条消息,慢任务保持在供应商等待 | 快任务完成后Redis PEL立即只剩慢任务;不得等慢任务结束后整批ACK,也不得在供应商结果回传前提前ACK |
| TC-CMPP-PERF-V2-003 | 全局并发边界 | 分别配置并发1、64、1024和大于1024的值,持续投递超过槽位数的消息 | 同时处理数不超过有效配置;缺省为64,大于1024按1024执行,空闲槽位持续补充 |
| TC-CMPP-PERF-V2-004 | Pending恢复去重 | 让一个供应商调用超过`MinIdle`,同时触发`XAUTOCLAIM`扫描 | 同一进程检测到相同Stream消息ID仍在处理时不重复Submit;原任务结束后按自身结果ACK或进入既有失败/死信流程 |
| TC-CMPP-PERF-V2-005 | Worker槽位指标 | 工作池空闲、部分占用和满载时抓取Gateway metrics | `cmpp_gateway_submit_worker_slots`的`configured/in_flight`与真实配置和在途数一致,不包含通道、消息或客户标识 |
| TC-CMPP-PERF-V2-006 | 失败、死信和重启兼容 | 构造提交失败至最大次数、畸形命令、进程重启后的pending恢复 | 失败次数、死信上报、独立ACK和failure hash清理保持既有语义;重启不丢消息、不把未完成消息误报成功 |
| TC-CMPP-PERF-V2-007 | 隔离环境阶梯持续压测 | 在供应商模拟器、真实API/PostgreSQL/Redis/Gateway链路中,先做100条受控突发,再依次执行10、20、30、40、50条/秒各60秒;每档等待Stream排空并核对数据库、模拟器和Prometheus | 每档SubmitResp拒绝和连接错误为0Stream最终`pending=0/lag=0`,无死信或服务异常;任一档SubmitResp P95超过5秒、Stream持续增长或服务异常时立即停止升档并保留该档证据,不把未执行档位记为通过 |
| TC-CMPP-PERF-V3-001 | 同连接窗口内并发 | 应用窗口设为2,让第1个Submit的API处理阻塞,再发送第2个Submit | 第2个请求无需等待第1个完成即可进入API并按自身Sequence_Id先返回SubmitResp;释放第1个后仍返回其原Sequence_Id |
| TC-CMPP-PERF-V3-002 | 应用窗口与全局上限 | 分别设置应用窗口1、32、2048及Gateway全局上限16、64 | 窗口1保持串行;有效并发为`min(应用窗口, Gateway上限, 1024)`,超过窗口时停止继续读取形成背压,不产生无界协程 |
| TC-CMPP-PERF-V3-003 | 非Submit协议活性 | 在多个慢Submit在途时发送ActiveTest并接收Deliver ACK | 心跳和ACK仍可被读取和处理,不因业务Submit串行处理而超时;登录必须在任何并发Submit前串行完成 |
| TC-CMPP-PERF-V3-004 | 断线在途清理 | Submit进入API后由客户端断开TCP,随后让API处理完成 | Gateway等待已接受处理收尾后再执行连接关闭回调;会话、Submit barrier和消息映射最终清理,不重新出现幽灵连接,不发生panic |
| TC-CMPP-PERF-V3-005 | 入站槽位聚合指标 | 建立不同窗口的测试连接并制造部分在途Submit后抓取metrics | `cmpp_gateway_inbound_submit_slots`的configured等于在线连接有效窗口合计、in_flight等于当前业务处理数;只有固定state标签 |
| TC-CMPP-PERF-V3-006 | V3阶梯容量复测 | 在与V2相同的隔离真实后端/数据库/Redis/供应商模拟器中执行10、20、30、40、50条/秒各60秒 | 与V2按同口径比较SubmitResp P50/P95/P99、API阶段、Stream pending/lag、供应商吞吐和资源;遇P95超过5秒、持续积压或服务异常立即停止,未执行档位不记为通过 |
| TC-CMPP-PERF-V4-001 | 分片结果幂等入Outbox | 对同一submitId和segmentIndex重复发布两次分片结果 | `gateway.submit.results`只新增一个确定性eventId事件;下一分片仅在前一分片Outbox写入成功后发送 |
| TC-CMPP-PERF-V4-002 | 聚合结果与命令ACK原子性 | 让供应商返回成功,在聚合结果写入与命令ACK边界注入Redis失败并重启Gateway | 不存在“命令已ACK但结果Outbox缺失”状态;重试同一发布脚本不会产生重复聚合事件 |
| TC-CMPP-PERF-V4-003 | API回调不占供应商槽 | API submit-result接口延迟10秒,同时持续让供应商快速返回SubmitResp | 供应商Worker槽在结果写入Outbox后立即释放;API延迟只增加独立回调Worker和Outbox积压,不降低供应商Submit槽可继续补位的能力 |
| TC-CMPP-PERF-V4-004 | 回调失败恢复与逐条ACK | 结果回调第一次返回503,随后恢复201并重启回调Worker | 失败事件保留PEL且未删除;恢复后重新投递,成功时单事件原子ACK+删除,其他事件不受整批等待 |
| TC-CMPP-PERF-V4-005 | API持久幂等 | 对同一聚合eventId重复回调两次,并检查提交记录、计费、余额、重试和任务进度 | `SmsSubmitRecord.resultEventId`只记录一次;第二次直接返回当前结果,不重复扣费、释放、补发或推进状态;不同eventId占用同一submit尝试时拒绝 |
| TC-CMPP-PERF-V4-006 | Outbox有界指标 | 制造回调在途和积压后抓取Gateway metrics | 回调Worker configured/in_flight与真实槽位一致,Outbox pending/lag与Redis consumer group一致,指标不含手机号、消息、submit、企业、应用或通道标签 |
| TC-CMPP-PERF-V4-007 | 双Stream发布后排空 | 完成一档隔离压测并等待异步处理结束 | `gateway.submit.commands`和`gateway.submit.results`均为`pending=0/lag=0`,结果Outbox成功事件已删除,无Gateway Submit死信;数据库业务数与客户端完全一致 |
| TC-CMPP-PERF-V4-008 | V4阶梯容量复测 | 在V3相同隔离供应商模拟器与真实API/PostgreSQL/Redis/Gateway中依次执行10、20、30、40、50条/秒各60秒 | 对比V3的SubmitResp分位、供应商RTT、命令Stream、结果Outbox、API阶段和资源;任一档出现拒绝、连接错误、P95超过5秒、双Stream持续增长或服务异常立即停止升档 |
| TC-CMPP-PERF-V5-001 | 入站应用快照复用 | 分别提交单号码、多号码和完整长短信,并统计`SmsApplication`查询 | 每次Submit入口只查询一次账号对应应用、企业和IP白名单;全部目标号码复用该已校验快照,应用/IP/模板/风控业务结果不变 |
| TC-CMPP-PERF-V5-002 | 默认规则完整性检查单飞 | 同一API实例并发触发任务风控和号码频控,再在30秒内重复提交 | 并发调用共用一个检查Promise;默认5条规则完整时只执行一次聚合count,不再逐消息产生两轮各5次存在性查询;实际生效规则和频控状态仍逐消息读取 |
| TC-CMPP-PERF-V5-003 | 默认规则缓存失效与恢复 | 让聚合检查失败后重试;另在缓存期后模拟缺失一条默认规则 | 检查失败立即清除缓存并允许下次重试;短TTL内只缓存完整性,TTL后发现缺失规则并按既有创建校验恢复,不缓存应用规则内容或业务判断 |
| TC-CMPP-PERF-V5-004 | 已持久化单消息快速入队 | 创建CMPP单号码内部任务和消息,记录已知taskId、messageRecordId、queuePriority后进入队列 | BullMQ jobId仍为messageRecordId、attempts和优先级不变;不再回查刚创建的任务和消息,任务最终更新为queued;普通批量任务原通用入队路径保持兼容 |
| TC-CMPP-PERF-V5-005 | V5隔离环境阶梯复测 | 发布到虚拟机测试环境后,以V4相同模拟器、连接数、8槽Outbox和10/20/30/40/50条每秒阶梯执行 | 对比V4的SubmitResp分位及`application_lookup/risk_frequency/queue_publish/complete_submit`阶段;数据库业务数、冻结/计费、双Stream排空和回执幂等保持一致,遇拒绝、连接错误、P95超过5秒或持续积压立即停止 |
执行记录(2026-08-20):`TC-CMPP-PERF-V5-001`至`004`通过本地API全量回归;`005`在`100.93.204.60`隔离测试环境完成。10/20/30/40条每秒均零拒绝、零连接错误且双Stream排空,判定通过;50条每秒缺8个SubmitResp且结束时命令Stream仍有`pending=64/lag=1407`,判定失败并停止升压。30与40条每秒真实积压下,优先任务排队P95分别为0.988秒、3.916秒,普通任务为26.282秒、58.536秒,优先级隔离通过;该结论仅覆盖移动号段,联通/电信六通道仍待P1复测。
| TC-GLOBAL-ALERT-001 | 铃铛分域预警菜单 | 准备签名清退未读消息和安全待处置告警后点击右上角铃铛 | 弹层分开显示“签名清退预警”和“安全检测与封禁”,分别展示真实数量和摘要,角标等于两项之和 |
| TC-GLOBAL-ALERT-002 | 预警菜单跳转 | 分别点击铃铛中的两个菜单项 | 签名项跳转`/admin/signature-retirement`,安全项跳转`/admin/security-detection`,弹层关闭且对应页面读取真实后端数据 |
| TC-GLOBAL-ALERT-003 | 域间故障隔离与轻量轮询 | 分别让一个汇总接口失败并观察30秒轮询请求 | 失败域显示0且另一域数据保留;安全预警使用专用汇总接口,不调用完整overview、规则、代理状态或告警大列表 |
| TC-DEPLOY-NET-001 | API回环监听边界 | 使用标准生产环境启动API,执行`ss -lnt`并从LAN/Tailscale探测3000端口,同时经Nginx业务入口请求健康接口 | API仅监听`127.0.0.1:3000`,外部不能直连3000;Nginx入口仍正常返回真实API健康结果;部署静态门禁校验`API_HOST`默认值与启动参数一致 |
## CMPP第三阶段业务批处理专项(2026-08-21)
| 用例ID | 场景 | 步骤 | 预期 |
| --- | --- | --- | --- |
| TC-CMPP-PERF-P3-001 | 有界批次领取 | 制造priority/normal混合Inbox并并发启动两个Worker | 每次领取不超过配置批次/槽位,使用SKIP LOCKED,无重复领取;priority先于normal且类内FIFO |
| TC-CMPP-PERF-P3-002 | 批次只读预加载 | 同批放入多应用、多内容正常短短信并统计SQL | 应用、模板、签名、黑名单、风控规则和敏感词按批读取,不逐短信重复;下一批重新读取应用状态 |
| TC-CMPP-PERF-P3-003 | 日限额批量原子性 | 在剩余额度边界并发提交并重放相同请求键 | 使用量不超过上限;每条预留决定独立持久化,重放不重复递增,拒绝项走既有失败回执 |
| TC-CMPP-PERF-P3-004 | 号码频控批量原子性 | 唯一号码批量提交、同号重复提交并模拟Worker崩溃重领 | 唯一号码批量更新;同号保留顺序语义并逐条处理;重领返回原决定,无穿透、重复计频或重复命中 |
| TC-CMPP-PERF-P3-005 | 三表与队列崩溃恢复 | 在三表提交后、BullMQ发布前注入失败并重领 | 任务/API请求/消息不重复,稳定MessageId对应唯一消息;以MessageId Job ID补入队后Inbox独立完成 |
| TC-CMPP-PERF-P3-006 | 异常与付费回退 | 覆盖正单价、黑名单、非法号、人工审核、引流歧义和已有消息 | 全部走原逐条状态机,余额冻结和回执语义不变;不得进入零计费批量快路径 |
| TC-CMPP-PERF-P3-007 | 500条/秒阶梯 | 在100.93.204.60依次执行smoke、100/200/300/500并逐级检查数据库、Redis和日志 | 任一级拒绝、缺响应、持续积压、锁等待或对账不一致立即停止;分别报告入口、Inbox完成和完整供应商链速率,不用积压冒充吞吐 |
执行记录(2026-08-21):`TC-CMPP-PERF-P3-001/002/003/004/005`已通过本地专项和测试机正常批次对账;`006`保留既有逐条回归通过,正单价吞吐未外推;`007`的smoke通过,100条/秒入口及Inbox对账通过,但命令Stream在注入结束时`pending=128/lag=922`且完整下游排空约87秒,按停止线判完整链失败并停止200/300/500档。
## Fail2ban 安全检测与人工封禁测试矩阵(2026-08-14)
- 本模块必须执行 `docs/fail2ban-assisted-blocking-test-cases-20260814.md` 中 TC-F2B 全量用例,专项用例是本平台功能测试的组成部分,不是可选附录。
- P0 门禁至少覆盖:九类规则真实 PostgreSQL 默认值与版本冲突、阈值边界、规则应用失败保留旧生效值、登录/HTTP/CMPP/SSH/Nginx 真实事件脱敏、事件键幂等、窗口聚合并发、可信代理 IP、Cloudflare 与直连入口执行器映射、系统和人工保护网段、近期重新认证、重复封禁原子认领、代理超时/失败、真实执行器回读、非 root NestJS 及任意命令/参数注入拒绝。
- 集成验收必须在隔离测试节点或网络 namespace 使用文档保留 IP;不得封禁预生产运维出口、Cloudflare 节点或真实客户 IP。未安装真实 Fail2ban/nftables/Nginx 资产时,只能把相关用例标记阻塞,不得用 Mock 通过代替。
- UI 验收覆盖桌面与窄屏的总览、告警、规则、封禁记录、保护名单、加载、空数据、失败和规则未生效状态;所有数字与操作结果必须能从 API、数据库、agent 与执行器证据交叉验证。
- `TC-F2B-OPS-008`:在非默认`APP_DIR`构建安全代理后执行安装器,核对systemd `ExecStart`与Fail2ban `actionban`均指向同一个真实可执行的`$APP_DIR/dist/cmpp-security-agent`;任一文件残留占位符、旧`current/bin`路径或目标不可执行时,安装/发布必须失败。
## 系统监控阈值与预警中心增量用例(2026-08-14)
| 用例ID | 场景 | 步骤 | 预期 |
| --- | --- | --- | --- |
| TC-INFRA-MON-029 | 模块顺序与技术说明 | 打开系统监控并检查标题和模块顺序 | 说明明确写明 Prometheus;服务关键指标紧邻活动告警上方,活动告警锚点可定位 |
| TC-INFRA-MON-030 | 阈值真实读取 | 打开阈值设置并核对 API 与数据库 | 十组固定指标来自 `InfrastructureAlertSetting`,不使用 Mock/localStorage,不允许编辑 PromQL |
| TC-INFRA-MON-031 | 阈值边界 | 提交警告≥严重、越界、缺项和未知指标 | API 返回 400,数据库版本和 Prometheus 规则均不改变 |
| TC-INFRA-MON-032 | 并发版本 | 两个会话以同一版本先后保存 | 仅第一个原子认领成功,后者返回 409 并提示刷新 |
| TC-INFRA-MON-033 | 规则校验与热加载 | 保存合法阈值,检查 promtool、规则文件、reload 与数据库 | 先校验再同目录原子替换,reload 成功后生效版本前进且写操作日志 |
| TC-INFRA-MON-034 | 应用失败回滚 | 令 promtool 或 reload 失败后保存 | 状态为 failed、展示原因,旧规则文件与旧生效阈值保留,不误报已生效 |
| TC-GLOBAL-ALERT-004 | 系统监控预警入口 | 准备隔离 QA Prometheus firing 告警并点击铃铛 | 第三项显示真实总数/严重数,角标计入三域总和,点击跳转系统监控活动告警区 |
| TC-SECURITY-UI-001 | Fail2ban 标识与标题规范 | 打开安全检测与封禁 | 不出现重复大号页面标题,说明明确写明使用 Fail2ban,字号遵循通用菜单标题 |
| TC-INFRA-MON-035 | 阈值弹窗单层滚动 | 在桌面和窄屏打开阈值设置,滚动到最后一组阈值 | 只有 Modal 外层内容区出现滚动条,阈值表单容器不产生第二层滚动或滚动陷阱,页头和页脚行为正常 |
| TC-INFRA-MON-036 | 活动告警逐条已读 | 使用管理员A点击一条当前活动告警的“标记已读” | PostgreSQL新增/更新管理员A与该次 activeAt 的记录;行显示“已读”,活动告警总数不变,铃铛系统监控数量减少1 |
| TC-INFRA-MON-037 | 已读用户隔离 | 管理员A标记已读后由管理员B查看同一告警 | 管理员B仍显示未读且铃铛数量不减少,管理员A的状态保持已读 |
| TC-INFRA-MON-038 | 同告警重新触发 | 标记已读后让告警恢复,再以相同标签重新触发并产生新 activeAt | 新触发记录重新显示“标记已读”,计入预警中心;旧 activeAt 不会永久屏蔽同指纹告警 |
| TC-INFRA-MON-039 | 过期与幂等 | 重复提交同一活动告警,再提交已恢复或 activeAt 不匹配的请求 | 同一次告警重复提交幂等;过期/不匹配请求返回404且不生成虚假已读记录;操作日志可追溯 |
## CMPP 500条/秒第一阶段:耐久Inbox快路径(2026-08-20
| 用例ID | 场景 | 步骤 | 预期 |
| --- | --- | --- | --- |
| TC-CMPP-500-P1-001 | 快速耐久受理 | 开启快路径提交合法短消息,并在风控/计费/队列依赖可观测时检查调用顺序 | SubmitResp在一条Inbox事实提交后返回`accepted_pending`;响应前不调用风控、频控、计费或BullMQ |
| TC-CMPP-500-P1-002 | 请求幂等 | 在同一已鉴权连接重投相同Sequence_Id与载荷 | Gateway请求键稳定,数据库只保留一条Inbox;两次返回相同MessageId,不重复创建任务、消息或冻结 |
| TC-CMPP-500-P1-003 | 幂等冲突 | 使用同一请求键提交不同载荷 | API拒绝冲突且不覆盖原Inbox/响应 |
| TC-CMPP-500-P1-004 | 多号码与长短信 | 分别提交多号码Submit和完整长短信分片 | Inbox保留全部号码及稳定子MessageId;长短信Worker处理的是完整重组正文,不是最后一片正文 |
| TC-CMPP-500-P1-005 | Worker领取与逐条完成 | 启动两个Worker并制造至少一个批次积压 | `SKIP LOCKED`领取不重复;每条独立完成,处理逻辑不占用领取事务 |
| TC-CMPP-500-P1-006 | 崩溃恢复与时区 | 数据库会话使用Asia/Shanghai,在领取后终止Worker,超过租约后重启 | UTC无时区列按UTC时钟比较,退避不会立即重领;processing记录被回收并完成,日限Date值合法,频控、冻结、任务和消息均不重复 |
| TC-CMPP-500-P1-007 | 异步业务拒绝 | 让已耐久受理短信命中真实模板/风控/余额拒绝 | SubmitResp仍表示已接收;后台生成真实失败状态和失败回执,不进入供应商发送 |
| TC-CMPP-500-P1-008 | 优先级 | 在普通Inbox积压期间持续混入priority应用 | priority先领取且类内FIFO;普通队列最终可排空;同时记录两类等待分位数 |
| TC-CMPP-500-P1-009 | 进程隔离 | 检查systemd、进程、连接和指标端口 | API角色不运行发送后台任务;`cmpp-send-worker`独立非root运行,指标仅监听127.0.0.1:9465 |
| TC-CMPP-500-P1-010 | 阶梯压测与对账 | 隔离供应商环境按既定同口径阶梯执行,压后等待全链排空 | 逐档报告SubmitResp、Inbox、两条Stream、最终数据库计数和排空时间;任何丢响应、重复、错误或未排空均失败,不发送真实短信 |
| TC-CMPP-500-P1-011 | Gateway API连接复用与流量隔离 | 将入站全局窗口设为48,后台协议日志持续写入,并构造Submit专用HTTP客户端 | Submit池每主机最大连接与空闲连接均为48、后台池独立16连接,HTTP总超时仍为10秒;后台日志/回执不得占用Submit连接或造成10秒API超时 |
| TC-CMPP-500-P1-012 | API/Worker数据库池隔离 | API与Worker分别配置32/8连接并在Worker积压时持续提交 | 两进程使用各自有界连接池,API受理连接不被Worker抢占;总连接数不超过PostgreSQL上限且压后无`idle in transaction`泄漏 |
执行记录(2026-08-20,测试环境):P1-001至009已由API/Gateway自动化、真实PostgreSQL迁移和独立Worker恢复验证覆盖;P1-011专用Submit传输隔离后100、200条/秒分别2999/2999、3998/3998成功,零拒绝、零节流、零连接错误。P1-010在500条/秒档失败:测试环境池调优后10秒仅2979条,实际297.9条/秒且节流611次;全部2979条最终完成并排空,但完整链仅约24条/秒。故第一阶段不通过500条/秒总目标,不执行“完整500条/秒已达标”的结论。
### 完整处理500条/秒第二阶段
| 编号 | 场景 | 操作 | 预期 |
|---|---|---|---|
| TC-CMPP-500-P2-001 | 合并校验与Inbox写入 | 普通短短信走快路径并检查SQL与阶段指标 | 使用账号唯一索引在同一SQL校验应用/企业/接口/IP/Src_Id并幂等插入;正常请求仅一次DB往返且不再单独记录`application_lookup` |
| TC-CMPP-500-P2-002 | 合并SQL拒绝安全 | 分别停用应用、停用企业、关闭接口、使用错误IP和Src_Id | 返回对应拒绝且Inbox没有新增;不读取或缓存旧应用快照 |
| TC-CMPP-500-P2-003 | 幂等与并发唯一键竞争 | 同载荷重试、冲突载荷重试,并并发提交相同请求键 | 同载荷返回原MessageId;冲突载荷拒绝;并发竞争最多执行一次只读恢复,不发生重复Inbox或无意义更新 |
| TC-CMPP-500-P2-004 | Worker批量应用快照 | 同批领取多个相同及不同应用Inbox | 每个领取批次按唯一应用ID一次查询,逐条继续使用匹配快照;应用不匹配时安全退避,不跨租约持有事务 |
| TC-CMPP-500-P2-005 | 有界容量配置 | 在测试环境提高Worker、BullMQ、Gateway Submit和Outbox并发并观测连接 | 各池配置值与在途数可观测,PostgreSQL连接低于`max_connections`并无长事务;单通道限速不被绕过 |
| TC-CMPP-500-P2-006 | 100→200→500完整链阶梯 | 使用全新测试号段、隔离六通道模拟器,逐档注入并等待全部队列排空 | 每档报告入口实际速率/分位、Inbox完成、各队列峰值与排空、供应商阶段和数据库对账;500档只有入口及完整链均达到500条/秒且零丢重才通过 |
执行记录(2026-08-20,测试环境):P2-001至004由121项SendChain专项、真实PostgreSQL修复后低负载9/9及100条/秒2998/2998受理覆盖;首次真实执行发现并修复`jsonb_build_object`参数类型错误,该无效轮未写Inbox。P2-005使用API/Worker池48/32及96/96/128/32四类有界业务槽,数据库压后无idle-in-transaction。P2-006在100条/秒入口通过但完整链失败:Inbox约57.5条/秒、双Stream完整排空约22.0条/秒,且后台API回调超时;按停止线未继续200/500,因此第二阶段仍不通过完整500条/秒目标。
## TC-CMPP-500-P4 正价计费与六通道并行
| 用例 | 场景 | 预期 |
| --- | --- | --- |
| TC-CMPP-500-P4-001 | 同企业正价短短信批量入站并重放 | 一次账户余额更新;每短信唯一`:freeze`流水;任务/请求/消息金额正确;重放不重复冻结 |
| TC-CMPP-500-P4-002 | 余额加授信小于批次或单条金额 | 不得透支;批次安全回退且只发送余额覆盖的短信 |
| TC-CMPP-500-P4-003 | 正价短信Submit接受及Outbox重放 | 一个原子SQL生成released/charged且不取得账户锁;余额净值不重复变化;SmsBillingRecord唯一charged;历史半完成状态仍可锁定恢复 |
| TC-CMPP-500-P4-004 | 零价短信Submit接受 | 保留业务结果但无0金额AccountTransaction |
| TC-CMPP-500-P4-005 | 两个同优先级非备用通道与一个备用通道 | 稳定weighted分流只覆盖两个主动通道;排除已尝试通道后可安全切换;备用不抢占 |
| TC-CMPP-500-P4-006 | 三运营商、六通道、325金额单位阶梯压测 | 每档入口/Inbox/供应商/回执/账务对账一致,双Stream和数据库最终稳定排空;失败即停止升档 |
| TC-CMPP-500-P4-007 | priority与normal并发积压 | priority保持明确服务能力且normal最终不饿死 |
| TC-CMPP-500-P4-008 | 测试配置治理 | 单价、账户与组项目先快照;临时主动双活和单价测试后恢复;预生产和凭据不变 |
| TC-CMPP-500-P4-009 | 单分片与多分片供应商Submit | 单分片只产生一个含segments的聚合Outbox事件;多分片逐片持久化并另有聚合事件,任何分片不丢失 |
| TC-CMPP-500-P4-010 | 同一批次并发任务进度刷新 | 并发调用共享一个运行中聚合查询,并在其间有新状态提交时只补一次尾随聚合;最终任务计数与消息终态一致 |
执行记录(2026-08-21):`P4-001/003/004/005/008/009/010`已由自动化、真实PostgreSQL账务、六通道隔离模拟器及配置回读覆盖;正价smoke通过。`P4-006`在100条/秒档2999/2999入口受理,但最后供应商提交耗时167.991秒,完整链约17.85条/秒,判定失败并按停止线未升200/300/500。`P4-002/007`本轮未追加专项压力场景,保留待测;临时单价、主备和号段规则已恢复,财务流水保留审计。
主流程回归记录(2026-08-21):停止继续性能优化后,以2条单价325的隔离CMPP短信验证接收、发送、供应商SubmitResp、最终回执和计费,Inbox/Submit/Receipt/Message/Billing均2条闭合,冻结/释放/扣费金额均650。另以实际MessageId注入1条测试机内部Gateway上行事件,上行精确匹配且客户CMPP普通Deliver/ACK最终deliveredGateway原始CMPP上行解析由全量Go测试和vet通过补充覆盖。临时单价已恢复为0,队列和数据库稳定,允许进入Git发布检查。
## CMPP发送准入与通道路由专项(2026-08-21)
| 用例ID | 场景 | 步骤 | 预期 |
| --- | --- | --- | --- |
| TC-CMPP-GUARD-001 | 签名未审核 | 将隔离应用签名改为待审核后提交1条带该签名短信 | 消息以`SIGNATURE`失败,生成客户失败回执,供应商提交0条 |
| TC-CMPP-GUARD-002 | 模板未报备 | 应用启用模板强校验且不存在匹配的已审核模板时提交1条 | 消息以`TEMPLATE`失败,供应商提交0条;`direct_send`应用不应误套用此断言 |
| TC-CMPP-GUARD-003 | 余额不足 | 设置正单价并使余额加授信小于本条金额后提交 | 消息以`BALANCE`失败,不冻结成负数、不进入供应商提交 |
| TC-CMPP-GUARD-004 | 应用接口关闭 | 关闭企业应用接口并发起CMPP登录/提交 | CMPP登录被拒绝,不能新增入站消息或供应商提交 |
| TC-CMPP-GUARD-005 | 应用禁用或删除 | 分别将应用状态置为`inactive`、`deleted`后登录 | 两种状态均在认证阶段拒绝,恢复后可重新登录 |
| TC-CMPP-GUARD-006 | 企业禁用或删除 | 分别将企业状态置为`inactive`、`deleted`后由其应用登录 | 两种状态均在认证阶段拒绝,不影响恢复后的应用配置 |
| TC-CMPP-GUARD-007 | 单号码频次 | 配置应用级5分钟阈值1并连续向同号提交2条 | 第1条正常发送,第2条以`RISK`拦截;命中记录阈值/实际值正确且第2条供应商提交0条 |
| TC-CMPP-GUARD-008 | 签名未在候选通道报备 | 将签名在路由组所有候选通道的运营商报备改为未通过后提交 | 消息以`ROUTE`失败,供应商提交0条;任一已报备在线候选仍存在时不得误拦截 |
| TC-CMPP-GUARD-009 | 主通道禁用 | 禁用通道组主通道、保留已报备且在线的备通道后提交 | 新消息不选禁用主通道,自动选择备通道并可最终送达 |
| TC-CMPP-GUARD-010 | 通道组全部通道禁用 | 同时禁用组内主备通道后提交 | 消息以`ROUTE`失败,供应商提交0条,不向已禁用连接发送 |
| TC-CMPP-GUARD-011 | 主通道拒绝后组内补发 | 让主通道返回非0 Submit结果,组开启补发且备通道在线/已报备 | 首次提交`rejected`;第二次提交指向未尝试备通道并关联`retryOfSubmitRecordId`,接受后按真实回执进入终态 |
| TC-CMPP-GUARD-012 | 配置恢复审计 | 每项测试后回读企业、应用、余额、签名、报备、通道、连接和临时规则 | 所有临时配置恢复原值,服务健康、队列无异常状态,操作和测试证据可追溯 |
执行记录(2026-08-21,测试环境):`TC-CMPP-GUARD-001`至`012`全部通过。入口采用耐久异步受理,因此业务拦截用例的SubmitResp仍可为0;最终结论以本次MessageId对应的消息错误码、供应商提交数及客户失败回执为准。通道组补发实测主通道结果码8、备通道accepted、消息最终delivered;全部临时配置已恢复。
## TC-CMPP-500-P4-P1 发送Worker低风险数据库往返收敛(2026-08-24)
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-CMPP-500-P4-P1-001 | CMPP单号码任务在提交、结果、回执和超时阶段刷新进度 | 使用直接状态更新;压力窗口不产生按batchTaskId的消息状态`GROUP BY`;多号码任务仍走聚合 |
| TC-CMPP-500-P4-P1-002 | 路由、在线通道与签名报备候选 | 一次数据库候选查询只返回active/connected/approved通道;无最终通道二次报备查询;报备或通道撤销能实时拦截 |
| TC-CMPP-500-P4-P1-003 | 开放会话与提交统计 | 每通道首次读取开放会话ID并复用;提交事务不更新`CmppSubmitSession.submitTotal`热点行;提交记录保持独立外键 |
| TC-CMPP-500-P4-P1-004 | Gateway双发布职责 | Go Gateway只消费Redis Stream;发送Worker不再写无消费者BullMQ副本;Stream PEL/ACK/结果Outbox/死信行为不变 |
| TC-CMPP-500-P4-P1-005 | 正价六通道100档 | 入口、消息、提交、回执、计费、唯一性和六账号分布一致;双Stream最终排空、Bull遗留值不增长、数据库无持续锁或idle事务 |
执行记录:本地API全量42套500项和TypeScript构建通过;正价smoke 9/9通过。最终100档2999/2999受理,P50/P95/P99=`33/77/179ms`,三运营商=`998/996/1005`,六供应商账号均有提交;2999个唯一号码首次供应商提交覆盖99.940秒、约30.00条/秒,未达到完整100条/秒,按停止线未升200/300/500。应用任务进度`GROUP BY`为0、开放会话热点累计更新为0、Bull遗留wait始终84119;两条Stream最终0/0。计费冻结/释放各2999笔974675,正式扣费2990笔971750、退款25笔8125SmsBillingRecord当前charged2965笔963625/refunded25笔8125,账务恒等。剩余主瓶颈是同企业计费`pg_advisory_xact_lock`累计373.373秒/841次;P1降低单条Worker总耗时但未提高完整供应商吞吐。临时单价和三条号段规则已恢复。
## TC-CMPP-500-P4-P2 正价计费并发锁治理(2026-08-24)
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-CMPP-500-P4-P2-001 | 同企业多应用正价并发冻结 | 任务、消息、冻结流水和账户余额仍同事务;账户锁仅覆盖事务末尾账务段,等待时间显著低于P1对照 |
| TC-CMPP-500-P4-P2-002 | 单价325的冻结、释放、扣费、退费并发幂等 | MessageId/号码唯一,账户流水与`SmsBillingRecord`净扣一致,无重复扣费或负余额 |
| TC-CMPP-500-P4-P2-003 | Worker微批候选的性能比较 | 只有完整供应商吞吐不退化才保留;退化时回退候选代码并重新部署验证 |
| TC-CMPP-500-P4-P2-004 | 六通道正价50档停止线 | 核对入口、唯一供应商首提交、通道分布、账务和队列;完整吞吐不到50时不升100 |
| TC-CMPP-500-P4-P2-005 | 禁止0计费压测代替正价证据 | smoke及所有压力档`unitPrice` min/max均325;单价0只在测试结束后做环境恢复,恢复后不再压测 |
执行记录:最经六通道正价50档1499/1499受理,入口P50/P95/P99=`31/77/227ms`,完整供应商首提交约21.69条/秒,因低于50未升100。计费锁598次累计3.241秒/均值5.420ms,较P1累计下降约99.1%、均值下降约98.8%。冻结/释放各1499笔487175charged1496笔486200,退费21笔6825,账单净扣一致。Worker微批候选因吞吐退化已回退;所有压力运行均为325正价,无0计费压测。
## TC-CMPP-RELEASE-CLOSEOUT 发布前主流程与拦截复核(2026-08-24)
| 用例ID | 场景 | 当前版本结果 |
| --- | --- | --- |
| TC-CMPP-RELEASE-001 | 正价CMPP接收、发送、SubmitResp、回执、计费 | 单价325的消息`MSG-6b537761-9a1c-47eb-88d3-fe5e1d7d33f9`为accepted/DELIVRD/delivered,计费记录325、账户charged -325;通过 |
| TC-CMPP-RELEASE-002 | 上行匹配与客户Deliver/ACK | 上行`cmt75bszh0qjy6vletv06f4pc`按MessageId精确匹配,下游投递最终delivered;通过 |
| TC-CMPP-RELEASE-003 | 签名、模板、余额、号码频次 | 分别为SIGNATURE/TEMPLATE/BALANCE/RISK,供应商提交均0;通过 |
| TC-CMPP-RELEASE-004 | 应用接口、应用状态、企业状态 | 接口关闭、应用inactive/deleted、企业inactive/deleted均bind状态3;通过 |
| TC-CMPP-RELEASE-005 | 报备与通道启停 | 报备缺失和主备全停为ROUTE且提交0;仅主停自动选择备通道并delivered;通过 |
| TC-CMPP-RELEASE-006 | 主通道拒绝后组内补发 | 主通道结果码8/rejected,备通道关联retryOf后accepted,消息delivered;通过 |
| TC-CMPP-RELEASE-007 | 配置、队列和服务恢复 | 应用/企业/签名/报备/通道全部恢复;Inbox、BullMQ、双Stream排空;无锁等待/idle事务;六服务和六连接健康;通过 |
说明:异步耐久入口的业务拦截仍可先返回成功SubmitResp,必须按精确MessageId核对最终错误码、供应商提交数和客户失败回执。供应商模拟器重启后必须同时等待模拟器连接数和数据库通道连接状态恢复,不能只看TCP连接数。
| TC-CMPP-OUTBOX-001 | Submit事实与Outbox原子持久化 | 提交记录、消息状态和Outbox同事务,payload submitId一致且唯一 |
| TC-CMPP-OUTBOX-002 | 影子到正式单路径切换 | 影子只对账;正式启用后旧直投关闭,无双发布 |
| TC-CMPP-OUTBOX-003 | 租约恢复与批量发布 | SKIP LOCKED领取、Redis pipeline、批量回写和有界失败重试 |
| TC-CMPP-OUTBOX-004 | 正价阶梯与计费恒等式 | 账单数等于消息数、金额等于消息数乘325,补发有retryOf |
| TC-CMPP-OUTBOX-005 | 首提容量停止线 | 仅首次Submit计算速率;50 TPS不达标即停止更高档 |
| TC-CMPP-BATCH-001 | 批量路由规划 | 同一聚合批次只执行一次消息/号段/候选路由预载,仍逐消息执行实时状态、报备及限速判断 |
| TC-CMPP-BATCH-002 | Submit与Outbox批量原子持久化 | Submit批量插入、消息集合式更新、Outbox批量插入同属一个短事务;MessageId/submitId唯一 |
| TC-CMPP-CALLBACK-001 | Gateway事件进程隔离 | Submit结果、回执、上行、协议日志和死信只进入回环回调进程及独立12槽池;连接状态仍进入主API |
| TC-CMPP-CALLBACK-002 | 回调安全边界 | 回调进程仅监听127.0.0.1,不加载计费管理Controller;健康与指标端点只在回环可见 |
| TC-CMPP-BATCH-003 | 正价50 TPS完整提交 | 单价325499条首次Submit在9.930秒完成(50.25/s);499笔账单162175,无丢重,队列最终排空 |
## TC-CMPP-PHASE5 单 Gateway 容量扩展(2026-08-25
| 用例ID | 场景 | 验收结果 |
| --- | --- | --- |
| TC-CMPP-PHASE5-001 | API、Gateway控制入口、实际运行三层校验1~8连接/1~64窗口 | `1x1/2x16/4x32/8x64/4x64/2x32`通过;越界拒绝 |
| TC-CMPP-PHASE5-002 | 协议日志降载 | 成功日志确定性采样,异常全留;独立Worker批量写库后ACK/XDEL,错误0且Stream排空 |
| TC-CMPP-PHASE5-003 | 批量HTTP回调与重放 | 多事件少请求;逐事件结果;非法事件不影响有效事件;HTTP失败整批重放;重试/死信可观测 |
| TC-CMPP-PHASE5-004 | 上行eventId幂等 | 同一事件投递两次只生成1条SmsUplinkMessage |
| TC-CMPP-PHASE5-005 | 在途平滑缩容 | 单通道1→4→1并发发送399条,SubmitResp/首次Submit均399,重复ID为0,连接恢复6/6 |
| TC-CMPP-PHASE5-006 | 非零单价阶梯停止线 | 20/30/50通过;70档P95/P99=`4099/5323ms`且实得66.66 TPS,立即停止100/150/200,稳定上限50 TPS |
| TC-CMPP-PHASE5-007 | 拦截与主备回归 | SIGNATURE/TEMPLATE/BALANCE/RISK均供应商前拦截;应用/企业停用拒绝鉴权;主停走备、全停ROUTE;拒绝补发retryOf完整 |
| TC-CMPP-PHASE5-008 | Gateway/Redis故障与最终排空 | Gateway重启恢复连接;排空时Redis短停后恢复;Submit/结果/日志Stream pending/lag均0,无锁等待/idle事务 |
| TC-CMPP-PHASE5-009 | 同账号并发pending拉取 | 8个并发刷新只产生1次API领取;记录以FOR UPDATE SKIP LOCKED从pending转dispatching,携带claimId和租约 |
| TC-CMPP-PHASE5-010 | API直推与Gateway恢复同时命中同一回执 | 仅抢到dispatching + claimId的路径发送;100 TPS正价实测972条终态回执对应972次下游ACK,重复0,最大尝试1 |
| TC-CMPP-PHASE5-011 | claim未发送、租约过期和ACK定时器竞态 | SubmitResp屏障或客户离线时释放claim且不增加重试次数;过期dispatching可恢复;Linux go test -race ./internal/inbound通过 |
| TC-CMPP-PHASE5-012 | 修复后正价容量与口径分离 | 20至200 TPS入口均无拒绝、节流或连接错误;999条100 TPS复验入口P95/P99 102/179ms,供应商首提80.00 TPS150/200冲击档首提约95 TPS天花板,两种口径分开报告 |
| TC-CMPP-PHASE5-013 | 同企业工作流串行与有界微批 | 同企业领取期间不再领取第二批;已有少量记录最多等待40ms聚合,目标32、上限64;优先级/FIFO、租约恢复和幂等不变 |
| TC-CMPP-PHASE5-014 | 不同企业正价并行 | 至少两个独立企业合计200 TPS;各企业账户冻结串行且企业间并行,单价均为325,分别对账消息、账单、首提和最终状态 |
| TC-CMPP-PHASE5-015 | Outbox UTC时间语义 | Asia/Shanghai数据库会话下领取、租约、发布、重试均写UTC无时区值;publishedAt-createdAt不再出现约8小时偏差 |
| TC-CMPP-PHASE5-016 | 微批发布边界与停止线 | 仅单Gateway;分别验证单企业100/150与多企业200,发生拒绝、连接错误、持续积压、数据库异常或账务不一致立即停止 |
| TC-CMPP-PHASE5-017 | Gateway到API长连接生命周期 | API keep-alive 120秒大于Gateway连接池90秒,headers timeout更大;跨越Node原默认5秒空闲边界后继续压测,不得出现loopback connection reset或Result 9 |
| TC-CMPP-PHASE5-018 | 同连接并发状态回调 | 同一connectionId的connected与submit并发时幂等upsert且保持在线;不同connectionId超过cmppMaxConnections仍403,不能误断当前连接或漏SubmitResp |
执行记录:按企业微批发布后,单企业100 TPS为999/999响应、P95/P99=`243/466ms`、首次供应商Submit=`95.85 TPS`;单企业150 TPS冲击为1498/1498、`83/117ms`、首次Submit=`122.87 TPS`;双企业200 TPS冲击为1999/1999、`148/287ms`、首次Submit=`129.39 TPS`。三档最终有效运行均零拒绝、零节流、零连接错误,价格均325。双企业档账务1988 charged/646100、11 refunded/35752145个Submit/Outbox唯一,1950条终态回执投递1950次、重复0,973条离线pending通过零发送客户端排空。多Gateway P2未实施。
## TC-ADMIN-SMS-RECORD-DENSITY 运营端短信记录高密度列表(2026-08-27)
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-ADMIN-SMS-RECORD-DENSITY-001 | 打开短信记录搜索区 | 企业、应用、提交日期、手机号码、运营商、短信内容、通道、发送状态、是否含引流信息9项条件均保留,不能新增、删减或合并 |
| TC-ADMIN-SMS-RECORD-DENSITY-002 | 在桌面与窄视口查看搜索区 | 仅控件宽度和布局响应式变化,9项条件、查询和重置行为不变,无控件覆盖或截断 |
| TC-ADMIN-SMS-RECORD-DENSITY-003 | 查看包含单分片和多分片的短信记录 | 列表按日期分组;提交与回执分别显示日期和时分秒;计费列同时显示真实金额、分片数和字数;列表不显示“已补发”标签 |
| TC-ADMIN-SMS-RECORD-DENSITY-004 | 点击任一行最右侧箭头 | 继续打开既有发送详情弹窗,原有短信内容、通道发送与回执、状态信息及分片补偿审计保持不变 |
| TC-ADMIN-SMS-RECORD-DENSITY-005 | 使用真实本地API数据加载、查询、翻页和打开详情 | 页面非空、无异常遮罩,控制台无新增错误;数据仍来自原有真实API,不引入mock或localStorage业务数据 |
执行记录:本地真实API/PostgreSQL渲染通过,9项条件全部存在,1/2分片均显示在计费列;右箭头成功打开原有详情弹窗,干净页面控制台日志为空。R11契约、前后端构建、159项API专项测试及Gateway全包测试/vet通过。
## TC-LG-STEP46-47 客户端发送与 Gateway 回调回归(2026-08-27
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-LG-STEP46-47-001 | Gateway 批量结果消费时 Redis 短暂 I/O timeout | 批量消费协程不永久退出;重试并重建 consumer group 后继续消费 SubmitResult、ReceiptEvent 和 UplinkEvent |
| TC-LG-STEP46-47-002 | 普通 MO 上行没有可关联的平台 messageId | Outbox 允许事件入流和回调;API 按接入号/手机号窗口匹配,未匹配也必须落库 |
| TC-LG-STEP46-47-003 | `templateMismatchMode=direct_send` 应用选择已审核签名、输入自由正文和号码 | 不要求模板,提交按钮可用;仍进入后端签名、风控、余额、路由和发送策略 |
| TC-LG-STEP46-47-004 | 任意必填项未完成时查看提交区 | 禁用按钮旁明确显示当前第一个可操作原因,不出现无说明禁用 |
| TC-LG-STEP46-47-005 | 绕过系统文件选择器注入 XLSX | 前端同时核对扩展名和非空 MIME,明确提示“仅支持 CSV、TSV 或 TXT 文本文件”,不调用导入预览 API |
| TC-LG-STEP46-47-006 | 390×844 首次打开定时选择器 | 弹层限制在视口内,清空/今天/确定操作区首屏可见可点,内容过高时仅弹层内滚动 |
| TC-LG-STEP46-47-007 | 客户端批量任务显示 UTC ISO 时间 | 提交时间和定时时间统一转为 Asia/Shanghai `YYYY-MM-DD HH:mm:ss`,不显示原始 `T...Z` 字符串 |
执行记录:Gateway `resultoutbox` 定向测试及全包测试通过;API 45套528项通过;API构建、前端TypeScript与Vite生产构建通过。390×844 Chromium 渲染回归中,无模板直发按钮可用,日期弹层为366×476且操作区Y=431~471,XLSX明确拒绝,批次时间显示为北京时间,控制台无错误。
## TC-UI-REVIEW-20260827 客户端展示、三网报备与人工审核状态
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-UI-REVIEW-001 | 查看客户端登录、工作台和账户余额 | 登录页存在“返回官网”;工作台四张指标卡的数字均为`.metric-card > strong`直接文本,不使用金额专用类或`MoneyText`包装,并使用同一字体、字号、字重和颜色;账户状态不显示“余额水位”;账户余额页金额为继承系统字体、常规字重的普通大号黑字,顶部仅显示左侧图标和“账户余额”标题;客户端右上角无待审核任务按钮 |
| TC-UI-REVIEW-002 | 首次打开批量任务、发送详情和上行短信 | 三个日期区间均为北京时间近7天(含当天) |
| TC-UI-REVIEW-003 | 查看不同状态的短信发送记录和回执 | 用户态状态为中文;未知协议值显示“状态未知” |
| TC-UI-REVIEW-004 | 对比两端同一应用的CMPP状态 | 两端均按已连接、已断开、未开通显示 |
| TC-UI-REVIEW-005 | 查看签名及引流三网状态 | 不显示使用场景、已提交资料、审核状态;三网状态来自真实路由和报备任务,部分通过与全部通过均映射为“报备通过” |
| TC-UI-REVIEW-006 | 在通道签名活跃度热力图输入通道名 | 仅保留匹配通道的维度行;企业、应用、签名搜索仍有效 |
| TC-UI-REVIEW-007 | 在运营端短信任务进度选择任务状态 | 请求携带精确状态且结果仅含该状态;重置恢复全部状态 |
| TC-UI-REVIEW-008 | 创建命中人工审核规则的批量任务 | 两端显示“待人工审核”、进度为0;客户端无终止按钮,详情显示审核原因,运营审核页可见关联批量任务号 |
| TC-UI-REVIEW-009 | 审核通过或驳回批量任务 | 状态按真实后端刷新;驳回时展示原因,不重复入队或发送 |
| TC-UI-REVIEW-010 | 接口对接某个日志子接口失败 | 接口概览仍可用且提示中文,不直接显示`Internal server error` |
## TC-DRAINAGE-UI-20260828 三网状态与引流字段统一
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-DRAINAGE-UI-001 | 客户端查看签名及展开后的引流信息列表 | 移动、联通、电信在同一组三网状态单元中清晰展示;每项含运营商名称和真实“报备通过/暂不可用”状态,签名与引流行布局一致 |
| TC-DRAINAGE-UI-002 | 客户端打开新增或修改引流信息弹窗 | 仅有必填“引流 URL 或号码”,不存在“名称”和“访问地址”;提示明确支持 URL、手机号码和固定电话号码 |
| TC-DRAINAGE-UI-003 | 分别提交 `https://example.com/path`、`example.com/path`、`www.example.com`、`13800138000`、`0755-12345678` | 带协议URL、不带协议URL、手机和固话均通过真实客户端 API 和服务端校验,写入 PostgreSQL;兼容 `siteName` 列与 `url` 列同步保存相同目标值,进入真实待审核流程 |
| TC-DRAINAGE-UI-004 | 提交普通文字或空值 | 前端禁止空值提交;绕过前端提交普通文字时后端返回受控参数错误,不写数据库、不创建审核记录 |
| TC-DRAINAGE-UI-005 | 运营端查看单条审核列表、详情、报备任务及报备记录 | 统一显示“引流 URL 或号码”及真实目标值,不再显示独立站点名称或旧“引流地址”标签;审核通过/驳回仍调用原真实 API |
| TC-DRAINAGE-UI-006 | 下载引流官方导入模板并配置导入映射 | 模板和映射仅要求“所属短信签名”“引流 URL 或号码”,不再要求“站点名称”;导入项进入真实审核批次 |
| TC-DRAINAGE-UI-007 | 桌面和窄屏查看三网状态组及引流列表 | 状态单元不相互覆盖,文字不截断为不可辨认内容;窄屏沿用受控列表滚动,不产生页面级横向溢出 |
## TC-PORTAL-20260831 六项运营/客户端修复
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-PORTAL-001 | 修改通用字段引用、资料用途、必填属性并刷新 | PUT保存真实配置,ID不变,新增操作日志;重复组合、已停用字段及非法必填值被拒绝;历史报备快照不变 |
| TC-PORTAL-002 | 比较同应用运营与客户端新增签名资料,无应用时比较通用资料 | 字段代码/名称/类型/必填/说明一致;通用+通道要求去重合并;已删除通道不提供字段;同字段双用途不覆盖快照 |
| TC-PORTAL-003 | 快速切换应用,旧字段请求最后返回;字段请求失败 | 仅展示当前应用资料;加载中或失败禁止提交,不把失败当作无需报备 |
| TC-PORTAL-004 | 删除签名/模板后刷新列表和选择器,构造status=deleted及includeHistory=true | 客户端列表/统计排除已删除对象;旧列表响应不能覆盖删除后刷新;已删除对象不可再次提交审核;历史发送记录不受影响 |
| TC-PORTAL-005 | 含引流、不含引流、未检测三类历史记录 | 列表仅含引流记录在发送状态下显示标签,无负向标签;详情明确三种状态,按真实后端位置高亮URL/号码 |
| TC-PORTAL-006 | 查看最终已回执及未回执短信 | 列表无回执时间列;详情“最终回执时间”来自消息最终结果,无值显示“-”;各通道回执时间仍保留 |
| TC-PORTAL-007 | 三个客户端查询页修改输入、日期、下拉后等待并翻页;查询/重置 | 输入不发搜索请求;翻页保持已应用条件;查询/重置回到第一页,只发一次新查询;上行返回第一页重新加载 |
| TC-PORTAL-008 | Prometheus同时返回系统盘、数据盘、第三块磁盘,顺序打乱或有缺失点 | 全部独立文件系统各有容量卡片及独立趋势;按instance/device/fstype匹配,绑定挂载合并,不串盘,不以0填缺失点;采集失败清空指标 |
| TC-PORTAL-009 | 系统盘或任一数据盘分别超过容量阈值 | 使用原有效阈值按独立文件系统告警,信息含设备及文件系统类型,同一文件系统绑定路径不重复告警;实际加载的基础和托管规则无同名重复;tmpfs/overlay等虚拟盘不参与 |
| TC-PORTAL-010 | 测试发布与安全边界 | 新独立恢复资产的custom dump、运行tar、配置tar、原标记和SHA全部验证后才能发布;查服务、health、Stream、窗口日志与资源哈希;不发/补发/重投短信,不修改客户/余额/通道配置 |
| TC-STORAGE-DEPLOY-001 | 数据盘迁移后安装/发布前置检查;在隔离挂载命名空间隐藏数据盘或绑定挂载 | 两个入口均在初始化/发布写入前拒绝继续;验证UUID、源/目标inode、读写属性及既有存储标记;宿主挂载及服务PID不变 |
| TC-STORAGE-DEPLOY-002 | 数据盘迁移后发布业务代码 | 新恢复资产在数据盘上,custom dump/tar/SHA验证通过;存储服务PID、绑定挂载、fstab、环境及systemd保护保持不变;代码回退不恢复旧系统盘业务数据;系统盘和数据盘均有真实监控指标 |
## TC-DISK-DEDUP-20260831 绑定挂载磁盘去重
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-DISK-DEDUP-001 | 同一设备同时采集/data、/var/lib/pgsql、/var/lib/redis、/var/lib/minio | API仅返回一个数据盘,容量不累加,mountpoints保留四个路径;/data优先展示,展开“其他挂载点(3)”可查看绑定路径;系统盘和EFI独立保留 |
| TC-DISK-DEDUP-002 | 打乱采集顺序、根目录有绑定路径、主路径停止采集、趋势缺失或NaN | 文件系统ID保持稳定;根盘兼容指标及趋势正确;主路径按层级/长度/字典序确定;同一文件系统只有一条趋势,不补零,不因路径改变丢失历史 |
| TC-DISK-DEDUP-003 | 不同instance/device/fstype的样本容量相同,或指标不可用 | 不同文件系统不误合并;缺失指标为null/空趋势,页面显示暂无数据而非旧卡片;不得仅凭容量相同合并 |
| TC-DISK-DEDUP-004 | 核对API查询、基础规则和按当前有效阈值生成的托管规则 | 容量和inode均max by(instance,device,fstype),可用容量min聚合,不按mountpoint重复告警;阈值不变;promtool校验通过,未来发布后再核对实际加载规则、告警及真实页面;告警标签变化会影响指纹和for计时,不虚报已保留 |
## TC-ENTERPRISE-SIGNATURE-DENSITY-20260902 企业签名高密度列表
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-ENTERPRISE-SIGNATURE-DENSITY-001 | 首次打开运营端企业签名管理 | 不请求或展示顶部全部/待审核/报备中/异常统计;短信签名Tab不显示总数;列表使用紧凑表头与行布局 |
| TC-ENTERPRISE-SIGNATURE-DENSITY-002 | 查看签名及展开的引流信息 | 两级表头统一使用“审核状态”;签名及引流信息的移动/联通/电信列同时显示汇总状态及已通过通道数/总通道数,不显示日期;引流信息列只显示条数,不显示异常数 |
| TC-ENTERPRISE-SIGNATURE-DENSITY-003 | 查看签名查询和签名列 | 查询标签及表头统一为“签名”,不显示签名用途;签名统一显示完整中文黑括号,例如“【聆界科技】”,已有括号不得重复包裹 |
| TC-ENTERPRISE-SIGNATURE-DENSITY-004 | 查看签名表头并翻页 | 签名表头不显示排序按钮,请求不携带signatureSort;后端按创建时间倒序分页,不在前端重排当前页,不产生重复请求 |
| TC-ENTERPRISE-SIGNATURE-DENSITY-005 | 查看签名及引流信息操作列 | 两级操作列都只展示“报备状态、编辑、删除”;不显示“报备详情”;三个入口继续调用原真实后端流程 |
| TC-ENTERPRISE-SIGNATURE-DENSITY-006 | 1600×1000桌面视口查看并展开首条签名 | 表头与数据列对齐,操作按钮不换行,展开表格无裁切;页面无框架错误层,控制台无相关错误;窄视口由列表容器横向滚动,不挤压错列 |
| TC-ENTERPRISE-SIGNATURE-DENSITY-007 | 某一运营商下所有当前目标通道的报备任务均为abandoned | 该签名及其引流信息在对应运营商列汇总为“放弃报备”,同时显示0/总通道数;仅部分通道放弃时不得误判为全部放弃 |
## TC-REPORT-WORKBENCH-20260902 报备工作台、补资料与单条导出
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-REPORT-WORKBENCH-001 | 打开运营端导航及四个报备页面 | 一级菜单为“报备工作台”,二级菜单依次为“报备资料池、报备批次、通道报备明细、状态记录”;资料池和批次不再共用页签 |
| TC-REPORT-WORKBENCH-002 | 运营端新增签名或修改签名报备资料 | 保存后签名自动审核通过并写`admin_create_approved/admin_update_approved`审核记录,客户端编辑和导入审核流程不变;后端返回资料变化标识并提示到报备资料池生成批次 |
| TC-REPORT-WORKBENCH-003 | 查看存在有效应用路由但尚未生成任务的签名 | 通道报备明细按企业应用×签名×通道×运营商显示虚拟“未报备”行,可单选或多选后通过真实状态接口创建/更新任务并写状态记录 |
| TC-REPORT-WORKBENCH-004 | 将一条通道运营商明细设为放弃报备后预检批次 | 仅该通道运营商组合被排除,其他有效组合仍可生成;不得发送、补发、重投或重新入队短信 |
| TC-REPORT-WORKBENCH-005 | 从资料池选择资料生成批次并打开批次明细 | 批次列表不直接铺开文件,仅显示通道数、生成状态及报备总数/报备中/成功/失败四项明细数;“打开明细”从右侧滑出该批次通道明细列表 |
| TC-REPORT-WORKBENCH-006 | 从通道报备明细或短信通道报备详情查看资料 | 字段严格按当前通道签名报备字段/引流字段sortOrder排列,历史未配置字段置后;加载失败、文件缺失和必填缺失显示真实错误 |
| TC-REPORT-WORKBENCH-007 | 导出一条签名通道运营商明细 | 后端读取真实签名、通道字段和MinIO对象生成单行XLSX;图片嵌入;不改变任务状态、不生成批次、不触发短信链路,并写操作日志 |
| TC-REPORT-WORKBENCH-008 | 短信通道管理进入报备详情 | 使用后端分页,默认按今日发送条数全量降序后分页;可按关键词、状态、运营商及今日发送区间查询;状态弹窗展示当前上下文和放弃风险 |
| TC-REPORT-WORKBENCH-009 | 导入命中已有签名且用途列未映射或为空 | 识别为补资料;未提供字段保持原值,提供的动态字段覆盖同名值并追加新字段;用途不得被空字符串清空;审核前不改真实签名 |
| TC-REPORT-WORKBENCH-010 | 在状态记录按批次、操作人、状态、入口、对象和时间搜索 | 返回真实状态记录及操作人;可追溯人工修改来源;分页、空数据、失败和历史无入口记录均正确展示 |
| TC-REPORT-WORKBENCH-020 | 1600px大屏PC查看状态记录列表 | 列表合并展示“变更对象”、“变更动作”和“操作人 / 时间”,无需左右滚动;备注、修改入口等完整信息仍可在详情弹窗查看,搜索参数和真实API不变 |
| TC-REPORT-WORKBENCH-011 | 桌面及390px窄屏查看四页和状态弹窗 | 桌面表格可扫描;窄屏核心主体、状态、今日发送和操作可访问,无按钮遮挡;控制台无新增错误,所有业务数据来自真实API/PostgreSQL |
| TC-REPORT-WORKBENCH-012 | 查看企业签名表头和签名列表 | 签名列不显示升序、降序或其他排序按钮;列表不显示逐行待生成明细字段;默认按创建时间倒序 |
| TC-REPORT-WORKBENCH-013 | 通道报备明细当前页有10条数据,点击右上角“全选当页” | 当前页10条全部选中,按钮变为“取消全选”,批量数为10;该按钮与“批量修改状态”保持统一操作区间距;翻页或查询后选择清空,不选中其他页面数据 |
| TC-REPORT-WORKBENCH-017 | 报备资料池当前页存在可生成资料,点击右上角“全选当页” | 仅选中本页全部可生成资料,按钮变为“取消全选”,“预检并生成”显示所选数量且与全选按钮保持统一操作区间距;不再显示表格上方的复选框式“选择本页全部可生成资料”,预检及生成接口契约不变 |
| TC-REPORT-WORKBENCH-014 | 生成同时包含签名和引流资料、覆盖多个通道的批次 | 每个通道生成一份简报;日期取批次生成日期,批次号一致;签名行和引流行分别按已确认格式展示;列表不直接展示文件,须从“报备文件导出”弹窗查看、复制或下载 |
| TC-REPORT-WORKBENCH-015 | 通道配置0个、1个或多个名称为“短信内容”的字段 | 0个时简报短信内容为空;1个时取资料中该字段的实际值;多个时严格按`sortOrder ASC, createdAt ASC`取第一个字段在资料中的实际值,后续同名字段不参与;资料未提供首字段时保持为空,不得使用通道缺省值冒充资料内容 |
| TC-REPORT-WORKBENCH-016 | 批次生成后修改字段库或签名/引流资料 | 历史批次简报仍使用生成时固化的批次快照,不随当前资料改变;不新增数据库migration,不触发短信发送或队列 |
| TC-REPORT-WORKBENCH-018 | 在批次右侧明细滑窗勾选表头全选框 | 当前批次全部通道明细被选中,可点击“批量修改报备状态”;每行仍可单独点击“修改状态”,明细中不显示“导出本条” |
| TC-REPORT-WORKBENCH-019 | 点击批量或单条“修改状态” | 状态选择和修改原因只在独立弹窗中出现;确认后调用既有批量状态接口,写入真实状态记录并刷新批次四项明细数;失败时显示错误,不静默吞错 |
| TC-REPORT-WORKBENCH-020 | 打开“报备文件导出”弹窗并下载单个通道文件 | 每个通道展示一份简报、复制按钮和报备文件下载按钮;XLSX文件名为`YYYY-MM-DD_通道名_批次号.xlsx`,文件来自该批次真实MinIO对象 |
| TC-REPORT-WORKBENCH-021 | 点击报备文件弹窗“全部下载” | 一次下载ZIP,内含每个通道一份XLSX和一份TXT简报;所有条目均按`YYYY-MM-DD_通道名_批次号`命名;任一通道文件缺失、超过100个通道或总文件超过200MB时返回明确错误,不生成不完整压缩包 |
| TC-REPORT-WORKBENCH-022 | 对尚未生成当前材料版本批次的签名,分别从通道报备明细和企业签名的报备状态弹窗将一个通道×运营商组合设为放弃报备,再恢复为其他状态并刷新企业签名页 | 两个入口调用同一真实状态接口并写入各自来源记录;设为放弃后待生成明细总数减少1,恢复后增加1。当前材料版本已经生成成功批次的组合不得因人工改状态重新计入,避免重复生成;企业签名页右上角两个按钮使用统一操作区间距,窄屏可换行且不重叠 |
| TC-REPORT-WORKBENCH-023 | 企业签名页按企业、应用或签名筛选后查看待生成报备资料汇总并点击“查看详情” | 数量按当前筛选范围内仍有至少一个待生成通道目标的签名资料去重,以“份”展示;按钮进入报备资料池,不再进入通道报备明细;明细数仍保留在接口中用于兼容但不在页面展示 |
| TC-REPORT-WORKBENCH-024 | 报备资料池分别准备全部可生成、部分可生成、缺资料、全部放弃、无有效通道及已有同版本批次的资料 | 页面同时显示文字状态;待生成和部分可生成为黄色、资料不完整为红色、已生成为绿色、全部放弃和无有效通道为灰色;部分可生成的阻断原因使用红色提示,不得只依靠颜色表达状态 |
## TC-HIGH-FREQUENCY-QUERY-20260902 高频查询与按需详情
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-HFQ-001 | 企业签名页首次进入、第一页查询、非第一页重置、翻页和排序 | 首次各加载一次签名分页/企业选项/应用选项;后续每项操作只请求一次签名分页,旧响应不得覆盖新条件 |
| TC-HFQ-002 | 打开签名编辑、签名报备状态、引流编辑和引流报备状态 | 分页摘要不含材料、原始任务和目标数组;四个入口分别按ID请求真实详情或目标,保存仍进入原真实后端流程 |
| TC-HFQ-003 | 短信记录查询后打开详情并快速切换或关闭 | 分页响应无submitRecords/receiptRecords/downstreamDeliveries;仅当前消息加载详情与分片审计,迟到响应不得写入下一条或已关闭弹窗 |
| TC-HFQ-004 | 通道列表加载10条数据 | 分页响应自带连接摘要;页面只请求通道分页和发送质量,不再逐行请求连接状态 |
| TC-HFQ-005 | Gateway异常、下游投递、客户端签名/模板、审核和三类报表修改筛选控件 | 控件变化不发业务查询;点击查询应用条件,重置恢复默认,分页沿用上次确认条件 |
| TC-HFQ-006 | 报备任务、状态记录和报备批次在第一页及非第一页点击重置 | 清空草稿及已应用条件并只加载一次第一页,不保留旧筛选结果 |
| TC-HFQ-007 | 通道报备详情首次进入、查询、重置和翻页 | 基础通道/字段/字段库只在进入时加载;查询、重置、翻页只请求一次报备任务分页,不下载全量签名和状态记录 |
| TC-HFQ-008 | 获取企业筛选选项 | 使用轻量options接口,仅返回id/name/code/status且后端过滤deleted,不返回企业认证材料 |
| TC-HFQ-009 | 批量导入解析后切换“保存为可复用映射方案” | 控件使用通用按钮外观、图标和清晰选中态;aria-pressed随状态切换,选中后展示方案名称输入框 |
| TC-HFQ-010 | 查看签名及引流两级操作按钮 | 报备状态、编辑、删除均使用通用sm按钮高度,删除按钮不再高低不齐 |
## TC-ADMIN-ENHANCEMENT-20260904 运营看板与配置交互增强
| 用例ID | 场景 | 预期 |
| --- | --- | --- |
| TC-DASHBOARD-FRAGMENT-001 | 准备当天单分片、长短信多分片及成功/失败回执后打开运营看板,并用PostgreSQL独立聚合复核 | “今日消息分片数”取真实`SmsMessageSegmentAudit`行数;“今日到达率”等于成功到达分片数/发送总分片数,零分片时为0;原总体成功率仍按业务短信统计 |
| TC-DASHBOARD-PROFIT-001 | 准备当天成功短信、返还流水和不同客户价/通道成本快照后打开运营看板 | 今日返还取真实返还流水;今日计收按最终成功短信计费条数×客户价快照;成本按成功分片×通道成本快照,利润与利润率计算一致,收入为0时利润率为0 |
| TC-ENTERPRISE-SIGNATURE-HOVER-001 | 在企业签名列表悬停被截断的签名 | 可查看完整签名、企业、应用、用途、审核状态及创建/更新时间;不增加接口或使用静态数据 |
| TC-NAV-DENSITY-001 | 在桌面端和390px窄屏展开运营端长菜单 | 一级分组、二级菜单上下间距更紧凑,菜单仍可滚动,图标、文本、角标、选中态及点击导航完整可用 |
| TC-SIGNATURE-QUALITY-MATRIX-001 | 打开任一签名发送质量详情,切换整体统计与按引流切分 | 通道×运营商矩阵保留通道、运营商、引流状态、提交次数、成功率、平均到达时间和提交失败数;表头与通道列滚动时可辨识,成功率层级清晰;请求及后端接口不变 |
| TC-REPORT-FIELD-EDIT-001 | 编辑未引用字段的代码、名称、类型和说明后刷新页面 | 修改通过真实PUT接口写入PostgreSQL并记录操作日志,刷新后仍存在;非法代码、空名称、非法类型和重复代码由API拒绝 |
| TC-REPORT-FIELD-EDIT-002 | 编辑已被通道或通用字段引用的字段 | 页面锁定代码和类型,允许修改名称和说明;绕过前端直接修改代码或类型时API返回400,既有通道映射和历史资料不受影响 |
| TC-REPORT-FIELD-ORDER-001 | 分别在签名、引流通用字段中点击上移/下移并刷新 | 仅在当前资料类型内整体重排,真实`sortOrder`按新顺序持久化;并发导致集合变化时明确失败,不产生部分更新 |
| TC-REPORT-WORKBENCH-025 | 在通道报备明细点击单条导出,并分别模拟空请求体和缺失必填资料 | 正常请求以JSON Content-Type提交并下载真实XLSX;空请求体返回可读400而不是500;资料错误明确返回且不静默生成空文件,不改变报备状态或触发短信链路 |