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

267 KiB
Raw Blame History

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-atenant-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. 查看上行关联下发记录。
  • 预期结果:
    • 展示上行内容、接入号、接收时间。
    • 可展示匹配到的下发 messageId。
    • 未匹配上行仍可查询,状态或关联为空。

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 ConnectChannelSubmitCommand.upstream 使用该配置。
    • 通道列表和通道组页面展示的连接状态、连接数和最近错误来自 Gateway 真实上游连接池回写;一次性连接探测成功不能展示为 connected
    • 通道测试短信必须调用真实 NestJS API,创建独立 SmsMessageRecordSmsSubmitRecord,并向 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
  • 前置条件:企业应用已绑定通道组,至少一个目标通道配置 drainageboth 报备字段。
  • 步骤:
    1. 客户端在已审核通过的企业签名中新增引流信息,填写动态字段并提交。
    2. 查询 SmsDrainageInfoDrainageReportMaterialChannelSignatureReportTask(reportType=drainage),并尝试直接调用状态变更接口。
    3. 在运营端“引流信息审核”查看完整资料并通过,再次查询上述表和报备记录。
    4. 分别从企业签名、通道报备详情、报备任务页修改同一引流项在同一通道的状态,并在报备记录页按引流信息筛选。
    5. 客户端修改已通过的引流信息,确认任务冻结后由运营再次审核通过;随后导出任务并导入回执。
    6. 对另一条待审引流信息执行带原因驳回,客户端查看驳回原因。
  • 预期结果:
    • 新建/修改均写独立 SmsDrainageInfoAuditRecord(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. 对照 SmsSubmitRecordSmsReceiptRecord 核验“今日总数/今日发送质量”。
    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 白名单、interfaceEnabledinterfaceType=cmpp20cmppAccountcmppEnterpriseCodepasswordCiphercmppMaxConnections 和通道组绑定;企业应用表单不展示或提交客户侧 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
  • 步骤:模拟带 messageId 的上行事件。
  • 预期结果:
    • 创建 SmsUplinkMessage。
    • tenantId 可通过 messageId 关联。
    • 客户端和运营端均可查询。

TC-SEND-009 未匹配上行短信入库

  • 优先级:P1
  • 步骤:模拟不带 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 客户端连接 17890Source_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 最终失败时,均须真实创建短信记录、SmsReceiptRecordCmppDownstreamDelivery,并向客户下发 undelivered/REJECTD Deliver Receipt,不得仅以 SubmitResp 失败替代回执。
    • Gateway 对每次 submit 记录 submit_receivedsubmit_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. 第一片提交后查询 CmppInboundLongMessageCmppInboundLongMessageSegmentSmsBatchTaskSmsMessageRecord
    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 提交校验;任一校验失败时按真实失败原因拒绝或失败。
    • rejectmanual_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 解析为 ReceiptEventNestJS 入库并更新最终状态。
    8. NestJS 调用 Gateway /downstream/receipt,Gateway 向仍在线的客户连接下发 CMPP Deliver Receipt。
    9. 上游 SMSC 下发普通 deliver 上行;长上行使用 UDH 分片乱序下发时,Gateway 应等待分片齐全后重组成一条 UplinkEventNestJS 入库。
    10. NestJS 调用 Gateway /downstream/uplinkGateway 对可关联 messageId 且客户仍在线的上行下发普通 CMPP Deliver。
    11. 客户断开 CMPP 连接后再次产生 receipt/uplink,确认 NestJS 写入客户侧待投递记录。
    12. 客户重新 bind/loginGateway 按账号拉取 pending 投递并补发,成功后回写 delivered。
  • 预期结果:
    • 客户 bind/login 使用真实数据库账号、密码、状态和 IP 白名单校验。
    • 业务校验失败时不调用上游 submit,不扣费,不伪造成功。
    • API 入队后不依赖同步调用 Gateway /upstream/submitGateway 停止时命令留在 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=2windowSize=1,上游使用可延迟 SubmitResp 的真实测试 SMSC 或本地 gocmpp 模拟 SMSCNestJS API、Redis、PostgreSQL、Go Gateway 均运行真实服务。
  • 步骤:
    1. 通过真实发送链路连续提交 3 条可通过业务校验的短信,保证前 2 条 SubmitResp 暂不返回。
    2. 观察 SubmitCommand.upstream 是否携带 desiredConnections=2windowSize=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_recordsms_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. 从运营端“Gateway提交异常”页面查询异常列表并打开脱敏详情。
    5. 完成风险确认、原因和状态校验后,将该异常命令重新写回 gateway.submit.commands
  • 预期结果:
    • 达到阈值后,Gateway 会把该消息转存为提交异常,而不是永久卡在 PEL。
    • 异常记录来自真实数据库,包含 streamMessageIdmessageId/submitId、失败原因和尝试次数;浏览器端只收到脱敏命令,不收到原始 payload 或密码密钥。
    • 人工重新入队成功后,异常状态更新为 requeued,记录新的 Redis Stream 消息 ID、操作人和原因,并写系统日志。
    • 重新入队后如后续收到真实 SubmitResult,对应异常记录应自动转为 resolved

TC-GW-013 下游客户在线时周期补投与失败封顶

  • 优先级:P0
  • 前置条件:客户应用 CMPP 账号真实可登录;平台已有至少 1 条 CmppDownstreamDelivery.status=pending 的回执或上行待投递记录;Gateway 周期补投任务已启动。
  • 步骤:
    1. 让客户先断线,制造一次投递失败,确认 CmppDownstreamDelivery 留在 pendingretryCount 递增。
    2. 让客户重新 bind,检查 Gateway 是否立即拉取一次 pending 进行补发。
    3. 在客户保持在线的情况下,继续制造一次临时投递失败,等待周期补投触发。
    4. 把同一条待投递连续失败到重试上限。
  • 预期结果:
    • 客户重连后会立即补发 pending 记录;客户在线但上次投递失败时,Gateway 会按周期再次拉取并补投。
    • 重试未超过上限时,CmppDownstreamDelivery 维持 pending,更新 retryCount/nextRetryAt/lastError
    • 达到上限后,记录转为 failed,不再无限 pending,且写真实失败审计日志。
    • 该能力只负责“客户已在线时的平台补投”和“消息不丢”;客户断线后的重新建链仍由客户系统自己负责。

TC-GW-014 运营端下游投递记录查询与人工重投

  • 优先级:P1
  • 前置条件:数据库中已有 CmppDownstreamDelivery 记录,至少覆盖 pendingfaileddelivered 三类状态;运营端已登录;Gateway 控制面和 NestJS API 均为真实服务。
  • 步骤:
    1. 进入运营端“下游投递记录”页面。
    2. 分别按状态、投递类型、应用、关键字进行筛选,检查分页。
    3. 打开一条记录详情,核对 payload、重试次数、最后错误和时间字段。
    4. 对一条 pendingfailed 记录执行人工重投。
  • 预期结果:
    • 页面列表来自真实 /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 记录在前端不可选且后端拒绝并发重投,不能仅依赖按钮禁用。

TC-GW-015 下游投递指数退避

  • 优先级:P1
  • 前置条件:存在一条可重复触发失败的 CmppDownstreamDelivery;系统已配置真实基础重试间隔和最大退避上限。
  • 步骤:
    1. 连续触发同一条下游投递失败 3 到 4 次。
    2. 每次失败后记录 nextRetryAt 与当前时间的差值。
    3. 持续失败直到接近退避上限。
  • 预期结果:
    • nextRetryAt 不是固定 60 秒,而是随失败次数递增。
    • 退避间隔符合基础间隔的 2 倍递增趋势,并在达到最大退避上限后停止继续增大。
    • 达到总重试上限后仍按既有规则转为 failed,不会无限重试。

TC-GW-016 下游投递批量重投

  • 优先级:P1
  • 前置条件:当前页至少有多条 pendingfailedCmppDownstreamDelivery;运营端“下游投递记录”页面和真实批量重投接口可用。
  • 步骤:
    1. 在页面勾选多条可重投记录。
    2. 点击“批量重投”。
    3. 检查后端返回的成功/失败汇总,并刷新列表。
  • 预期结果:
    • 页面调用真实 /api/admin/operations/downstream-deliveries/requeue 批量接口,不是前端逐条伪造结果。
    • 后端逐条执行真实重投,返回 total/successCount/failedCount/results
    • 成功和失败记录都会保留真实后端状态与错误信息;空选择时接口拒绝执行。

TC-GW-017 下游投递告警统一聚合

  • 优先级:P1
  • 前置条件:真实 CmppDownstreamDelivery 中准备阈值内/外的 pending、未超时/已超过 ackDeadlineAtawaiting_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/uplinkpending/delivered/failed
  • 步骤:
    1. 打开运营端“下游投递记录”页面,查看顶部总览卡片、类型分布、重试压力和应用告警排行。
    2. 调用真实 /api/admin/operations/downstream-deliveries/dashboard,核对 summary/typeBreakdown/retryBuckets/topApplications
    3. 切换应用和类型筛选,确认顶部 Dashboard 与下方记录列表同时切换到同一筛选范围。
  • 预期结果:
    • 顶部 Dashboard 必须来自真实聚合接口,不能由当前页列表条目在前端临时汇总。
    • summarytotal/pending/awaitingAck/delivered/failed/unconfirmed/rejected/stalledPending/stalledAck/recentFailed/alertCount 与数据库真实结果一致。
    • typeBreakdown 能正确区分 receiptuplink 的状态分布。
    • retryBuckets 真实反映 pending/failed 记录的重试压力分布。
    • topApplications 使用与 summary.alertCount 相同的时间窗和状态条件统计,各应用告警数之和与同范围总告警一致,并以告警量优先排序。

TC-GW-019 下游在线账号 Presence 持久化

  • 优先级:P1
  • 前置条件:Gateway 已配置真实 REDIS_URL;客户端应用存在可用的 6 位 cmppAccountGateway 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-candidatesGET /downstream/recovery-statuses
    2. 调用 GET /downstream/recovery-overview
    3. 比较总览接口与两个明细接口返回结果。
  • 预期结果:
    • /downstream/recovery-overview 同时返回候选账号列表和恢复状态列表。
    • 总览接口中的 candidates/statuses 与两个明细接口真实结果一致,不允许返回静态拼装样例。
    • 运维可仅通过总览接口快速判断“哪些账号待恢复、哪些账号处于退避或错误状态”。

TC-GW-024 恢复状态回流与运营端展示

  • 优先级:P1
  • 前置条件:Gateway 已产生至少一条真实恢复状态;NestJS API、PostgreSQL 和运营端页面可访问。
  • 步骤:
    1. 触发某账号恢复状态变化,例如 waiting_connectionsuccessfailed
    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_contendedlock_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. 查询 SmsUplinkMessageSmsUplinkMatchCandidateCmppDownstreamDelivery 和操作日志。
    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. 客户端进入发送页选择该模板。
  • 预期结果:
    • 系统识别 nameorderNodatecode 四个变量。
    • 变量不重复,展示顺序与模板中首次出现顺序一致。
    • 审核通过后模板可被选择发送。
    • 系统日志记录模板创建、提交审核、审核通过。

TC-TEMPLATE-002 多变量完整填充发送成功

  • 优先级:P0
  • 前置条件:多变量模板审核通过,签名报备通过,账户余额充足。
  • 步骤:
    1. 选择多变量模板。
    2. 填写全部变量:nameorderNodatecode
    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
  • 前置条件:模板要求 namecodeCSV 只包含 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. 与数据库或明细列表按时间范围聚合结果核对。
  • 预期结果:
    • 今日使用平台配置时区,不错算跨日数据。
    • 近 7 天和近 30 天边界包含/排除规则明确。
    • 趋势图每个点位与明细聚合一致。

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. 执行一次归档任务,再查询 OperationLogOperationLogArchive
    4. 模拟归档插入失败并重新执行。
  • 预期结果:
    • 级别筛选在数据库分页前生效,total、页数和当前页记录准确且排序稳定。
    • 所有接口 pageSize 最大为 100,不存在无界全表返回。
    • 到期日志按 archiveMonth=YYYY-MM 进入归档表,在线表只删除已成功归档的记录,原始 id 和详情不丢失。
    • 归档使用有界小批量和 SKIP LOCKED;归档失败时源日志仍保留,不阻塞正常日志写入。

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 online1/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。
    • 缺陷复测。
  • 建议执行命令:
    npm run spike:contracts
    npm run test:api
    npm run test:gateway
    npm run verify:phase8
    
  • 产出物:
    • 测试执行记录。
    • 缺陷列表和复测结果。
    • 性能 smoke 结果。
    • 未覆盖项和延期说明。

16. 回归执行建议

每次阶段回归至少执行:

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=100NestJS 以通道 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_logsresource 指向 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 创建待审核企业认证、签名、模板、短信审核任务,检查铃铛总数和分类数。 总数等于分类汇总;点击分类跳转并带入筛选;审核完成后数量刷新;新增待办触发站内提醒或浏览器通知。
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 分;仅改变展示精度,不改写数据库成本及历史提交成本快照。

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 小时的短信;启动 API 定时扫描并模拟重复扫描。 两类短信都转为 timeout 并退款;任务进度刷新;同一短信只退款一次;定时扫描默认启用且每 5 分钟执行。
TC-BILLING-014 在运营端充值记录中分别打开整数金额、含1至4位有效小数、负数冲正以及缺少可追溯余额的真实订单回执。 每行提供“查看回执”;弹窗左上只使用系统真实Logo;企业、订单号、时间、备注与数据库订单一致;可追溯订单的入账前余额等于入账后余额减本次变动;无快照时前后余额不得伪造;主金额整数不显示小数,非整数仅显示有效小数,余额仍显示四位精度;正数显示已入账,负数显示已冲正。
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;退款不算收入;成本严格等于各次提交的通道成本单价快照乘以该次成功分片数,失败和未知分片成本为0;通道维度收入只归属最终提交且不重复;利润=消费-成本,利润率计算正确,收入为0时显示0%。
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 connected1/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 在报备字段库分别提交 License2026license_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_IDNestJS 立即终结为 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,打开运营端“Gateway提交异常”,按状态、应用、通道和关键字筛选并查看详情。 记录写入 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-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 或前端静态数据伪造成功。

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 用登录运营用户修改企业应用及其他任一写操作,再查看系统日志;另构造失败请求。 成功写操作均有操作人、路径、资源和结果日志;失败请求不写伪成功日志,日志不含请求体、密码或密钥。

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 分别查询运营端、客户端用户列表和详情,并尝试跨租户访问。 响应不含 passwordHashsessionVersion、密钥或认证内部字段;跨租户查询、更新、改密、禁用和删除由 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=connectedlastHeartbeatAt=NULLconnectedAt 早于心跳阈值的客户接入连接,再触发新连接登记。 陈旧记录在连接数校验前删除,新连接不被错误的 cmppMaxConnections 拒绝;Gateway 能继续读取 Submit。
TC-CMPP-DOWNSTREAM-NULL-002 创建一条刚建立、lastHeartbeatAt=NULLconnectedAt 尚未超过阈值的连接并执行清理。 新连接保留,不因首次心跳尚未写入而误删。
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_DUPLICATEphoneNumber 字段提示,不返回 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:待审签名缺应用、企业资料或资质文件时,预检返回具体blockedReasonsallowedActions不含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/uploadFileObject租户来自会话;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 分别落库 7890CMPPconfig.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,通讯日志分别出现receivedfailed事件,账号可检索、耗时和安全错误可见,数据库无短信业务记录。
  • TC-PROTOCOL-LOG-002:真实CMPP Submit获得供应商SubmitResp;通讯日志可按CMPP、通道到平台、SubmitResp及平台消息号筛选,展示上游消息号和结果码,不包含短信正文或通道密码;同一个SubmitResp只能落一条最终处理结果,不得同时出现receivedsuccess重复行。
  • TC-PROTOCOL-LOG-003:供应商发送DELIVER状态报告;Gateway结构化日志出现收到事件,NestJS通讯日志以一条记录展示该报文及最终处理结果。构造解包失败或API拒绝时必须出现对应失败证据,不能静默返回。
  • TC-PROTOCOL-LOG-004:通过公开HTTP API提交合法和非法请求;通讯日志展示客户到平台的受理或失败状态、请求号、脱敏手机号、业务码和耗时,鉴权头、密钥和正文不得入库。
  • 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,重复回执不得重复投递、扣费或退款。
  • TC-PROTOCOL-LOG-012:供应商长短信每个真实分片分别产生一条平台→供应商通道/CMPP_SUBMIT和一条供应商通道→平台/CMPP_SUBMIT_RESP;内部submit-result聚合回调不得额外落协议日志。
  • TC-RECEIPT-LONG-013:两分片长短信主记录保存首片上游消息号,第二片返回YL:1014等任意非成功状态且首片未回执;系统通过第二片审计识别当前提交尝试,整条短信进入失败/补发或退款终态并只投递一次最终失败回执,不再卡在submitted
  • 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和重试状态。

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-00510000000000视为合法基础格式并继续号段/路由处理;非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 查看Gateway提交异常列表 标题、说明、总数、表格和分页层次清晰,不紧贴容器边框
TC-REPORT-SCOPE-009 检查本轮报表变更范围 T-4未知转失败未实现,日报未知口径和历史数据保持不变

2026-07-26 通道补发归因与发送详情用例

用例编号 场景 预期结果
TC-RETRY-ROUTE-001 直接签名短信在首通道失败,签名在同组备用通道已报备通过 使用短信记录signatureId选中备用通道;无需模板;日志记录开始、选择结果和尝试通道
TC-RETRY-ROUTE-002 模板短信在首通道失败,备用通道不可用或未报备 不创建伪补发;结构化日志记录失败原因、通道组和已尝试通道,不静默吞错
TC-SUBMIT-ATTR-003 同一短信先后经两个通道提交,旧尝试的聚合结果迟到 Gateway携带原始submitIdAPI只更新对应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 三个失败回执并发处理且没有可用备用通道 主记录最终失败;只产生一笔退款交易和一次余额增量,只生成一个CMPP最终失败回执及一个HTTP回调事件
TC-BILLING-IDEM-004 三个线程使用同一短信退款幂等键并发退款 三次调用返回同一交易IDAccountTransaction只有一条,账户余额只增加一次
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/pageSizeitems 不超过页容量。
  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