Files
lislgosms/docs/testing-progress.md
T

119 KiB
Raw Blame History

第一版系统化测试进度

2026-07-09 运营端通道测试短信闭环修复

  • 生产验证发现运营端通道“短信测试”弹窗仅关闭页面,未调用后端;POST /api/admin/channels/:id/test 仍返回 phase-4 placeholder,不创建 SmsMessageRecord/SmsSubmitRecord,也不写入 Gateway SubmitCommand,因此短信记录页面无记录。
  • 已修复为真实链路:前端提交手机号、内容和可选接入号;NestJS 校验通道 active 且存在在线 CMPP 连接后,创建独立 SmsMessageRecordSmsSubmitRecord 和操作日志,并向 BullMQ gateway.submit.queue 与 Redis Stream gateway.submit.commands 写入真实 SubmitCommand。通道测试不绑定企业、企业应用或 SmsBatchTask 发送任务。
  • 测试口径同步:TC-ADMIN-003 增加通道测试短信闭环要求,必须能从页面/API 发起真实测试短信,短信记录页面可查询到对应记录,Gateway submit worker 按通道真实 CMPP 配置消费发送。
  • 已执行:npm --prefix api test -- channels.service.spec.ts --runInBandnpm --prefix api run buildnpm run build。待生产部署后用指定号码做一次真实发送验证,并回查 DB/短信记录。
  • 2026-07-09 追加:按产品边界收窄通道测试短信,SmsMessageRecord/SmsSubmitRecord/SmsReceiptRecord/SmsMessageSegmentAudit 支持 tenantId/batchTaskId 为空;通道测试只记录短信、提交结果和回执,不进入企业账务、发送任务进度、客户侧 Deliver 推送或业务补发。
  • 2026-07-09 追加:生产验证短信进入 Gateway 后出现 SUBMIT_TIMEOUT/context deadline exceeded,上游平台疑似内容乱码;排查确认 API、数据库和 Redis Stream 中中文内容正常,SubmitCommand.cmpp.msgFmt=8,根因为 Gateway 在 CMPP 2.0 通道上仍固定构造 Cmpp3SubmitReqPkt。已修复为按通道 cmppVersion 分别构造 Cmpp2SubmitReqPkt/Cmpp3SubmitReqPkt,并同时处理 CMPP 2.0/3.0 SubmitResp。新增 submit_packet_test.go 覆盖 CMPP 2.0 中文 UCS2 Submit 包类型和长度。
  • 2026-07-09 追加:生产验证 Submit 已 accepted 后未见 SmsReceiptRecord,结合上游为 CMPP 2.0 排查 Gateway readLoop,确认只处理 Cmpp3DeliverReqPktCMPP 2.0 回执 Deliver 即使到达连接也不会 ACK 或进入 receipt 事件链路。已修复为同时处理 Cmpp2DeliverReqPkt/Cmpp3DeliverReqPkt,分别返回 Cmpp2DeliverRspPkt/Cmpp3DeliverRspPkt,并统一 Deliver 解码、回执和上行处理。新增 deliver_test.go 覆盖 CMPP 2.0 DELIVRD 回执写入事件链路。
  • 2026-07-09 追加:运营端短信记录“发送详情 - 通道发送与回执”的“回执码”必须展示通道原始回执码 SmsReceiptRecord.rawStatus,用于和上游平台核对;该字段不再回退展示平台映射状态 receiptStatus 或提交状态。
  • 2026-07-09 追加:生产验证 17317959177 在 DB 中已有 rawStatus=DELIVRD,但页面仍显示空。排查确认页面调用 /admin/send/messages 时生产返回缺少 submitRecords/receiptRecords 明细,而 /admin/operations/messages 返回完整通道发送与回执记录;短信记录页已切换到完整明细接口,并将 UTC ISO 时间按 Asia/Shanghai 展示,避免 16 点多页面显示 8 点多。

2026-07-09 企业应用短信接口开关和接口类型

  • 按设计基线恢复企业应用添加/编辑页“短信接口 开通/关闭”和“接口类型 CMPP/HTTP”;当前第一版只允许 CMPP2.0,HTTP 在页面中禁用,后端拒绝未实现的 interfaceType=http
  • Prisma SmsApplication 新增 interfaceEnabledinterfaceType 持久化字段;企业应用创建、编辑、列表和 CMPP 参数接口均返回真实数据库值。
  • 发送链路新增硬校验:interfaceEnabled=false 时客户端/API 发送、Gateway bind/login 鉴权和 Gateway submit 入站都会拒绝,不进入任务、计费或 Gateway 上游提交。
  • 测试口径同步:TC-ADMIN-018A 覆盖表单保存、CMPP2.0 only、HTTP 禁用和接口关闭后的发送/Gateway 拒绝;TC-GW-006 覆盖 Gateway 鉴权与 submit 对接口开关的校验。
  • 已执行:npm --prefix api run prisma:generatenpm --prefix api test -- sms-config.service.spec.ts send-chain.service.spec.tsnpm --prefix api run buildnpm run buildgit diff --checknpm --prefix api run prisma:migrate:deploy

2026-07-09 通道复制默认停用与真实连接池状态回写修复

  • 生产验证发现当前 3 个赛邮行业通道中有 2 个由首个 active 通道复制而来;数据库 CmppConnectionState 曾显示 3 条通道都为 connected/currentConnections=1,但生产机 ss/netstat 与上游平台都只能看到 1 条真实 TCP 长连接。
  • 根因一:POST /api/admin/channels/:id/copy 会继承源通道 status=active,复制后的通道创建完成后立即参与 Gateway 连接流程,和“复制只是拷贝配置,不应自动上线”的产品预期不符。
  • 根因二:Gateway /connections/connect 之前只做一次性 DialCMPP 探测,探测成功后就把 connected/currentConnections=desiredConnections 回写给 NestJS;该探测连接随后立即断开,导致页面状态与真实上游连接池不一致。
  • 已修复:
    • 通道复制后统一保存为 disabled,复制日志补充 sourceStatuscopiedStatus,避免 active 通道副本自动占用上游连接。
    • Gateway ConnectChannel 改为直接建立/复用真实上游连接池,并由连接池回写 connected/failed/disconnectedcurrentConnections、最近错误和断开时间;连接丢失时状态随真实连接数变化更新。
  • 测试口径同步:
    • TC-ADMIN-003 增加“连接状态必须来自真实上游连接池回写”的要求。
    • TC-ADMIN-016 明确复制 active 通道后副本默认 disabled,且不会立即触发上游真实连接。
  • 已执行:npm --prefix api test -- channels.service.spec.ts --runInBandnpm --prefix api run buildgo test ./internal/control ./internal/upstreamgo build -o ..\\dist\\cmpp-gateway .\\cmd\\gateway

2026-07-09 线上通道 CMPP 版本修复

  • 线上生产验证发现 3 个赛邮行业通道配置均指向 121.40.172.212:7890,其中 2 个已触发 Gateway 真实连接并失败,CmppConnectionState.lastErrorpacketWriter.ReadBytes error: ReadBytes reads 14 bytes, not equal to 16 we expected
  • 生产机到上游 121.40.172.212:7890 TCP 可连接,失败不是 API/Gateway 服务不可用,也不是网络完全不通;结合上游确认参数为 CMPP 2.0,根因定位为通道创建默认 CMPP 3.0 且运营端没有版本选择入口。
  • 已修复通道创建/编辑:运营端新增 CMPP 2.0/3.0 版本选择,默认 2.0NestJS 通道 API 默认 cmppVersion=2.0,并只允许 2.0 或 3.0Prisma SmsChannel.cmppVersion 默认值同步改为 2.0。
  • 测试口径同步:TC-ADMIN-003 要求通道协议默认 CMPP,CMPP 版本默认 2.0,且可选择 2.0 或 3.0;Gateway 连接命令必须携带真实通道版本。
  • 待复测:部署迁移后将线上赛邮通道 cmppVersion 调整为 2.0,并重新触发 Gateway 连接验证。

2026-07-07 企业应用通用下拉与优先队列需求补充

  • 已补充需求文档,明确运营端企业应用新增时选择企业必须使用通用 Select/下拉控件,企业选项来自真实企业 API,支持加载、空态和错误态,不允许静态数组或 localStorage 兜底。
  • 已补充应用发送队列等级需求:短信应用必须保存普通队列/优先队列配置,默认普通队列;优先队列用于验证码、登录确认、交易通知等高时效短信。
  • 已补充发送链路要求:发送入队必须按应用队列等级分流,优先队列在同等业务校验、通道组路由、通道限速和 Gateway 连接条件下插队消费;普通队列不能永久饿死。
  • 已补充测试计划和系统功能用例:
    • 企业应用新增表单企业选择与队列等级真实保存。
    • 优先队列插队发送。
    • SubmitCommand 队列等级契约校验。
    • 混合优先级队列性能 smoke。
  • 当前状态:仅完成需求和测试口径补充,前后端、Prisma、BullMQ/Send Worker、Gateway 队列契约尚未实现,不能记为功能验收通过。
  • 2026-07-07 追加:Prisma 与 NestJS 企业应用 API 已增加 queuePriority 持久化字段,创建/编辑支持 normal/priority 校验,列表/详情随真实应用数据返回;前端表单、发送入队、Send Worker 调度和 Gateway 队列契约仍待后续步骤实现。
  • 2026-07-07 追加:运营端企业应用新增第一步企业选择已改为通用 Select;企业应用新增/编辑表单已按设计锚点恢复“发送队列”单选项,并在保存时真实提交 queuePriority。发送入队、Send Worker 调度和 Gateway 队列契约仍待后续步骤实现。
  • 2026-07-07 追加:发送链路已将应用 queuePriority 固化到 SmsMessageRecordBullMQ 入队按 priority/normal 写入不同 job prioritySubmitCommand 契约、示例和 Go Gateway 队列结构已增加 queuePriority;当前实现覆盖优先队列插队的基础能力,持续高优先级流量下普通队列防饥饿策略仍需后续压测和调度增强。
  • 2026-07-07 追加:Gateway 队列契约第 8 步已独立校验,SubmitCommand schema/example 要求 queuePriorityGo Gateway SubmitCommand 结构可反序列化该字段,并通过 npm run spike:contractsnpm run spike:gateway
  • 2026-07-07 追加:第 9 步收口验证通过:npm --prefix api run prisma:generatenpm --prefix api test -- sms-config.service.spec.ts send-chain.service.spec.ts --runInBandnpm run spike:contractsnpm run spike:gatewaynpm --prefix api run buildnpm run build 均通过;前端 build 仅保留既有 Vite chunk size warning。

2026-07-06 企业管理列表字段回归

  • 按设计锚点 131f344a^ 恢复运营端企业管理列表字段:企业 ID、企业名称、当前余额、透支限额、今日消费、企业状态、操作。
  • 新增真实后端接口 GET /api/admin/tenants/management-list,由 NestJS/Prisma 聚合租户、企业账户和当天短信消息金额;前端不再用静态字段或本地假数拼出今日消费。
  • 当前余额来自 TenantAccount.balanceCents,透支限额来自 TenantAccount.creditCents,今日消费来自当天 SmsMessageRecord.amountCents 汇总。
  • 已执行:
    • npm --prefix api test -- tenants.service.spec.ts --runInBand
    • npm --prefix api run build
    • npm run build
  • 验证结果:API 单测、API build、前端 build 均通过;前端 build 仅保留既有 Vite chunk size warning。

2026-07-06 企业编辑页和上传链路修复

  • 按设计锚点 131f344a^ 恢复运营端企业新建/编辑页字段:企业照片、企业名称、统一社会信用代码、省/直辖市、市/区、通讯地址、联系人姓名、身份证号、手机号、电子邮箱。
  • 运营端企业新建/编辑页移除偏离锚点的企业编码、企业状态字段;后端 POST /api/admin/tenants 支持不传企业编码,并按信用代码/企业名生成真实唯一企业编码。
  • 修复营业执照/企业照片上传 500
    • 启动脚本在 MinIO 不可用时启用本地对象存储 .local-data/object-storage,文件仍通过真实 NestJS 上传接口写入对象存储目录并创建 FileObject 数据库记录。
    • 文件上传接口缺少 multipart 文件时返回 400。
    • FileObject.sizeBytes 返回前转换为字符串,避免 Prisma BigInt JSON 序列化 500。
  • 已执行:
    • npm --prefix api test -- tenants.service.spec.ts files.service.spec.ts --runInBand
    • npm --prefix api run build
    • npm run build
    • POST http://localhost:3000/api/admin/files/upload multipart smoke
  • 验证结果:API 单测、API build、前端 build 和真实上传 smoke 均通过;前端 build 仅保留既有 Vite chunk size warning。

2026-07-06 本地 MinIO 启动脚本补充

  • tools/start-local.ps1 补充本地 MinIO 启动流程:Docker Compose 优先;无 Docker 时查找 C:\cmpp-platform-local\minio.exeC:\cmpp-platform-local\minio\minio.exe 或 PATH 中的 minio.exe,使用 C:\cmpp-platform-local\minio-data 作为数据目录,监听 9000/9001
  • package.json 新增 npm run start:local:minio,用于单独启动本地 MinIO。
  • MinIO 不可用时,脚本仍会明确启用 .local-data/object-storage fallback;启动完成提示会区分 MinIO 是否真实运行。
  • MinIO 模式下对象存储服务会在上传/预签名前自动确认并创建 cmpp-platform bucket。
  • 已执行:
    • npm --prefix api run build
    • npm run start:local -- -SkipApi -SkipWeb -SkipMigrate
  • 验证结果:API build 和启动脚本 smoke 通过;当前机器未发现 minio.exe,脚本按预期提示并启用本地对象存储 fallback。

2026-07-06 应用级 CMPP 连接和签名/引流表单基线

  • CMPP 连接状态从企业/租户级聚合改为应用级独立连接:
    • CmppConnectionState 新增 applicationId 并关联 SmsApplication
    • 企业应用列表和连接详情只读取当前应用的 CmppConnectionState
    • 运营端断开连接只操作当前应用下的连接。
    • Gateway 连接上报 POST /api/admin/gateway/connections 支持 applicationId,新连接可按应用独立记录。
  • 运营端添加/编辑短信签名页面按设计锚点 131f344a^ 补齐字段:签名依据、短信签名、资质凭证、公司名称、统一社会信用代码、法人姓名、法人身份证号、法人身份证照片、责任人姓名、责任人手机号、责任人身份证号、责任人身份证照片、三网报备状态。
  • 运营端添加/编辑引流信息页面按设计锚点 131f344a^ 补齐字段:引流信息、字段名称 1-10、文件上传、三网报备状态、提交时间、备注。
  • 签名和引流表单仍使用真实 enterprise-signatures 后端接口保存;扩展字段写入 SmsSignature.drainageInfo JSON,文件上传走真实 admin/files/upload 并保存 FileObject 引用。
  • 已执行:
    • npm --prefix api run prisma:generate
    • npm --prefix api test -- sms-config.service.spec.ts channels.service.spec.ts --runInBand
    • npm run build
    • npm --prefix api run build
    • npm --prefix api run prisma:migrate:deploy
  • 验证结果:Prisma Client 生成、API 针对测试、API build、前端 build 和本地 PostgreSQL migration deploy 均通过;前端 build 仅保留既有 Vite chunk size warning。

2026-07-01

新增测试基础

  • API 引入 Jest + ts-jest。
  • API 新增脚本:
    • npm --prefix api test
    • npm --prefix api test -- <spec>
  • 根目录新增脚本:
    • npm run test:api
    • npm run test:gateway

新增 API 测试

测试文件 覆盖范围
api/src/risk-review/risk-review.service.spec.ts 最大号码数、重复率、非法号码率、黑名单率、模板变量异常、非工作时间营销大批量、短时间频控、直接拒绝、人工审核。
api/src/billing/billing.service.spec.ts 70/67 费用预估、余额/授信/套餐检查、充值、冻结、扣费、释放、退款、调整、短信计费记录。
api/src/send-chain/send-chain.service.spec.ts 批量任务创建、手机号去重拆分、发送入队、Gateway SubmitCommand 投递、submit result、receipt、uplink、72 小时未知转超时。
api/src/channels/channels.service.spec.ts 通道创建、路由规则、报备材料 upsert、报备任务创建、导出、回执导入、签名报备状态同步。
api/src/operations/operations.service.spec.ts 发送记录查询过滤、dashboard、statistics、trace、reconciliation。

新增 Gateway 测试

  • gateway/internal/tracker/tracker_test.go 增加并发 SEQID/MSGID/GatewayMessageID 映射测试。
  • 既有 Gateway 测试继续覆盖:
    • tracker 基础映射和未知 submit resp。
    • reconnector 重连和最终错误返回。
    • health handler。
    • gocmpp adapter。
    • spike simulator。

已执行命令

npm --prefix api test -- risk-review.service.spec.ts
npm --prefix api test -- billing.service.spec.ts
npm --prefix api test -- send-chain.service.spec.ts
npm --prefix api test -- channels.service.spec.ts
npm --prefix api test -- operations.service.spec.ts
npm run test:api
npm run verify:phase8
npm run build
npm run spike:gateway
npm --prefix api test
npm run test:gateway
node tools/smoke/real-env-smoke.mjs
$env:API_PORT='3101'; npm --prefix api run start:dev
node <inline step4 precheck smoke>
$env:API_PORT='3101'; $env:API_ENABLE_SEND_WORKER='true'; npm --prefix api run start:dev
node <inline step5 send-chain smoke>
node <inline step5 schedule probe>
$env:API_PORT='3101'; npm --prefix api run start:dev
node <inline step6 billing/reconciliation smoke>
node <inline step6 auto-billing probe>
npm run spike:contracts
npm run test:gateway
$env:API_PORT='3101'; $env:API_ENABLE_SEND_WORKER='true'; npm --prefix api run start:dev
node <inline step7 channel/cmpp status smoke>
npm run verify:phase8
npm run test:api
npm run test:gateway

当前结果

  • API Jest5 个 test suite 通过,22 个测试通过。
  • Gatewaynpm run spike:gateway 通过。
  • 阶段 8 完整验证:npm run verify:phase8 通过,其中 BullMQ spike 15000 条消息、并发 500、端到端 705.65 TPS,满足 500 TPS。
  • 前端 build 通过,仍存在既有 Vite chunk size warning。
  • API Jest 使用 mock 依赖的结果仅代表单元/轻集成测试通过;系统功能验收仍要求 PostgreSQL/Redis/MinIO 和真实 API smoke 通过。
  • 真实 PostgreSQL/Redis/MinIO smoke 通过:
    • PostgreSQL localhost:5432、Redis localhost:6379、MinIO localhost:9000/9001 端口均连通。
    • npm --prefix api run prisma:migrate:deploy 通过,无待应用迁移。
    • API 以真实 .env 启动,GET http://127.0.0.1:3101/api/health 返回 ok
    • tools/smoke/real-env-smoke.mjs 已补充最小幂等 seed,并验证登录、企业/客户、人工充值、余额检查、发送任务、MinIO 预签名上传、运营日志、发送链路追踪和账务对账聚合。
  • 第 4 步发送前置校验 smoke 通过:
    • TC-TEMPLATE-001TC-TEMPLATE-002TC-TEMPLATE-003 / TC-RISK-005TC-RISK-001TC-RISK-002TC-RISK-003TC-RISK-004TC-BILLING-001 / TC-TEMPLATE-005TC-BILLING-PRECHECK-001 均通过。
    • 记录两个接口健壮性问题:不存在的 reviewerId、不存在的 createdById 会触发数据库外键 500。
    • 客户侧导入发送、非法字符展示、敏感词接入发送前风控当前缺少完整入口,已在 docs/testing-execution-step-4.md 记录为阻塞缺口。
  • 第 5 步发送链路 smoke 通过:
    • TC-SEND-001 / TC-SEND-002、旧版 TC-SEND-003 / TC-SEND-004TC-SEND-005TC-SEND-006TC-SEND-007TC-SEND-008、旧版 TC-SEND-009 / TC-SEND-010 均通过。
    • 2026-07-03 新增的通道组真实路由用例 TC-SEND-010TC-SEND-018 尚未开发和执行,不能沿用旧 smoke 通过结论。
    • 使用真实 Redis/BullMQ 和 API_ENABLE_SEND_WORKER=true 验证了任务创建、号码去重拆分、自动入队、Worker 消费、submit record、submit result、receipt、uplink、72 小时 unknown 转 timeout、客户端/运营端任务查看。
    • 定时发送探测发现 scheduledAt/sendMode=scheduled 会被接口忽略,任务直接变为 queued,已在 docs/testing-execution-step-5.md 记录为功能缺口。
  • 第 6 步计费和对账 smoke 通过:
    • TC-BILLING-001TC-BILLING-002 / TC-RECHARGE-001TC-BILLING-003TC-BILLING-004 / TC-BILLING-005 / TC-BILLING-006 / TC-BILLING-007TC-BILLING-008 / TC-RECON-001 seedTC-RECON-001TC-DASHBOARD-001 / TC-STAT-001TC-TRACE-001TC-BILLING-009 均通过。
    • 验证了费用预估、人工充值、余额检查、冻结、扣费、释放、退款、短信计费记录、账务流水、dashboard/statistics、trace 和 reconciliation。
    • 自动计费探测发现发送任务不会自动生成短信计费记录、账户交易流水,消息金额默认为 0,已在 docs/testing-execution-step-6.md 记录为发送计费集成缺口。
  • 第 7 步客户/通道 CMPP 连接状态和 Gateway smoke 通过:
    • TC-GW-CONTRACT-001TC-GW-001TC-GW-002TC-GW-003TC-GW-004TC-CMPP-STATUS-001 / TC-CHANNEL-001TC-CHANNEL-ROUTE-001TC-CHANNEL-METRIC-001TC-CMPP-SESSION-001 / TC-CONNECTION-COUNT-001TC-CMPP-STATUS-002 / TC-OPERATIONS-MONITOR-001TC-GATEWAY-EVENT-001 均通过。
    • 验证了 Gateway 队列契约、Go Gateway health/重连/tracker/gocmpp 模拟器、通道创建、路由、metrics、submit session、通道维度监控和 Gateway submit event trace。
    • 客户级 CMPP 连接状态、客户连接数量、通道连接列表和 Gateway health 聚合到运营 dashboard 尚缺少一等 API,已在 docs/testing-execution-step-7.md 记录。
  • 第 8 步最终回归通过:
    • npm run verify:phase8 通过,BullMQ 15000 条消息、并发 500、端到端 TPS 668.71,满足 500 TPSPrisma generate、API build、前端 build 均通过。
    • npm run test:api 通过,5 个 test suite、22 个 tests 全部通过。
    • npm run test:gateway 通过,Go Gateway health、connection、tracker、cmpp、spike 测试全部通过。
    • 最终归档见 docs/testing-execution-step-8.md

已知缺口

  • 暂未新增前端测试框架,前端仍以 npm run build 作为 smoke。
  • BullMQ 真实链路仍由 npm run spike:bullmq 覆盖,不在 Jest 内启动 Redis。
  • Gateway 未接真实运营商 SMSC;真实 CMPP 互通需要运营商测试环境后补充联调记录。
  • 客户侧导入发送、短信内容非法字符展示和敏感词发送前拦截尚未形成完整业务入口。
  • 定时短信发送缺少计划发送时间字段、scheduled 状态、到点触发和取消接口。
  • 发送链路尚未自动接入计费闭环,发送任务不会自动冻结/扣费/生成短信计费记录。
  • 客户/通道 CMPP 连接状态和连接数量尚未形成运营端/客户端一等接口,Gateway health 未聚合到 NestJS dashboard。

2026-07-01 缺口修复复测

本轮修复范围

  • P0 定时短信发送闭环:
    • SmsBatchTask 增加 scheduledAtcanceledAt 字段和 status/scheduledAt 索引。
    • CreateBatchTaskDto 支持 sendMode=scheduledscheduledAt
    • 新增定时任务取消和到点触发入口:POST /api/client/send/batch-tasks/:id/cancelPOST /api/admin/send/scheduled/dispatch-due
    • 到点触发前重新校验企业状态、认证状态、应用状态、模板审核状态、签名审核/报备状态和账户余额。
  • P0 发送链路自动计费闭环:
    • 发送创建时按通道单价写入消息计费条数、单价和金额。
    • 立即发送创建时执行账户检查和冻结;定时发送创建时检查余额,到点再冻结。
    • submit accepted 后生成/更新 SmsBillingRecord、写入 charged 流水;submit rejected/timeout 释放冻结;失败回执和 72 小时超时执行退款。
  • P0 发送前内容校验:
    • 风控评估接入敏感词字典和控制字符扫描。
    • variableIssues 扩展为 { variables, content },同时保留变量异常和内容异常证据。
    • emoji/UCS2、多空格和换行不直接拒绝,继续通过 70/67 字符长度影响计费。
  • P1/P2 补齐:
    • 新增企业认证模型/API,提交、审核通过、驳回会同步 Tenant.certificationStatus,发送前强制认证通过。
    • 新增客户侧导入预览/确认入口,覆盖 CSV/TXT 文本解析、20MB 限制、重复/非法/黑名单/变量缺失提示。
    • 新增客户/通道 CMPP 连接状态模型/APIGateway 或本地 Gateway 模拟器可通过真实 API 回写连接状态,运营 dashboard 聚合连接状态。
    • 新增应用密钥重置、应用/签名/模板状态变化、通道启停接口,并写入系统日志。
    • 无效 createdByIdreviewerId 改为明确 400,不再冒泡数据库外键 500。

新增/更新测试

测试文件 新增覆盖
api/src/send-chain/send-chain.service.spec.ts TC-SCHEDULE-001 到 006、TC-BILLING-AUTO-001 到 004、TC-IMPORT-001 到 006 子集、企业认证/状态阻断。
api/src/risk-review/risk-review.service.spec.ts TC-CONTENT-001 到 004 子集、敏感词和控制字符拦截、无效 createdById。
api/src/certification/certification.service.spec.ts TC-CERT-001 到 004 子集,认证提交、审核、驳回和租户状态同步。
api/src/channels/channels.service.spec.ts 通道启停日志、通道连接状态 upsert/list、客户连接状态 list。
api/src/sms-config/sms-config.service.spec.ts 无效 reviewerId 400,避免审核外键 500。
api/src/operations/operations.service.spec.ts Dashboard Gateway 连接状态聚合。

已执行命令

npm run prisma:generate
npm --prefix api test -- send-chain.service.spec.ts risk-review.service.spec.ts sms-config.service.spec.ts
npm --prefix api test
npm --prefix api run build
npm --prefix api run prisma:migrate:deploy
npm run verify:phase8
npm run test:api
npm run test:gateway

当前结果

  • Prisma Client 生成通过。
  • 新增迁移已应用到真实 PostgreSQL
    • 20260701103000_add_scheduled_sms_fields
    • 20260701110000_add_certification_and_connection_state
  • API build 通过。
  • API Jest7 个 test suite 通过,34 个测试通过。
  • 最终回归通过:
    • npm run verify:phase8 通过,BullMQ 15000 条消息、并发 500、端到端 TPS 608.93,满足 500 TPSPrisma generate、API build、前端 build 均通过。
    • npm run test:api 通过,7 个 test suite、34 个 tests 全部通过。
    • npm run test:gateway 通过,Go Gateway health、connection、tracker、cmpp、spike 测试全部通过。

剩余说明

  • 客户侧导入当前提供 API 级文本预览/确认闭环;浏览器端真实文件选择、GBK 二进制转码和错误文件下载仍需前端/E2E 后续覆盖。
  • Gateway 连接状态通过 NestJS API 支持 Go Gateway 或本地模拟器回写;真实运营商 SMSC 联调仍需运营商测试环境。

2026-07-02 运营端优化转真实后端补齐

本轮修复范围

  • 修正测试策略说明:mock 仅作为单元/轻集成测试替身,不能作为业务完成标准;新增页面能力必须接 NestJS API、Prisma/PostgreSQL 和必要操作日志。
  • 通道管理补齐真实 API
    • POST /api/admin/channels/:id/copy:复制通道配置、通道报备字段和该通道签名报备材料,写入操作日志。
    • DELETE /api/admin/channels/:id:软删除通道,避免破坏历史发送/报备外键。
    • GET /api/admin/channels/:id/connection-logs:基于 OperationLogCmppConnectionState 查询连接日志;保留 /link-logs 兼容旧前端。
  • 安全控制补齐真实 API:敏感词、全局黑名单、企业黑名单支持 keyword/status 查询、创建、启停/软删除,并写操作日志。
  • 企业黑名单修正为企业应用级黑名单:Prisma EnterpriseBlacklist 新增 applicationId 并改为 applicationId + phoneNumber 唯一;运营端页面按企业和短信应用新增/搜索;发送预览和风控只命中当前应用的 active 黑名单。
  • 模板审核补齐真实查询:运营端模板列表支持 keyword/status,并返回企业、应用、签名信息;前端模板审核页已改为调用真实 API。
  • 运营端企业模板管理新增短信模板时,后端直接写入 auditStatus=approved;短信模板审核页展示为“已通过”,客户端自行提交模板仍保留审核流。
  • 企业认证审核补齐真实查询:列表支持 keyword/status,详情返回企业信息和认证 materials;前端企业认证审核页已改为调用真实 API。
  • 前端新增 /api Vite 代理和 src/api/adminApi.ts,通道管理、模板审核、企业认证审核应调用真实 API;API 不可用时页面应展示错误态或空态,静态兜底不能作为验收通过依据。

新增/更新测试

测试文件 新增覆盖
api/src/channels/channels.service.spec.ts 通道复制、软删除、连接状态日志写入、连接日志查询。
api/src/dictionaries/dictionaries.service.spec.ts 敏感词、全局黑名单、企业黑名单查询、创建、软删除和操作日志。

已执行命令

npm --prefix api run build
npm --prefix api test
npm run build

当前结果

  • API build 通过。
  • API Jest8 个 test suite 通过,38 个测试通过。
  • 前端 build 通过,仍存在既有 Vite chunk size warning。

文档同步

  • 已将今天的客户端和运营端优化要求补入 docs/first-version-development-requirements.md
    • 去除客户端独立账号设置菜单,改为头像下拉承载退出登录和修改密码。
    • 明确模板审核搜索、企业认证详情审核、企业应用 CMPP 连接数/连接详情/参数复制、通道复制、通道软删除、通道连接日志、安全控制 CRUD、系统日志分页等均需要真实后端 API 支撑。
    • 补充客户端用户、运营端企业认证、通道、连接、字典、安全控制、系统日志等接口范围。
    • 修正 Codex 执行模板,明确 mock、localStorage 或静态数据不得作为真实开发完成标准。
  • 已将今天的验收点补入 docs/system-functional-test-cases.md
    • 新增 TC-CLIENT-010 到 TC-CLIENT-011。
    • 新增 TC-ADMIN-014 到 TC-ADMIN-022。

2026-07-02 新增浏览器和业务闭环用例执行

执行环境

  • APInpm --prefix api run start:dev,监听 http://localhost:3000/api
  • 前端:npm run build 后使用 npm run preview -- --port 4173,访问 http://localhost:4173
  • Browser 插件:可连接本地 tab,但对 Vite dev 页 Page.navigate 超时;改用临时目录 Playwright 包加本机 Chrome 执行浏览器 smoke,未修改项目依赖。
  • PostgreSQL:本地 localhost:5432 可用,API smoke 使用真实数据库。

已执行命令

npm run build

# 临时目录 C:\Users\hectorzhao\AppData\Local\Temp\cmpp-pw-smoke
npm init -y
npm install playwright --no-save
node <browser-and-api-smoke>

通过用例

用例 结果 覆盖点
TC-DASHBOARD-CLIENT-UI UI-SMOKE PASS / BACKEND GAP 客户端 Dashboard 可渲染账户余额、今日发送、账户状态,但页面数据仍需确认全部来自真实 API。
TC-DASHBOARD-ADMIN-UI UI-SMOKE PASS / BACKEND GAP 运营端 Dashboard 可渲染今日发送总量、总体成功率、企业消费排行、通道运行,但当前源码仍存在 mock 数据路径。
TC-BILLING-MANUAL-UI UI-SMOKE PASS / BACKEND GAP 运营端人工充值弹窗填写后,前端表格新增企业、金额、操作人和备注;该页面当前未调用真实充值 API。
TC-LOG-ADMIN-UI UI-SMOKE PASS / BACKEND GAP 运营端系统日志页面可展示人工充值、账户计费等记录;页面数据仍需接真实日志 API。
TC-LOG-CLIENT-UI UI-SMOKE PASS / BACKEND GAP 客户端系统日志页面可渲染并展示客户侧日志记录;页面数据仍需接真实日志 API。
TC-CMPP-STATUS-UI UI-SMOKE PASS / BACKEND GAP 企业应用管理可展示 CMPP 状态和连接数量并打开连接详情;页面当前仍有本地初始数据路径。
TC-FRONTEND-CONSOLE PASS 关键页面无相关 console error/pageerror;仅忽略 favicon 404。
TC-BILLING-MANUAL-API PASS 人工充值无需审批:确认后账户余额、短信条数、充值单、账户流水和 Dashboard transactions 聚合同步更新。
TC-CMPP-STATUS-API PASS 通道创建、Gateway 连接状态回写、按通道/客户查询、连接日志和 Dashboard gatewayConnections 聚合通过。

发现和说明

  • npm run dev 在本机 5173 被占用后切换到 5174Vite 首次依赖 bundling 长时间未完成,浏览器看到白屏;生产构建和 preview 渲染正常。
  • 运营端人工充值页面当前是前端本地状态 smoke,不能作为系统功能通过;真实入账闭环通过 POST /api/admin/billing/manual-recharges 验证。
  • 人工充值不需要审批,测试口径已同步修正为“有权限确认即入账,不产生 pending 审批态”。

真实后端缺口和 Bug 清单

编号 严重级别 问题 证据 期望修复
BUG-FE-001 P0 运营端人工充值页面未调用真实后端,提交后只更新前端本地表格状态。 src/apps/admin/AdminRechargeRecordsPage.tsx 使用 rechargeRecordsSeeduseStatesubmitManualRechargesetRecords 页面提交调用 POST /api/admin/billing/manual-recharges,成功后刷新真实充值记录、账户余额、流水和日志。
BUG-FE-002 P0 运营端 Dashboard 仍使用 mock service 和静态排行,不能证明真实统计准确。 src/apps/admin/AdminHome.tsx 引用 adminServicehourlySendTrendauditTrend,指标从前端数组计算。 接入 GET /api/admin/operations/dashboard/statistics 或拆分真实统计接口,所有卡片和排行从 API 返回。
BUG-FE-003 P0 客户端 Dashboard 仍使用 mock service,余额、发送量、最近充值等不是实时后端数据。 src/apps/client/ClientHome.tsx 使用 clientService.getOverview() 和客户端 mock 数据。 接入客户端真实 dashboard、账户、任务、充值流水 API,点击明细继承真实筛选条件。
BUG-FE-004 P0 客户端和运营端系统日志页面仍有静态数据路径,无法验证真实日志、分页、筛选和租户隔离。 src/apps/admin/AdminSystemLogsPage.tsxsrc/apps/client/ClientSystemLogsPage.tsx 页面 smoke 可展示,但未证明调用真实日志 API。 接入真实日志 API,支持分页、筛选、详情、租户隔离,失败动作也可查。
BUG-FE-005 P0 企业应用 CMPP 状态和连接详情页面仍使用本地初始数据,未读取真实连接状态 API。 src/apps/admin/AdminEnterpriseApplicationsPage.tsx 使用 initialSmsAppssetSmsApps,连接删除也是本地状态变更。 接入企业应用、连接状态、连接详情、连接删除/断开真实 API 或 Gateway 回写接口。
BUG-API-001 P1 通道创建参数缺失时返回 Prisma 500,而不是业务 400。 浏览器 smoke 第一轮 POST /api/admin/channels 缺少 code/gatewayHost/gatewayPort/account/passwordCipher/srcIdAPI 返回 Internal server error。 为通道创建 DTO 增加校验,缺失必填字段返回 400 和可读错误,并写失败日志。
BUG-DEV-001 P1 npm run dev 在 5173 被占用后切到 5174Vite 依赖 bundling 长时间未完成,浏览器看到白屏。 本轮浏览器测试中 5174 HTTP 后续可达,但首次打开截图为空白;生产 build/preview 正常。 检查 Vite dev 依赖预构建和端口占用问题,确保开发模式可稳定渲染。
BUG-SEND-001 P0 发送路由规则允许直接绑定单个通道,违反“规则只能绑定通道组”的业务约束。 SendChainService.selectChannel() 当前存在 route?.channel ?? route?.group... 路径;ChannelRouteRule 模型也保留 channelId 字段。 路由规则只能表达应用到通道组的绑定关系;发送链路必须从企业应用绑定的运营商通道组内选路,不允许规则直接指定单个通道。
BUG-SEND-002 P0 未命中路由规则时会 fallback 到全局第一个 active 通道,可能把短信发到未配置给该企业/应用的通道。 SendChainService.selectChannel() 未找到 route 后执行 smsChannel.findFirst({ where: { status: 'active' } }) 企业应用没有配置对应运营商通道组或无可用通道时,短信直接 failed;不得进入 pending/delayed,不得 fallback 到其他 active 通道,需记录 trace/日志。
BUG-SEND-003 P0 发送选路只判断通道业务状态 active,不判断 CMPP 真实连接状态。 selectChannel() 只检查 SmsChannel.status,未查询 CmppConnectionState.status/currentConnections/lastHeartbeatAt/lastError 选路必须跳过离线、认证失败、心跳超时、重连中或 currentConnections=0 的通道;至少 1 条连接 connected 且心跳正常才可发送,连续 3 次心跳失败进入重连且不可选。
BUG-SEND-004 P0 通道组主通道提交失败、超时或回执失败后不会切换到下一个通道补发。 handleSubmitResult()handleReceipt() 只更新状态、释放/退款和刷新进度,没有重新选路或创建补发记录;retry.maxAttempts 目前未形成业务补发闭环。 除 unknown、超过 72 小时、超过通道组补发时间上限或通道组关闭补发外,submit rejected/timeout、连接断开、未提交成功、receipt failed 均需补发;省网失败后立即走全国通道,全国通道按优先级继续补发,最终成功只按企业应用客户费率扣一次。
BUG-SEND-005 P0 通道组省网/全国路由没有接入真实发送链路,手机号段库也未参与归属地识别。 SmsChannelGroupItemChannelRouteRule 虽有 carrier/province 字段,PhoneSegmentprefix/carrier/province/city,但 SendChainService.selectChannel() 未读取 message.phoneNumber、未查询 phoneSegment,只按优先级取第一个 active 通道;前端 AdminChannelGroupFormPage 的省网/全国配置仍为本地 useState 发送前按可配置号码前缀正则识别运营商,识别失败走移动通道组;按手机号段库识别省份和城市,省份识别失败走对应运营商全国通道;通道需支持移动/联通/电信/三网和全国/单省发送地区,三网作为通配。
BUG-SEND-006 P0 企业应用缺少按运营商绑定多个通道组和保存校验的真实闭环。 当前发送链路只按 tenantId/applicationId 查询单一路由规则;未体现一个应用分别绑定移动、联通、电信通道组,也未强制至少绑定一个通道组后才能保存。 企业应用可分别绑定移动、联通、电信通道组;一个都不绑定时 UI 不允许保存,发送时直接 failed;移动、联通、电信短信按识别结果进入对应通道组。

2026-07-03 通道组真实路由和补发修复

本轮修复范围

  • BUG-SEND-001:后端 createRouteRule 禁止直接绑定单通道,路由规则只能绑定应用、运营商和通道组;发送链路不再读取 route.channel
  • BUG-SEND-002:发送链路未找到企业应用对应运营商通道组或无可用在线通道时,短信直接标记 failed,不再 fallback 到全局第一个 active 通道。
  • BUG-SEND-003:发送选路加入 CMPP 连接状态过滤,通道必须业务 active、连接 connecteddesiredConnections > 0currentConnections > 0 才可选;online/open 仅作为旧 Gateway 回写兼容词入库归一化。
  • BUG-CMPP-STATUS-001:新建/启用通道后若 Gateway 连接请求长时间无回写,API 后台兜底任务会将超过 30 秒的 connecting 连接标记为 failed,写入超时原因和连接日志,避免页面长期停留“连接中”。
  • BUG-SEND-004submit rejected、submit timeout、回执 failed 等失败场景会在补发开启且未超过时间限制时,排除已尝试通道并切换到同一通道组全国通道继续提交;unknown、超过 72 小时、超过通道组补发上限或关闭补发时不补发。
  • BUG-SEND-005:新增 PhoneCarrierRule 运营商前缀正则配置,发送前先识别运营商,识别失败默认移动;手机号段库用于识别省份,省份识别失败走对应运营商全国通道;通道新增 sendRegion,支持全国或单省。
  • BUG-SEND-006:企业应用创建页面可分别选择移动、联通、电信通道组,一个都不选时 UI 阻止保存;创建应用成功后写入真实通道组路由规则。
  • 前端配置补充:通道创建支持移动、联通、电信、三网和发送地区;手机号段库新增“运营商区分规则”tab。

新增/更新测试

测试文件 新增覆盖
api/src/send-chain/send-chain.service.spec.ts 应用运营商通道组路由、在线连接过滤、失败不 fallback、补发关闭时释放/退款。
api/src/channels/channels.service.spec.ts 通道发送地区默认值、通道组补发配置、禁止单通道路由规则。

已执行命令

npm --prefix api run prisma:generate
npm --prefix api test -- send-chain.service.spec.ts channels.service.spec.ts --runInBand
npm --prefix api test
npm --prefix api run build
npm run build
npm run verify:phase8                         # 阻塞:BullMQ spike endToEndTps 未达到 500
npm run spike:bullmq                          # 复跑仍未达到 500

当前结果

  • Prisma Client generate:通过。
  • API Jest10 个 test suite 通过,50 个测试通过。
  • API build:通过。
  • 前端 build:通过,仍存在既有大 chunk warning。
  • npm run verify:phase8:未通过,阻塞在 spike:bullmq 性能阈值;第一次 endToEndTps=464.58,复跑 npm run spike:bullmq endToEndTps=495.97,第三次 endToEndTps=477.17,均低于 500 TPS 阈值。
  • 尚未执行真实 PostgreSQL/Redis/Gateway 端到端 smoke;需在生产验证或本地真实服务环境中覆盖 TC-SEND-010TC-SEND-018TC-CMPP-STATUS-008A

2026-07-02 真实后端缺口修复

本轮修复范围

  • BUG-FE-001:运营端充值记录页移除 rechargeRecordsSeed 验收路径,加载真实租户、人工充值记录、账户余额和账户流水;确认人工充值调用 POST /api/admin/billing/manual-recharges,成功后刷新真实记录、账户、流水,并由后端写 billing.manual_recharge 操作日志,不产生 pending 审批态。
  • BUG-FE-002:运营端 Dashboard 移除 adminService、静态趋势和前端排行计算,改为调用 GET /api/admin/operations/dashboard/statistics、真实通道 API 和真实账户聚合。
  • BUG-FE-003:客户端 Dashboard 移除 clientService、静态趋势和本地 mock,改为调用 GET /api/client/operations/dashboard、客户端账务/任务聚合,并通过 x-tenant-id 限定当前租户。
  • BUG-FE-004:运营端和客户端系统日志页移除静态 logsSeed,接入真实日志 API,支持分页、关键字、级别、模块和时间范围;长详情使用详情卡展示 JSON 摘要。
  • BUG-FE-005:企业应用管理短信应用 tab 接入真实企业应用、租户连接状态、连接详情和 CMPP 参数 API;断开连接调用真实后端并写系统日志,变更后刷新列表。彩信 tab 仍为第一版待开发路径,不作为短信验收依据。
  • BUG-API-001:通道创建在 Service 层校验 code/name/gatewayHost/gatewayPort/account/passwordCipher/srcId,缺失或端口非法返回 400,不再让 Prisma validation error 冒泡成 500。
  • BUG-DEV-001:复现 Vite 8 dev server 在端口切换后依赖/模块转换请求超时,导致白屏;根 npm run dev 改为先 npm run buildvite preview --host 0.0.0.0,确保本地打开稳定。vite.config.ts 保留 optimizeDeps.noDiscovery,避免自动扫描引发的预构建卡住。

新增/更新测试

测试文件 新增覆盖
api/src/channels/channels.service.spec.ts 通道创建缺少必填字段时返回可读 400。
api/src/billing/billing.service.spec.ts 人工充值写入 billing.manual_recharge 操作日志。
api/src/operations/operations.service.spec.ts Dashboard 新增今日统计、账户/充值/待审核聚合和系统日志分页详情。
api/src/sms-config/sms-config.service.spec.ts 企业应用列表聚合真实 CMPP 连接状态、CMPP 参数读取、断开连接写日志。

已执行命令和 Smoke

npm --prefix api test
npm --prefix api run build
npm run build
npm run dev

# API HTTP smoke on API_PORT=3101
GET  /api/health
POST /api/admin/channels                 # 缺必填字段返回 400
GET  /api/admin/operations/dashboard/statistics
GET  /api/admin/system-logs?page=1&pageSize=2

当前结果

  • API Jest8 个 test suite 通过,43 个测试通过。
  • API build:通过。
  • 前端 build:通过,仍存在既有大 chunk warning。
  • npm run dev:通过,当前会 build 后启动 Vite preview,实际可访问 http://localhost:4173/,避免 Vite 8 dev optimizer/transform 白屏。
  • 浏览器 smoke 通过:
    • 运营端 Dashboard 渲染真实聚合指标,无相关 console error。
    • 运营端人工充值页渲染真实记录,人工充值弹窗展示真实企业下拉和确认入口。
    • 运营端系统日志页渲染真实日志,长详情以卡片展示。
    • 企业应用管理页渲染真实应用和 CMPP 状态,连接详情弹窗和 CMPP 参数弹窗可打开。
    • 客户端 Dashboard 和客户端系统日志页按当前租户渲染,无相关 console error。
  • API HTTP smoke/api/health 返回 ok;通道缺参返回 400 和可读错误;dashboard/statistics、system-logs 返回真实数据。

剩余说明

  • npm run dev 为稳定预览模式,不提供 Vite HMR;保留原因是 Vite 8/Rolldown dev transform 在当前 Windows + 中文路径工作区下会阻塞模块请求并造成白屏。开发时如需热更新,可另行评估降级 Vite 或迁移工作区路径后恢复原生 dev server。

2026-07-02 登录与用户管理闭环补充

本轮修复范围

  • 新增用户登录字段和 fail2ban 持久化字段:emailphonefailedLoginCountlockedUntillastLoginAtdeletedAt
  • 登录入口拆分为 /client/login/admin/login,两端均调用真实验证码和登录 API。
  • 用户登录入口和用户表单统一文案为“用户名/登录账号”,提示可用用户名、邮箱或手机号登录。
  • 运营端登录仅允许 platform_admin;客户端登录仅允许已关联企业的 enterprise_admin
  • 运营端用户管理接入真实 /api/admin/users,支持平台管理员和企业管理员的新增、编辑、启用/禁用、删除、改密;企业管理员必须关联企业。
  • 客户端用户管理接入真实 /api/client/users,所有操作继承当前登录企业 tenantId
  • 启用/禁用、删除均通过确认弹窗执行;用户删除采用软删除,不破坏历史日志和业务记录。
  • 连续 5 次登录失败后锁定 24 小时;登录成功清空失败次数和锁定状态。

已执行测试

npm --prefix api test -- users.service.spec.ts auth.service.spec.ts
npm --prefix api run prisma:generate
npm --prefix api run build
npm run build

当前结果

  • users.service.spec.tsauth.service.spec.ts:通过,覆盖用户类型约束、企业关联约束、操作日志、端登录隔离和失败次数累计。
  • API build:通过。
  • 前端 build:通过,仍有既有大 chunk warning。
  • tools/smoke/real-env-smoke.mjs 已同步企业管理员邮箱/手机号、角色 seed、验证码登录和 CMPP 端口 17890
  • 真实数据库迁移、浏览器端登录 smoke 需要在生产验证环境执行 prisma migrate deploy 后补充记录。

2026-07-02 非彩信纯 mock 菜单真实化

本轮修复范围

  • 客户端:充值套餐、账单流水、批量任务、短信发送、短信签名、短信模板改为调用真实 API;签名材料使用真实文件元数据和材料关联接口;发送任务调用真实批量任务接口。
  • 运营端:数据统计、账务账户、发送监控、敏感词、全局黑名单、企业黑名单、手机号段库、报备字段库、通道组、通道报备字段、报备任务、报备记录、短信审核、短信记录改为真实 API。
  • 企业管理:客户列表、客户表单、客户详情由 adminEnterpriseMock/localStorage 改为真实租户、账户、应用、签名、模板接口;后端补充租户编辑、状态变更和删除接口。
  • 通道管理:删除静态通道兜底,API 失败展示错误态。
  • 企业认证审核:删除静态认证兜底,API 失败展示错误态。
  • 企业签名/企业模板运营端列表只展示真实短信配置数据;彩信相关菜单继续作为待开发边界,不计入第一版短信验收。

已执行命令

npm --prefix api test
npm --prefix api run build
npm run build
npm run verify:phase8

当前结果

  • API Jest10 个 test suite 通过,49 个测试通过。
  • API build 通过。
  • 前端 build 通过,仍存在既有大 chunk warning。
  • npm run verify:phase8 通过:
    • Gateway 队列契约 4 个示例通过。
    • Go Gateway 测试通过。
    • BullMQ 15000 条消息、并发 500、端到端 TPS 681.47,满足 500 TPS。
    • Prisma generate、API build、前端 build 均通过。
  • 源码搜索剩余静态业务数据集中在彩信待开发页面、彩信审核页面、企业应用彩信 tab,以及 src/api/session.ts 的登录 session 持久化;非彩信主菜单的 clientService/adminService 业务路径已清理。

待复测

  • 浏览器 smoke 和真实文件上传 smoke 需要在生产验证环境补跑,重点复测客户端发送、签名材料上传、短信审核、短信记录、客户管理和报备任务。

2026-07-03 单运营商通道组、应用级费率和回执幂等

本轮修复范围

  • 通道组规则:
    • SmsChannelGroup.carrier 固化为移动、联通、电信三选一,禁止三网通道组。
    • SmsChannelGroupItem.carrier 保留并参与发送,必须等于通道组运营商。
    • 三网只作为通道本体能力 SmsChannel.carrier=all,放入某个通道组后只服务该组运营商。
    • 同一通道组内同一省份只能配置一个通道;省份 item 必须引用发送地区一致的通道。
    • 全国通道允许多个,但同一通道组内全国通道优先级禁止重复;本期不做权重分流。
    • 路由规则必须绑定应用、运营商、通道组,且 route carrier 必须等于 group carrier。
  • 发送和计费规则:
    • 运营商以号码前缀正则为准;手机号段库只提供省份/城市,carrier 仅作后台提示或校验。
    • 发送前校验最终选中通道的签名报备任务为 approved,补发切换通道时重新校验。
    • 企业应用新增 customerUnitPrice,客户扣费按应用级客户费率;通道成本只作内部成本。
    • 迟到旧通道 failed receipt 不覆盖新通道 delivered 最终状态;历史回执仍入库可查。
    • 重复 submit/receipt 回调不得重复扣费、释放冻结或退款。
    • 补发使用触发时当前通道组配置;本期不考虑人工重发。
  • 前端和真实 smoke
    • 企业应用表单增加客户单价输入,保存时写入真实应用 API。
    • 企业应用按移动、联通、电信分别选择通道组,选项按通道组 carrier 过滤。
    • 真实 smoke seed 补充应用客户单价、三网通道放入移动组、签名-通道 approved 报备。

新增/更新测试

测试文件 新增覆盖
api/src/channels/channels.service.spec.ts 单运营商通道组、通道组 item carrier 校验、通道 carrier 兼容、省份与发送地区一致、同省唯一、全国优先级唯一、route carrier 与 group carrier 一致。
api/src/send-chain/send-chain.service.spec.ts 通道组 item carrier 参与发送、最终通道签名报备校验、应用级客户费率、迟到旧 failed receipt 不覆盖 delivered、重复账务动作幂等。
api/src/sms-config/sms-config.service.spec.ts 应用配置与列表在新增客户费率字段后继续通过。

已执行命令

npm --prefix api run prisma:generate
npm --prefix api test -- channels.service.spec.ts send-chain.service.spec.ts sms-config.service.spec.ts --runInBand
npm --prefix api test
npm --prefix api run build
npm run build
npm --prefix api run prisma:migrate:deploy
$env:API_PORT='3101'; $env:API_ENABLE_SEND_WORKER='true'; npm --prefix api run start:dev
node tools/smoke/real-env-smoke.mjs
node <inline channel-group rule HTTP smoke>
npm run spike:contracts
npm run test:gateway
npm run verify:phase8

当前结果

  • Prisma Client 生成通过。
  • 新增迁移已应用到真实 PostgreSQL
    • 20260703143000_add_channel_group_carrier
    • 20260703152000_add_application_customer_rate
  • API Jest10 个 test suite 通过,56 个测试通过。
  • API build 通过。
  • 前端 build 通过,仍存在既有 Vite chunk size warning。
  • 真实 API smoke 通过:
    • tools/smoke/real-env-smoke.mjs 通过,验证真实 API、Prisma/PostgreSQL、Redis/BullMQ、登录、充值、发送任务、worker 入队、文件上传元数据和操作日志。
    • inline 通道组规则 HTTP smoke 通过,覆盖三网组拒绝、item carrier 不匹配拒绝、通道 carrier 不兼容拒绝、省份/发送地区不匹配拒绝、同省重复拒绝、全国优先级重复拒绝、route carrier/group carrier 不匹配拒绝。
  • Gateway 队列契约通过,4 个示例均验证通过。
  • npm run test:gateway 通过,Go Gateway health、connection、tracker、cmpp、spike 测试全部通过。
  • npm run verify:phase8 未通过,仍阻塞在已知 BullMQ spike 性能阈值:
    • 15000 条消息、并发 500。
    • enqueue TPS 3139.43。
    • end-to-end TPS 479.02,低于 500 TPS。

剩余说明

  • verify:phase8 当前失败点是独立 BullMQ 性能阈值,不是本轮通道组、计费、报备、回执业务逻辑测试失败。
  • 浏览器端完整手工回归仍建议补跑企业应用创建、通道组配置、短信记录详情弹窗中的历史回执展示。

2026-07-07 Gateway 下游 CMPP 入站第一阶段补齐

本轮修复

  • Go Gateway 启动时同时监听 GATEWAY_CMPP_ADDR,默认生产端口 0.0.0.0:17890,不再只是 HTTP /health 控制服务。
  • 新增企业应用独立 6 位 cmppAccountPrisma 迁移 20260707162000_add_application_cmpp_account 会为存量应用生成账号;客户端/运营端 CMPP 参数接口返回该应用独立账号。
  • Gateway 下游 CMPP bind 使用真实 gocmpp 协议解析 Source_Addr/AuthSource/Timestamp,调用 NestJS /api/gateway/events/inbound/authenticate,由真实数据库校验应用账号、应用 CMPP 密码、企业状态、企业认证状态、应用状态和 IP 白名单。
  • Gateway 下游 CMPP submit 解码 CMPP 3.0 SubmitReq,调用 NestJS /api/gateway/events/inbound/submitNestJS 按 sourceType=cmpp 创建发送记录并复用模板/签名/风控/余额/运营商识别/通道组路由/队列优先级链路。
  • Go Gateway 新增入站集成测试,覆盖本地 CMPP 客户端 connect/login、UCS2 submit 和 API 回调。

验证状态

  • npm --prefix api run prisma:generate:通过。
  • npm --prefix api test -- sms-config.service.spec.ts send-chain.service.spec.ts --runInBand:通过。
  • npm --prefix api run build:通过。
  • go test ./...Gateway):通过。

剩余缺口

  • 下游连接状态回写、连接数上限、断开/心跳历史日志仍需继续产品化。
  • 下游 submit 当前通过 sourceType=cmpp 的系统批次兼容承载,尚未完全拆成独立单条发送模型。
  • 客户侧最终 Deliver Receipt 投递、客户侧上行 Deliver 推送、上游真实 SMSC submit worker、上游 receipt/uplink 生产解析仍未完成。

2026-07-11 Gateway 客户侧 Submit 日志完善

本轮修复

  • Gateway 入站 Submit 日志增加 submit_receivedsubmit_acceptedsubmit_rejected 结构化事件,同时记录 CONNECT 声明的客户协议版本与 Go 实际解包类型,并记录账号、客户 IP、sequenceId、号码、srcId、编码、分片、CMPP result、平台 messageId、CMPP Msg_Id 和处理耗时。
  • Gateway HTTP 回调在 NestJS 返回非 2xx 时保留最多 64KB 响应体,客户 Submit 失败日志可直接显示模板不匹配、IP 白名单、余额或路由等真实业务原因,不再只显示 HTTP 状态码。
  • 日志不记录明文短信正文,仅记录字符数和 MD5 哈希,便于比对同一内容且避免日志泄露。
  • 将当前 gocmpp 版本固定为仓库内小型 fork,仅在 server 循环补充底层诊断:包在进入业务 handler 之前发生长度、命令字、包体读取或 Unpack 失败时,记录 read/unpack packet failed、远端地址、库解析协议模式、Go 错误类型和原始错误;正常 EOF 断开不记为解包失败。

验证状态

  • go test ./internal/inbound -count=1:通过。
  • go test ./... -count=1:通过。
  • go build ./cmd/gateway:通过。
  • 真实 TCP 非法包用例:向入站端口写入非法 total_length,确认业务 handler 未执行时仍产生 read/unpack packet failed 日志。

2026-07-07 Gateway 上游提交与下游 Deliver 闭环补齐

本轮修复

  • SubmitCommand 契约、示例和 Go 结构增加 upstream.gatewayHost/gatewayPort/account/passwordCipher/cmppVersion,API 发送链路在真实业务校验通过后保留 BullMQ 审计投递,同时写入 Redis Stream gateway.submit.commands 主命令流。
  • Go Gateway 新增上游提交管理器,按通道建立/复用 gocmpp 客户端连接,发送真实 CMPP Submit,接收 SubmitResp,并回调 NestJS SubmitResult
  • Go Gateway 上游读循环开始处理 deliver receipt 和普通 deliver 上行:receipt 解析后回调 NestJS /gateway/events/receipt,普通上行解码后回调 /gateway/events/uplink
  • Gateway 下游入站服务记录客户 Submit 对应的 messageId 到在线客户连接映射;NestJS 收到最终 receipt/uplink 并入库后调用 Gateway /downstream/receipt/downstream/uplinkGateway 向在线客户下发 CMPP Deliver Receipt 或普通 Deliver。
  • api/src/send-chain/send-chain.service.spec.ts 覆盖 SubmitCommand 上游配置和 Redis Stream 发布;gateway/internal/inbound/server_test.go 覆盖客户 submit 后平台下发 Deliver ReceiptGateway 契约示例覆盖新 upstream 字段。

验证状态

  • npm --prefix api test -- send-chain.service.spec.ts:通过。
  • npm --prefix api test:通过,12 个 suites、82 个 tests。
  • npm --prefix api run build:通过。
  • go test ./...Gateway):通过。
  • npm run spike:contracts:通过,4 个 Gateway 队列契约示例通过。

剩余缺口

  • Gateway 控制面 /upstream/submit 仅保留为调试/补偿入口;生产主链路由 Go Gateway submit worker 消费 Redis Stream gateway.submit.commands 触发。worker 当前覆盖新消息 > 消费和 ack,pending 历史消息扫描与精细重试治理放入后续在途恢复阶段。
  • 客户侧 Deliver Receipt/上行 Deliver 当前依赖 Gateway 内存在线连接映射;客户断线、Gateway 重启或映射丢失时尚未实现持久化缓存、重试和投递失败审计。
  • 普通上行只有能关联 messageId 的事件可推送给客户;仅按接入号、手机号、应用和时间窗口匹配客户连接仍待产品化。
  • 长短信拆分/重组、多连接窗口、窗口满、在途消息恢复、断线重连后的状态补偿仍待后续实现和压测。

2026-07-07 阶段 1Gateway SubmitCommand 独立消费

本轮修复

  • NestJS SendChain 取消主链路同步调用 Gateway /upstream/submit;真实业务校验通过后创建 SmsSubmitRecord、保留 BullMQ gateway.submit.queue 审计/兼容投递,并向 Redis Stream gateway.submit.commands 写入 SubmitCommand
  • Go Gateway 新增 submitworker,启动时默认创建/复用 consumer group cmpp-gateway,独立消费 Redis Stream 中的 SubmitCommand,调用同一个上游提交管理器真实 submit 到上游 SMSC。
  • Gateway /upstream/submit 保留为调试/运维补偿接口,不作为 API 主发送路径。
  • Gateway worker 支持环境变量:REDIS_URLGATEWAY_SUBMIT_STREAMGATEWAY_SUBMIT_GROUPGATEWAY_SUBMIT_CONSUMERGATEWAY_SUBMIT_WORKER_DISABLED=true

验收口径

  • API 入队后不再因为 Gateway 控制面短暂不可达而自己生成 timeoutSubmitResult 必须由 Gateway worker 真实消费和提交后回调。
  • Gateway 停止时,SubmitCommand 留在 Redis StreamGateway 恢复后由 consumer group 继续消费新消息。
  • BullMQ gateway.submit.queue 仅作为审计/兼容,不再是唯一主提交通道。

剩余边界

  • 当前 worker 先覆盖新消息 > 消费和 ackpending 历史消息扫描、claim、重试退避和死信审计放到在途恢复阶段继续做。

2026-07-07 阶段 2/3:客户侧 Deliver 持久化重投与普通上行匹配

本轮修复

  • Prisma 新增 CmppDownstreamDelivery,用于保存客户侧待投递 Deliver Receipt 和普通 Deliver 上行;状态覆盖 pending/delivered,记录 retryCount、nextRetryAt、lastError、payload、message/application 关联。
  • SmsUplinkMessage 增加 applicationIdmessageRecordIdmatchStatusmatchReason,并建立应用和匹配下发记录关系。
  • NestJS 收到最终 receipt 后,先写平台回执和消息状态,再创建客户侧待投递记录,尝试调用 Gateway /downstream/receipt;成功标记 delivered,客户不在线或 Gateway 不可达时保留 pending 并记录失败原因。
  • NestJS 收到普通上行后执行匹配:messageId 精确匹配优先;无 messageId 时按接入号匹配应用路由;仍无唯一应用时按手机号和最近下发时间窗口匹配;多候选标记 ambiguous,未匹配标记 unmatched,但均真实入库。
  • Gateway 下游客户 bind/login 成功后保存账号级在线连接,并调用 NestJS /gateway/events/downstream/pending 拉取 pending 投递;补发成功后回调 /gateway/events/downstream/delivered,失败回调 /gateway/events/downstream/failed
  • 运营/客户端上行查询 include 应用和匹配下发记录,便于页面展示 matchStatus/matchReason。

验证状态

  • npm --prefix api run prisma:generate:通过。
  • npm --prefix api test -- send-chain.service.spec.ts:通过。
  • npm --prefix api test:通过,12 个 suites、82 个 tests。
  • npm --prefix api run build:通过。
  • go test ./...Gateway):通过。
  • npm run spike:contracts:通过。
  • npm run build:通过,仅既有 Vite chunk size warning。

剩余边界

  • 待投递 pending 目前在客户 bind/login 时拉取补发;后台周期扫描、指数退避、过期策略、死信队列和运营端失败审计页面仍待后续实现。
  • 上行匹配已覆盖 messageId、接入号和手机号时间窗口;共享接入号、多应用多候选时不会误推,但人工认领/改派流程尚未实现。
  • 客户连接断开检测和应用级连接数状态回写仍需继续产品化。

2026-07-08 阶段 4Gateway 长短信拆分与长上行重组

本轮修复

  • Go Gateway 上游 Submit 支持长短信第一版拆分:超过 140 字节的短信按 CMPP 标准 6 字节 UDH 生成分片,每片总长度不超过 140 字节,并设置 PkTotal/PkNumber/TpUdhi 后逐包发送到上游 SMSC。
  • 同一平台 SubmitCommand 的多个 accepted 分片 MsgId 均登记到 Gateway 映射表,后续任一分片 receipt 可回溯到原 messageId/submitId/channelId
  • Go Gateway 上游普通 Deliver 支持长上行第一版重组:收到 TpUdhi=1 且携带标准 UDH 的分片时,按通道、主叫、被叫、引用号和总片数缓存;分片齐全后只回传一条完整 UplinkEvent 给 NestJS。
  • 新增 gateway/internal/upstream/long_message_test.go,覆盖 UCS2 长短信拆分、短短信不分片、长上行乱序重组。

验证状态

  • go test ./...Gateway):通过。

剩余边界

  • 阶段 4 后长短信仍按单条平台消息记录展示,尚未提供运营端分片级提交明细、分片级补发审计和部分分片失败后的精细补偿;该审计缺口已在阶段 23 补齐第一版。
  • 长上行分片缓存当前为 Gateway 进程内内存;Gateway 重启、跨连接分片漂移或超过缓存 TTL 的残片不会恢复,后续在“在途消息恢复/状态补偿”阶段继续做。

2026-07-08 阶段 5Gateway 多连接窗口与窗口满控制

本轮修复

  • SubmitCommand.upstream 契约、示例、Go 结构和 NestJS 生产者增加 desiredConnections/windowSize,字段来自通道真实配置;未配置时默认 desiredConnections=1windowSize=16
  • Go Gateway 上游提交管理器从单连接升级为通道级连接池:同一通道按 desiredConnections 建立多条 CMPP 客户端连接,每条连接独立维护 submit pending、receipt/uplink 映射和长上行分片缓存。
  • 每条上游连接增加窗口令牌;提交前必须获得窗口,SubmitResp、reject 或 timeout 后释放窗口;所有连接窗口均满时等待可用窗口,超过提交超时时返回 WINDOW_TIMEOUT
  • 长短信分片也复用连接池窗口调度,同一条平台消息的多个 accepted 分片仍映射回原 messageId/submitId/channelId
  • 新增 gateway/internal/upstream/pool_test.go,覆盖连接池跨连接获取窗口、窗口满拒绝继续占用、释放后可重新获取。

验证状态

  • go test ./...Gateway):通过。
  • npm --prefix api test -- send-chain.service.spec.ts:通过。

剩余边界

  • 当前窗口状态为 Gateway 进程内控制,尚未把连接级窗口占用、等待队列长度、submit latency 等指标回写到 NestJS 或运营端页面。
  • 当前阶段只处理窗口容量和多连接发送;Gateway 重启、上游连接断开时的在途 submit 恢复、pending claim、状态补偿和死信审计仍在下一阶段处理。

2026-07-08 阶段 6CMPP 配置入口补齐

本轮修复

  • 运营端通道创建/编辑表单新增上游 desiredConnectionswindowSize 输入,真实提交到 NestJS 通道 API,并规范化写入 SmsChannel.config
  • NestJS ChannelsServicedesiredConnections/windowSize 增加正整数校验;通道激活后的 ConnectChannel 请求和发送链路 SubmitCommand.upstream 均复用该真实配置。
  • Prisma 为 SmsApplication 新增 cmppMaxConnectionscmppWindowSize 字段;运营端短信应用创建/编辑表单新增 cmppAccount 和客户最大连接数输入,客户提交窗口暂不展示给运营配置,保留后端默认值。
  • 企业应用 cmppAccount 现在支持两种真实路径:显式填写 6 位数字账号,或留空由后端自动生成唯一账号;重复账号和非法格式会被后端拒绝。
  • 企业应用 CMPP 参数接口改为从应用真实字段返回 enterpriseCode/account/passwordCipher/maxConnections/windowSize,不再借用任意通道企业代码或默认值拼装客户参数。
  • 应用级 cmppEnterpriseCode 新建/编辑可自定义;接口密码新建默认随机 16 位 UUID 片段,编辑留空不覆盖、填写 16 位后更新。AppID 仅作为平台应用标识展示,不作为 CMPP 协议认证参数。

验证状态

  • npm --prefix api run prisma:generate:通过。
  • npm --prefix api test -- sms-config.service.spec.ts channels.service.spec.ts:通过,2 个 suites、34 个 tests。
  • npm --prefix api run build:通过。
  • npm run build:通过,仅既有 Vite chunk size warning。

说明

  • desiredConnections/windowSize 不是 CMPP 协议标准字段,也不是 gocmpp 的原生配置项;它们是本平台对上游通道连接池和提交窗口的运行参数。
  • cmppAccount 是客户侧应用接入账号;当前已支持真实生成、真实保存和显式配置。

2026-07-08 阶段 7SubmitCommand 在途恢复第一步

本轮修复

  • Go Gateway submitworker 在正常消费新消息前新增 pending 恢复流程:对 Redis Stream consumer group 中空闲超过阈值的消息执行 XAUTOCLAIM,将滞留在 PEL 的 SubmitCommand 认领到当前 consumer。
  • 被认领的 pending 命令复用现有 handleMessage -> Upstream.Submit -> XAck 成功路径处理;成功后 ack,失败时保留在 PEL,留给后续重试/死信治理。
  • submitworker 增加可注入 Submit 函数,便于单测覆盖消息处理路径;新增单测覆盖 injected submit 和默认 minIdle 阈值。

验证状态

  • go test ./...Gateway):通过。

剩余边界

  • 当前恢复能力只覆盖 Redis Stream PEL 中“已被读走但未 ack”的 pending 命令;尚未实现恢复次数上限、死信队列、失败审计页面和人工补偿入口。
  • Gateway 重启时上游连接内已经发出但尚未收到 submit resp 的 in-flight CMPP 请求,仍未完成状态补偿;这部分继续放在后续“断线重连后的消息状态处理”阶段。

2026-07-08 阶段 8:上游连接断开时 pending submit 补偿

本轮修复

  • Go Gateway 上游连接读循环开始区分“空读超时”和“真实连接断开”;空读超时继续等待,真实断开则进入连接丢失处理。
  • 某条上游连接断开时,Gateway 会把该连接上所有等待 submit resp 的 pending submit 立即唤醒,返回 timeout + CONNECTION_LOST,不再机械等待固定 SUBMIT_TIMEOUT
  • 连接池在再次分配连接前会重新执行 ensureConnected();旧连接断开后,后续新消息可重新建立物理连接继续提交。
  • 新增 gateway/internal/upstream/connection_loss_test.go,覆盖 pending submit 被唤醒和临时读超时识别。

验证状态

  • go test ./...Gateway):通过。
  • npm --prefix api test -- send-chain.service.spec.ts:通过。

剩余边界

  • 当前补偿只覆盖“连接断开且 submit resp 尚未返回”的场景;尚未覆盖“上游其实已受理,但 submit resp 在断线前后丢失”的二次确认和幂等回查。
  • submit 结果死信队列、失败审计、恢复次数上限和人工补偿入口仍在后续阶段。

2026-07-08 阶段 9receipt 驱动的保守二次归因

本轮修复

  • Gateway 上游 receipt 事件补充 phoneNumber,即使无法从内存 tracker 中精确恢复平台 messageId,也会把运营商回执手机号带回 NestJS。
  • NestJS handleReceipt 新增保守归因:如果 receipt 无法按平台 messageId/gatewayMessageId 精确命中,只在“同通道、同手机号、72 小时窗口内、且仅存在 1 条 timeout + gatewayMessageId=null 的 submit 记录”时才接收该回执。
  • 归因成功后会先回填该次 sms_submit_record.gatewayMessageId/sequenceId,再写入真实 sms_receipt_record 并按既有逻辑更新 sms_message_record、下游客户回执推送和幂等保护。
  • 新增 SendChainService 单测,覆盖唯一候选归因成功和多候选拒绝归因两种场景。

验证状态

  • go test ./...Gateway):待本轮统一回归。
  • npm --prefix api test -- send-chain.service.spec.ts:待本轮统一回归。

剩余边界

  • 当前只做“唯一候选才归因”的保守版本,仍未实现面向运营商或供应商的 submit 结果主动回查。
  • 如果同通道同手机号在窗口内存在多条 timeout 候选,系统会拒绝归因,后续仍需人工补偿或更强的协议级关联键。

2026-07-08 阶段 10SubmitCommand 死信治理第一版

本轮修复

  • Prisma 新增真实表 GatewaySubmitDeadLetter,保存 Gateway SubmitCommand 死信的消息 ID、租户/应用/通道、失败原因、尝试次数、原始命令载荷、人工重入队状态和解决状态。
  • Go Gateway submitworker 新增失败次数治理:同一条 Stream 消息处理失败达到阈值后,调用 NestJS /gateway/events/dead-letter 入库死信,并对原消息执行 ack,避免它无限滞留在 PEL。
  • Gateway 对非法 SubmitCommand 载荷也会直接转死信,防止 poison message 持续阻塞消费。
  • NestJS 新增真实死信接口:Gateway 可上报死信;运营端后端可分页查询 /api/admin/operations/gateway-submit-dead-letters;可通过 /api/admin/operations/gateway-submit-dead-letters/:id/requeue 将原始 SubmitCommand 重新写回 Redis Stream。
  • NestJS 在收到同一 submitId/messageId 的后续真实 SubmitResult 时,会把对应死信自动标记为 resolved

验证状态

  • npm --prefix api run prisma:generate:通过。
  • npm --prefix api test -- send-chain.service.spec.ts operations.service.spec.ts:通过,2 个 suites、26 个测试通过。
  • npm --prefix api run build:通过。
  • go test ./...Gateway):通过。

剩余边界

  • 当前死信治理只提供“达到阈值后入库 + 人工重入队”的第一版,尚未实现后台自动重放、重放节流、过期清理和专门的前端运营页面。
  • 非法载荷死信如果缺少完整 SubmitCommand,当前不可人工重放,只能用于审计和人工排查。

2026-07-08 阶段 11:下游客户在线时周期补投与失败封顶

本轮修复

  • 明确责任边界:客户系统负责断线后的重新 bind;平台负责客户不在线或临时投递失败时的消息不丢、待投递保存和补投。
  • Go Gateway 下游入站服务新增在线账号周期补投:除客户 bind 成功后立即拉取 pending 外,Gateway 还会按周期为当前在线账号再次调用 /gateway/events/downstream/pending,继续补发未投递成功的 Deliver Receipt/上行 Deliver。
  • Gateway 向下游发送 Deliver 失败时会清理失效的内存会话映射,避免对已失效连接无休止重复尝试。
  • NestJS markDownstreamDeliveryFailed 新增失败上限:未超过阈值时继续 pending 并推进 retryCount/nextRetryAt;达到阈值后转为 failed,停止无限重试,并写 gateway.downstream_delivery_failed 系统日志。

验证状态

  • npm --prefix api test -- send-chain.service.spec.ts:通过,1 个 suite、21 个测试通过。
  • go test ./internal/inbound ./internal/control ./...Gateway):通过。

剩余边界

  • 当前周期补投只针对“Gateway 认为客户在线”的账号;尚未实现下游投递失败专门列表、人工重投页面和跨 Gateway 实例共享的客户在线状态。
  • CmppDownstreamDelivery 目前仍使用固定重试间隔,尚未实现指数退避、不同消息类型差异化策略和过期归档。

2026-07-08 阶段 12:下游投递失败审计与人工重投

本轮修复

  • 运营端新增真实下游投递查询接口 /api/admin/operations/downstream-deliveries,支持按 tenantId/applicationId/deliveryType/status/keyword 筛选并分页返回真实 CmppDownstreamDelivery 数据。
  • NestJS 新增 /api/admin/operations/downstream-deliveries/:id/requeue,可对单条下游投递记录执行人工重投,真实调用 Gateway /downstream/receipt/downstream/uplink,并写 gateway.downstream_delivery_requeue 系统日志。
  • 运营端新增“下游投递记录”页面,列表、详情、筛选和重投均接真实后端,不使用 mock、本地状态或静态数组。

验证状态

  • npm --prefix api test -- send-chain.service.spec.ts operations.service.spec.ts:通过,2 个 suites、29 个测试通过。
  • npm --prefix api run build:通过。
  • npm run build:通过,仅有既有 Vite chunk size warning。

剩余边界

  • 当前人工重投仍是单条操作,尚未提供批量重投、失败聚合告警和专门的下游投递 Dashboard。
  • 页面侧暂未做自动轮询刷新,需要手动查询或重进页面观察状态变化。

2026-07-08 阶段 13:下游投递自动退避第一版

本轮修复

  • CmppDownstreamDelivery 的失败重试从固定 60 秒改为指数退避:基础间隔来自 CMPP_DOWNSTREAM_RETRY_DELAY_MS,每次失败按 2 倍递增,并受 CMPP_DOWNSTREAM_RETRY_MAX_DELAY_MS 上限约束。
  • 这样在客户长时间离线或网络持续抖动时,平台不会每分钟机械重试同一条下游投递,能更温和地消耗 API、Gateway 和连接资源。
  • 总重试次数上限逻辑保持不变,超过 CMPP_DOWNSTREAM_MAX_RETRIES 后仍转 failed 并写失败审计。

验证状态

  • npm --prefix api test -- send-chain.service.spec.ts:通过,新增指数退避单测。

剩余边界

  • 当前退避策略还没有加入随机抖动,多个记录在同一时间失败时,后续重试时刻仍可能比较集中。
  • 退避参数当前是全局环境变量,尚未细分到 receipt/uplink 或不同客户应用级别。

2026-07-08 阶段 14:下游投递批量重投

本轮修复

  • 运营端下游投递记录页新增勾选和“批量重投”操作,仅允许对当前页的 pending/failed 记录执行批量重投。
  • NestJS 新增真实批量接口 /api/admin/operations/downstream-deliveries/requeue,逐条调用既有单条重投逻辑,返回成功/失败汇总,不用前端自行拼结果。
  • SendChainService 新增批量重投结果汇总与空选择拦截单测。

验证状态

  • npm --prefix api test -- send-chain.service.spec.ts:通过,新增批量重投单测。
  • npm --prefix api run build:通过。
  • npm run build:待本轮统一回归。

剩余边界

  • 当前批量重投只支持“勾选当前页记录”,还不支持“按筛选条件全量重投”或后台异步大批量任务。
  • 批量结果当前以内联提示为主,尚未做专门的批量执行历史与导出。

2026-07-08 阶段 15:下游投递告警第一版

本轮修复

  • OperationsService.dashboard() 新增真实下游投递告警聚合 downstreamDeliverySummary,统计 pending/failed/delivered 总量,以及“积压过久的 pending”和“最近失败”两类告警计数。
  • 运营端右上角通知新增“下游投递告警”,数量直接来自真实 Dashboard 聚合。
  • 运营看板新增下游投递告警摘要卡片,帮助运营从总览页直接感知当前下游投递异常。

验证状态

  • npm --prefix api test -- operations.service.spec.ts:随定向测试通过。
  • npm --prefix api run build:通过。
  • npm run build:通过,仅有既有 Vite chunk size warning。

剩余边界

  • 当前告警仍是站内聚合提醒,尚未接短信、邮件、企业微信等外部告警通道。
  • 告警口径当前采用全局阈值环境变量,尚未按客户应用、消息类型或时间段细分。

2026-07-08 阶段 16:下游投递 Dashboard 第一版

本轮修复

  • 新增真实接口 /api/admin/operations/downstream-deliveries/dashboard,直接按 CmppDownstreamDelivery 聚合返回 summary/typeBreakdown/retryBuckets/topApplications
  • 运营端“下游投递记录”页面顶部补上真实 Dashboard 区域,展示投递总量、待投递、已投递、告警、类型分布、重试压力和应用告警排行。
  • Dashboard 筛选范围与页面应用/类型筛选保持一致,不允许由前端只根据当前页列表数据临时拼装。

验证状态

  • npm --prefix api test -- operations.service.spec.ts:通过。
  • npm --prefix api run build:通过。
  • npm run build:通过,仅有既有 Vite chunk size warning。
  • git diff --check:无空白错误,仅 Windows LF/CRLF 提示。

剩余边界

  • 当前 Dashboard 仍偏运营处置视角,尚未补时间趋势、按客户/账号维度的更细颗粒聚合。
  • 应用告警排行当前以 pending + failed 为主排序,尚未加入更复杂的权重和 SLA 指标。

2026-07-08 阶段 17:下游在线账号 Presence 持久化底座

本轮修复

  • Gateway inbound 新增 Redis presence store,客户 cmppAccount 在 bind 成功、submit 建链和下游回执/上行投递时,会把在线账号状态写入 Redis。
  • presence 数据至少包含 account/srcId/remoteIp/gatewayInstanceId/state/connectedAt/updatedAt,并按 TTL 自动过期,避免该状态只存在单进程内存中。
  • Gateway 发送失败触发连接清理时,会同步移除该账号的 Redis presence 记录。
  • 该阶段先完成“在线状态外部化”,尚未宣称“Gateway 重启后 pending 投递自动恢复”已完成;恢复逻辑在后续阶段继续补。

验证状态

  • go test ./internal/inbound/...:通过。
  • go test ./cmd/gateway/...:通过。

剩余边界

  • 当前 presence 主要服务于后续恢复能力,Gateway 还未在启动时主动根据 Redis presence 扫描并恢复 pending 投递。
  • 连接断开当前主要依赖发送失败清理和 TTL 过期兜底,尚未建立更完整的显式断线回收机制。

2026-07-08 阶段 18Gateway 恢复候选视图

本轮修复

  • Gateway 启动时会读取 Redis presence,并输出恢复候选账号加载日志。
  • 新增控制面接口 GET /downstream/recovery-candidates,返回 Redis presence 与当前内存在线账号合并后的恢复候选视图。
  • 候选视图当前用于后续恢复逻辑和运维排查,不直接触发 pending 下游投递补发。

验证状态

  • go test ./internal/inbound/...:通过。
  • go test ./internal/control/...:通过。
  • go test ./cmd/gateway/...:通过。

剩余边界

  • 当前只是“识别谁值得恢复”,还没有执行“把这些账号的 pending 回执/上行自动继续补投”。
  • 候选视图默认按 Redis TTL 和最近活跃时间保留,尚未叠加更复杂的健康判定和跨实例去重策略。

2026-07-08 阶段 19Gateway pending 恢复执行第一版

本轮修复

  • Gateway 启动时会立即按恢复候选账号执行一次 pending 下游投递恢复扫描。
  • 后续每轮补投周期除扫描当前内存在线账号外,也会继续扫描恢复候选账号,尝试恢复 CmppDownstreamDelivery.pending
  • 当前恢复策略是“能投就投,投不了继续 pending”:若账号尚无可用下游连接,Gateway 不会把记录误标成失败,而是等待客户重连后的后续恢复机会。

验证状态

  • go test ./internal/inbound/...:通过。
  • go test ./internal/control/...:通过。
  • go test ./cmd/gateway/...:通过。

剩余边界

  • 当前恢复仍按固定扫描周期触发,尚未做更细的按账号退避、恢复批次追踪和恢复告警。
  • 仍未覆盖更复杂的长短信分片恢复、跨实例抢占协调和恢复中的重复投递防抖。

2026-07-08 阶段 20Gateway 恢复退避、锁与状态审计

本轮修复

  • Gateway 新增账号级恢复锁,避免同一 cmppAccount 被并发重复恢复。
  • 恢复失败、等待连接和部分成功场景会写入真实恢复状态,并按指数退避计算下一次可恢复时间,减少无意义高频重试。
  • 控制面新增 GET /downstream/recovery-statuses,可查看账号最近恢复状态、尝试次数、下一次重试时间和错误原因。

验证状态

  • go test ./internal/inbound/...:通过。
  • go test ./internal/control/...:通过。
  • go test ./cmd/gateway/...:通过。

剩余边界

  • 当前恢复状态审计仍停留在 Gateway 控制面和 Redis,尚未同步到运营端页面或 NestJS 持久化审计表。
  • 恢复退避当前按账号统一处理,尚未细分到回执/上行类型、失败类别或跨实例抢占优先级。

2026-07-08 阶段 21Gateway 恢复总览与链路缺口收口

本轮修复

  • 控制面新增 GET /downstream/recovery-overview,一次性返回恢复候选账号和恢复状态,便于生产联调与排查。
  • 需求文档已按当前真实代码重新梳理 CMPP 端到端链路剩余缺口,明确区分“已能验收的真实链路能力”和“尚未产品化完成的恢复审计/指标/复杂补偿能力”。
  • 系统测试用例新增恢复总览接口口径,便于后续生产验证直接对照。

验证状态

  • go test ./internal/control/...:通过。
  • go test ./internal/inbound/...:通过(延续前一阶段验证结果,本轮未改动 inbound 核心分支逻辑)。
  • go test ./cmd/gateway/...:通过。

阶段 21 后剩余真实缺口

  • 恢复状态仍未写回 NestJS/Prisma/PostgreSQL,运营端暂无真实恢复状态页面。
  • 多 Gateway 实例下更强的恢复抢占协调、分片级补偿审计、共享接入号上行人工认领仍未完成。
  • 连接级窗口利用率、恢复吞吐、恢复失败分布等运营指标仍未进入真实后台页面。

2026-07-08 阶段 22:恢复状态回流 NestJS 与运营端展示

本轮修复

  • NestJS 新增真实恢复状态接收接口 /api/gateway/events/downstream/recovery-status
  • Prisma/PostgreSQL 新增 GatewayDownstreamRecoveryStatus 表,按 cmppAccount 持久化恢复状态、尝试次数、下一次恢复时间、错误原因及应用/企业关联。
  • 运营端新增独立“恢复状态管理”页面,支持真实恢复状态列表、分页、详情接口和当前筛选结果 CSV 导出。
  • 原“下游投递记录”页面仅保留投递记录与重投能力,不再混放恢复状态列表。
  • 恢复状态新增 failureCategory 失败分类字段,Gateway 回传、NestJS 兜底归类并落库,运营端支持分类筛选、分布统计、详情展示和导出。
  • 多 Gateway 恢复抢占协调补强:恢复锁升级为 Redis token 租约,恢复完成时通过 Lua 原子校验 token 后才写状态和释放锁;迟到旧实例不能误删新实例锁。
  • GatewayDownstreamRecoveryStatus 新增 lockOwner/lockExpiresAtGateway 回传并由 NestJS 入库,运营端恢复状态列表和详情可查看锁持有实例。
  • 本地启动脚本补充 .local-tools\minio.exe 查找路径,并已验证本机 MinIO 可通过 npm run start:local:minio 启动。

验证状态

  • npm --prefix api run prisma:generate:通过。
  • npm --prefix api test -- operations.service.spec.ts send-chain.service.spec.ts:通过。
  • npm --prefix api run build:通过。
  • go test ./internal/inbound/... ./internal/control/... ./cmd/gateway/...:通过。
  • npm run build:通过,仅有既有 Vite chunk size warning。
  • npm --prefix api run prisma:migrate:deploy:通过,已应用 20260708213000_add_recovery_lock_observability
  • npm run start:local:minio:通过,MinIO API http://localhost:9000、Console http://localhost:9001 已监听。

阶段 22 后剩余真实缺口

  • 恢复状态已回流 NestJS,并已具备独立运营页、详情、导出和第一版失败分类分布;后续仍缺少恢复吞吐、耗时趋势、连续失败账号等更细指标。
  • 多 Gateway 账号级恢复抢占协调已具备 token 租约和完成校验;分片级补偿审计、共享接入号上行人工认领仍未完成。
  • 连接级窗口利用率、连接级心跳、恢复吞吐和恢复耗时等运营指标仍未进入真实后台页面。

2026-07-08 阶段 23:长短信分片级补偿审计

本轮修复

  • Prisma/PostgreSQL 新增 SmsMessageSegmentAudit,按短信记录、submitId、分片序号保存真实分片提交、回执和补偿归因。
  • Go Gateway 上游提交结果 SubmitResult 增加 segments[],逐片回传 segmentTotal/segmentIndex/sequenceId/gatewayMessageId/submitStatus/submittedAt,长短信不再只暴露首个分片结果。
  • NestJS handleSubmitResult 写入分片提交审计,handleReceipt 按上游 gatewayMessageId 回填分片回执状态;重投或补偿产生的新 submitId 与历史 submitId 可并存追踪。
  • 运营端短信记录详情新增“分片补偿审计”列表,从真实 API 查询 SmsMessageSegmentAudit,展示分片、submitId、通道、Sequence、MsgId、提交状态、回执状态、补偿类型和错误信息。
  • 契约文档和示例补充 SubmitResult.segments[],系统测试用例新增 TC-GW-026 长短信分片补偿审计

验证状态

  • npm --prefix api run prisma:generate:通过。
  • go test ./internal/upstream/... ./internal/queue/... ./internal/submitworker/...:通过。
  • npm --prefix api test -- send-chain.service.spec.ts operations.service.spec.ts:通过。
  • npm --prefix api run build:通过。
  • npm run build:通过,仅有既有 Vite chunk size warning。

阶段 23 后剩余真实缺口

  • 长短信分片级提交、回执和补偿归因已具备真实审计;后续仍需补按单个分片自动重投、分片级人工重投和更细的补偿指标。
  • 共享接入号、多候选普通上行的人工认领流程仍未完成。
  • 连接级窗口利用率、连接级心跳、恢复吞吐、恢复耗时趋势和连续失败账号等运营指标仍未进入真实后台页面。

2026-07-08 阶段 24:共享接入号上行人工认领

本轮修复

  • Prisma/PostgreSQL 新增 SmsUplinkMatchCandidate,用于保存普通上行 ambiguous 场景下的候选企业、应用、下发短信、候选来源、置信度、认领状态和认领时间。
  • NestJS 上行匹配逻辑增强:接入号匹配多个应用、或手机号时间窗口匹配多条下发时,不误推客户;上行记录标记 ambiguous,并真实写入候选表。
  • 运营端“短信上行记录”详情新增候选认领区,展示候选企业、候选应用、候选来源、置信度、候选下发短信和候选原因,支持“认领并推送”。
  • 新增 POST /admin/operations/uplink-messages/:id/claim:认领后更新 SmsUplinkMessagematched,选中候选置为 claimed,其他候选置为 rejected,写入操作日志,并创建真实 CmppDownstreamDelivery(deliveryType=uplink) 走客户侧下游投递链路。
  • 系统测试用例新增 TC-GW-027 共享接入号上行人工认领

验证状态

  • npm --prefix api run prisma:generate:通过。
  • npm --prefix api run prisma:migrate:deploy:通过,已应用 20260708233000_add_uplink_match_candidates
  • npm --prefix api test -- send-chain.service.spec.ts operations.service.spec.ts:通过,40 个测试。
  • npm --prefix api run build:通过。
  • npm run build:通过,仅有既有 Vite chunk size warning。

当前剩余真实缺口

  • 共享接入号上行已具备候选记录、人工认领和认领后下游投递第一版;后续仍需补批量认领、认领复核和认领准确率/积压指标。
  • 长短信分片级提交、回执和补偿归因已具备真实审计;后续仍需补按单个分片自动重投、分片级人工重投和更细的补偿指标。
  • 连接级窗口利用率、连接级心跳、恢复吞吐、恢复耗时趋势和连续失败账号等运营指标仍未进入真实后台页面。

2026-07-03 阶段 9:运营端报备回执导入真实上传/解析

本轮修复

  • 运营端报备任务导入弹窗改为真实选择 CSV/TSV/TXT 文件。
  • 前端先调用 /api/admin/files/upload 保存文件对象,再提交 fileObjectId、文件名和文本内容到 /api/admin/report-tasks/{id}/receipt-import
  • 后端导入接口解析文本回执,识别 status/result/状态/结果 列,统计成功行、失败行,并保存行级解析结果。
  • 报备任务状态由后端按解析结果派生:全成功为 completed,有成功有失败为 partial,全失败或空文件为 failed
  • 未识别的运营商状态按失败处理,避免把未知回执误判为通过。

已执行命令

npm --prefix api test -- channels.service.spec.ts
npm --prefix api test
npm --prefix api run build
npm run build
git diff --check

当前结果

  • api/src/channels/channels.service.spec.ts 新增文本回执解析和任务状态派生覆盖。
  • API Jest12 个 test suite 通过,73 个测试通过。
  • API build 通过。
  • 前端 build 通过,仍存在既有 Vite chunk size warning。
  • git diff --check 无空白错误,仅 Windows 工作区 LF/CRLF 提示。
  • 本地服务已重启:http://localhost:3000/http://localhost:5173/ 均监听,/api/admin/report-tasks/admin/report-tasks HTTP smoke 返回 200。

2026-07-03 全菜单真实后端、上传和列宽回归

本轮修复

  • 客户端企业认证从纯前端状态机改为真实 GET/POST /api/client/enterprise-certification 驱动。
  • 客户端企业认证营业执照上传接入 /api/admin/files/upload,提交时保存 licenseFileObjectId 等材料字段。
  • 运营端企业表单“企业照片”从禁用占位按钮改为真实上传,保存时写入 photoFileObjectId
  • 客户端账号设置、运营端系统配置无真实保存接口,已移除路由并删除纯前端页面。
  • 彩信待开发菜单路由统一指向占位页,不再进入静态 mock 演示页面。
  • 客户端短信发送详情、批量任务表格中明显偏窄的中文字段列已加宽。

已执行命令

npm --prefix api test
npm --prefix api run build
npm run build
npm run spike:contracts
npm run test:gateway
$env:API_BASE_URL='http://127.0.0.1:3000/api'; node tools/smoke/real-env-smoke.mjs
npm run verify:phase8
git diff --check

当前结果

  • API Jest12 个 test suite 通过,73 个测试通过。
  • API build 通过。
  • 前端 build 通过,仍存在既有 Vite chunk size warning。
  • Gateway 队列契约通过,4 个示例均验证通过。
  • npm run test:gateway 通过。
  • 真实 API smoke 通过,覆盖真实 PostgreSQL/Redis/MinIO/API 主链路和文件上传对象写入。
  • 浏览器抽检通过:客户端真实登录后,企业认证页面无“纯前端原型”文案,资料页出现真实上传入口;彩信待开发入口显示占位页而非静态表单。
  • npm run verify:phase8 仍未通过,失败点仍是已知 BullMQ spike 性能阈值:15000 条消息、并发 500、end-to-end TPS 469.76,低于 500。

2026-07-03 企业列表列宽和新建应用交互回归

本轮修复

  • 通用 Table 组件增加 colgroup、列最小宽度和表格最小宽度计算,显式配置的业务列不再被容器强行压窄,超出区域横向滚动。
  • 企业管理列表加宽企业 ID、企业名称、企业编码、统一社会信用代码、联系人、联系电话、余额、短信余量、状态和操作列。
  • 企业模板管理列表加宽企业、应用、签名、模板内容、审核状态、更新时间和操作列,模板内容列保留两行展示。
  • 运营端短信任务进度、短信审核、短信记录、报备任务、用户、系统日志、安全控制、充值记录等列表中的状态/操作/数量等易挤压列统一加宽。
  • 新建企业应用入口弹窗改为先选择真实企业,再进入应用参数、客户单价、IP 白名单和三网通道组配置;未选择企业时“下一步”禁用。
  • 新建短信应用表单把移动、联通、电信通道组配置改为独立卡片区,显示已配置数量和无可用通道组提示;未填写应用名称或未选择任一运营商通道组时禁止保存。
  • 补齐基础弹窗居中、遮罩、最大宽度和正文滚动样式,避免 1280px 视口下弹窗偏移或被截断。

已执行命令和浏览器验证

npm run build
git diff --check
  • 前端 build 通过,仍存在既有 Vite chunk size warning。
  • git diff --check 无空白错误,仅 Windows 工作区 LF/CRLF 提示。
  • 窄列扫描仅剩短字段列:报备字段“必填”90px、运营看板排名72px、短信上行选择框72px。
  • 浏览器使用真实运营端登录 admin@example.com 抽检通过:
    • 企业管理表格最小宽度 1920px,统一社会信用代码列 220px,联系人列 160px,联系电话列 150px,横向滚动生效。
    • 企业模板管理表格最小宽度 1820px,模板内容列 420px,横向滚动生效。
    • 新建企业应用弹窗在 1280px 视口下未截断,未选择企业时“下一步”禁用。
    • 新建短信应用页显示三网通道组卡片、已配置数量和无可用通道组提示,初始状态“创建应用”禁用。

2026-07-06 文件上传预览和下载回归

本轮修复

  • 文件服务新增真实下载接口 GET /api/admin/files/:id/download,从 MinIO 或本地对象存储读取真实文件对象,支持 inline 预览和 attachment 下载。
  • 运营端企业照片、企业签名材料、引流材料、报备回执导入均在真实上传成功后显示下载入口;图片类型文件显示点击预览入口。
  • 客户端企业认证营业执照上传成功后显示下载入口,图片类型文件显示点击预览入口;提交认证时保存文件类型信息。
  • 客户端签名列表对已保存签名材料显示下载入口,图片材料按文件名或类型显示预览入口。
  • 客户端短信发送导入号码文件为前端解析文件,未生成后端文件对象;页面仅提供本地原始文件下载,不标记为真实后端归档。

已执行命令

npm --prefix api test -- files.service.spec.ts
npm --prefix api run build
npm run build
git diff --check

当前结果

  • 文件服务单测通过:1 个 test suite、2 个测试通过。
  • API build 通过。
  • 前端 build 通过,仍存在既有 Vite chunk size warning。
  • git diff --check 无空白错误,仅 Windows 工作区 LF/CRLF 提示。

2026-07-06 企业列表人工充值入口

本轮修复

  • 运营端企业管理列表新增“充值”按钮。
  • 点击“充值”打开企业人工充值弹窗,展示企业名称、当前余额,并支持录入充值金额、操作人和备注;充值金额允许负数冲正,0 金额不允许提交;企业列表入口不要求填写短信条数。
  • 提交后调用现有真实接口 POST /api/admin/billing/manual-recharges,成功后重新拉取企业管理列表,余额来自真实账户接口聚合结果。
  • 该入口不使用前端本地状态模拟充值入账;充值订单、账户余额、账户流水和操作日志仍由后端 BillingService.createManualRecharge 负责。

已执行命令

npm run build
git diff --check

当前结果

  • 前端 build 通过,仍存在既有 Vite chunk size warning。
  • git diff --check 无空白错误,仅 Windows 工作区 LF/CRLF 提示。

2026-07-07 手机号段 Tab 和通道组补发上限

本轮修复

  • 运营端手机号段库页面移除自定义卡片式 Tab,改用通用 Tabs 控件,与企业应用管理页面“短信应用/彩信应用”交互一致。
  • 通道组添加/编辑页面新增“补发时间上限(小时)”输入控件,编辑时回填 retryTimeLimitHours,保存时写入真实通道组接口。
  • 补发时间上限按后端现有校验限制为 1 到 72 小时。

已执行命令

npm run build
git diff --check

当前结果

  • 前端 build 通过,仍存在既有 Vite chunk size warning。
  • git diff --check 无空白错误,仅 Windows 工作区 LF/CRLF 提示。

2026-07-07 账单流水页面移除和列表分页

本轮修复

  • 删除客户端账单流水页面和运营端账单流水页面,移除对应路由、菜单、占位映射和首页跳转入口。
  • 移除公开交易查询/创建接口:GET/POST /api/admin/billing/transactionsGET /api/client/billing/transactions
  • 保留内部 AccountTransaction 写入能力,人工充值、扣费、释放、退款等真实计费动作仍可写入内部账务记录;本期不作为独立账单流水页面验收。
  • 通用 Table 组件新增内置分页,默认每页 10 条;服务端分页页面关闭内置分页,避免双分页。
  • 补齐手写列表和卡片列表分页:通道管理、通道组、充值记录、客户端应用、客户端充值套餐、客户端签名、客户端模板、客户端批量任务、客户端发送详情、运营端短信任务进度、运营端企业签名。

已执行命令

npm run build
npm --prefix api run build
npm --prefix api test -- billing.service.spec.ts --runInBand
git diff --check

当前结果

  • 前端 build 通过,仍存在既有 Vite chunk size warning。
  • API build 通过。
  • BillingService 单测通过:1 个 test suite、6 个测试通过。
  • git diff --check 无空白错误,仅 Windows 工作区 LF/CRLF 提示。

2026-07-07 通道组表格和分钟级补发上限

本轮修复

  • 通道组添加/编辑页的省网分流、全国通道配置从卡片改为通用表格展示,行内保留编辑、删除操作。
  • 通道状态文案改为设计锚点口径“链接正常/通道停用”;“链接正常”必须来自真实 CMPP 连接状态 connected 且当前连接数大于 0,新建但未连接的 active 通道不再显示为链接正常。
  • 通道组补发时间上限从整小时升级为分钟级配置,页面交互为“小时 + 分钟”,默认 12 小时 0 分钟;后端新增 retryTimeLimitMinutes 持久化字段,并保留 retryTimeLimitHours 兼容旧调用。
  • 发送链路按分钟级上限判断是否继续补发,超过配置分钟数、超过 72 小时或关闭补发时均不再补发。

已执行命令

npm --prefix api run prisma:generate
npm --prefix api test -- channels.service.spec.ts send-chain.service.spec.ts --runInBand
npm --prefix api run build
npm run build
git diff --check

当前结果

  • Prisma Client 已根据新 schema 生成。
  • ChannelsService 和 SendChainService 定向单测通过:2 个 test suites、35 个测试通过。
  • API build 通过。
  • 前端 build 通过,仍存在既有 Vite chunk size warning。
  • git diff --check 无空白错误,仅 Windows 工作区 LF/CRLF 提示。

2026-07-10 手机号段库大数据分页

本轮修复

  • GET /api/admin/dictionaries/phone-segments 从固定返回前 200 条改为按唯一 prefix 游标分页,支持服务端按号段、运营商、省份和城市搜索。
  • API 每页多读取 1 条计算 hasMore/nextCursor,不执行 50 万级号段表的 COUNT(*)
  • 运营端手机号段页面使用真实服务端分页,移除号段总数卡片、Tab 数字和分页总数,只显示当前页码及上一页/下一页。
  • 生产手机号段数据已从 dannyhu926/phone_location 2026 年 4 月数据导入;源数据 516470 条,过滤 253 条非 7 位异常记录,最终有效 7 位号段 516217 条。

验证口径

  • API 定向单测覆盖游标、搜索、每页多取 1 条和不查询总数。
  • 前端 build 和 API build 必须通过。
  • 生产验证应覆盖首尾翻页、关键词搜索、API/Gateway/PostgreSQL 健康状态和典型号段归属地查询。

已执行命令与结果

npm --prefix api test -- --runTestsByPath src/dictionaries/dictionaries.service.spec.ts
npm --prefix api run build
npm run build
git diff --check
  • DictionariesService 定向单测通过:1 个 test suite、3 个测试通过。
  • API build 和前端 build 通过;前端仍有既有 chunk size warning。
  • 生产 API 实测 pageSize=2:第一页返回 1300000/1300001nextCursor=1300001,下一页返回 1300002/1300003,响应无 total 字段。
  • 生产 API 搜索 1882120 返回“中国移动/上海/上海”;搜索“上海”首屏响应约 80ms。
  • 生产 cmpp-apicmpp-gateway、PostgreSQL、Nginx 均为 activeAPI health 正常。
  • 隔离部署后曾因 dist/assets 被保留为 700 root:root 导致 Nginx 无权读取 JS/CSS、admin 页面空白;线上已修正为目录 755、文件 644,正式生产部署脚本同步固化权限。
  • 正式部署发现已有生产管理员且未配置 PROD_ADMIN_PASSWORD 时,upsert.create 仍会对空密码执行哈希;已拆分 create/update 密码变量,已有账号不改密码,新建账号才生成临时密码。

2026-07-10 Batch 0 飞书瑕疵台账与分批策略

来源:飞书《短信平台第一版瑕疵》。本表仅记录问题路由和验收边界;除 Batch 1 外,其他项目仍须先在生产验证环境只读复现并核对真实代码、API、PostgreSQL、Redis、MinIO 或 Gateway 状态,不能根据页面现象直接修改。

飞书项 初步分类 真实链路/风险 计划批次 当前状态
1.1-1.5 企业-充值流程 UI + API/DB 对象存储预览、人工充值、充值订单、账户流水 Batch 1 已完成并部署;历史余额取 AccountTransaction 快照
2.1 通道密码展示/修改 UI + API/DB + 安全 密码密文、权限、审计、上游连接配置 Batch 2 已完成:密码不回显,留空不覆盖,填写新值才更新
2.2 扩展位数和通道流速 UI + API/DB + Gateway 通道配置持久化、Gateway submit 限速 Batch 2 已完成:真实持久化并下发 Gateway SubmitCommand
2.3 通道组名称为空提示 UI 校验 服务端字段校验与前端错误提示一致 Batch 2 已验证:既有前端提示会在真实 API 调用前中断保存
2.4 发送记录详情弹窗 UI + API 详情、回执、提交记录必须来自真实接口 Batch 2 已完成:真实状态、提交和回执信息分层展示
2.5 连接日志优化 UI + API + Gateway 连接状态回写、操作日志、分页筛选 Batch 2 已完成:展示真实连接状态摘要并支持日志关键词筛选
2.6 通道测试 API/DB + Gateway/CMPP 测试 submit、Redis Stream、上游响应、审计 Batch 2 已完成:提交结果展示真实测试流水和提交记录
2.7 短信记录页面 UI + API/DB + Gateway 短信、submit、回执、分片审计真实查询 Batch 2 已完成:筛选下推 PostgreSQL,详情/审计为真实接口
3.1 报备配置无返回 UI 导航 返回后筛选/表单状态不丢失 Batch 3 已完成:返回通道列表
3.2 通道组添加通道弹窗 UI + API 通道组成员真实保存和回填 Batch 3 已完成:真实候选、状态展示、重复项限制和错误提示
4.1 创建用户 UI + API/DB 用户、角色、企业关联、审计 Batch 4 已完成:真实表单校验、提交状态和错误提示
4.2 禁用/删除/改密后踢下线 API/DB + 会话 Token/session 失效、跨浏览器验证、审计 Batch 4 已完成:数据库会话版本使旧 token 失效
4.3 禁用按钮颜色 UI 仅样式,保持通用危险操作语义 Batch 4 已完成:使用 warning 语义色
4.4 个人改密缺失 UI + API/会话 当前用户校验、密码更新、旧会话失效 Batch 4 已完成:右上角真实当前密码校验与改密
5.1 待审核任务数不准 API/DB 聚合 审核状态口径与任务明细一致 Batch 5 已完成:风险审核改按 SmsSendTask.pending_review 统计
5.2 任务进度 UI + API/DB + Gateway 状态机、发送/回执计数、分页 Batch 5 已完成:未知/超时不重复累计,已处理数不超过总号码数
5.3 企业应用 UI + API/DB 短信应用真实 CRUD/审核;彩信仅占位 Batch 5 已完成:停用使用 warning 色,启用使用 success 色,搜索区宽度协调
5.4 企业模板 UI + API/DB 模板材料、审核状态、真实筛选 Batch 5 已完成:审核状态以中文展示,draft 显示为草稿
5.5 企业签名 UI + API/DB + MinIO 资质文件、签名审核、对象存储预览 Batch 5 已完成:左边框按三网真实报备结果展示,编辑页不允许手工改报备状态
5.6 引流信息 UI + API/DB 字典字段、签名/模板关联、审核口径 Batch 5 已完成:列表改为引流信息、长链接不跳转且省略展示、操作列可见,编辑页不允许手工改报备状态
6.1 手机号段库 Tab UI 使用通用 Tabs,不改变真实号段数据路径 Batch 6 已完成:Tab 按内容宽度展示
6.2 运营商区分规则分页 UI + API/DB 服务端分页、筛选与总数口径 Batch 6 已完成:PostgreSQL 分页、总数、25 条每页
7.1 敏感词页 UI + API/DB 敏感词 CRUD、生效范围、发送校验 Batch 6 已完成:状态 Tag 清晰展示,添加弹窗扩展,保留真实 CRUD
8.1 系统日志 IP 为空 API/DB + Nginx 转发头、请求上下文、OperationLog 落库、历史数据边界 Batch 6 已完成:真实 HTTP 操作日志记录 Nginx 转发的客户端 IP;后台任务保持空值
8.2 客户端标题 UI 客户端产品名称与运营端区分 Batch 6 已完成:短信平台客户端
8.3 通用输入框/文本框样式 UI 去除内层填充色,保留边框和焦点状态 回归复查 已完成:含 Chromium 自动填充背景
8.4 精确时间格式 UI 所有精确时间统一 YYYY-MM-DD HH:mm:ss Batch 6 已完成:统一 helper 覆盖日志、用户、充值、任务与配置展示
8.5 中文图片文件名乱码 API/DB + MinIO + UI multipart 编码、对象存储文件名、历史展示兼容 回归复查 已完成:新上传正确入库,历史展示兼容解码
8.6 全局分页控件 UI + API/DB 总页数、首页/末页、指定页跳转与服务端分页口径 Batch 6 已完成:统一控件支持首页、末页、页码跳转;真实服务端分页页传入总页数
9.1 客户端菜单顺序 UI 签名与引流信息菜单位于模板管理之前 Batch 6 已完成

执行约束

  • 每个 Batch 先只读复现并记录页面、API、DB、Gateway 分类,再做最小真实修复。
  • 纯 UI 项也必须确认页面数据源不是 mock、localStorage 或静态数组;未实现后端的彩信仅保留待开发占位。
  • 每批结束执行相关 API 测试、API build、前端 build;涉及 Gateway 时追加 Go 测试和生产 Gateway health/CMPP 验证。
  • 完成后更新本文件;未经明确要求不提交或推送代码。

2026-07-10 Batch 1 企业充值流程瑕疵

本轮修复

  • 企业新建/编辑页的图片“预览”改为站内弹窗展示,不再跳转或新开页面;下载仍走真实对象存储文件接口。
  • 通用 InputSelectTextarea 根据 required 属性显示必填标识;企业资料和人工充值弹窗不再依赖页面散落的文案约定。
  • 运营端充值记录列表的“充值后余额”改为真实订单关联 AccountTransaction.balanceAfter;不再用当前 TenantAccount 余额冒充历史快照。没有可追溯流水的历史记录显示 -
  • 人工充值弹窗补齐非零校验、提交中禁用和 API 失败提示;提交仍调用 POST /api/admin/billing/manual-recharges,成功后刷新真实记录。
  • 企业名称与统一社会信用代码已经使用同一双列栅格,本轮复现未见对齐问题,不做无效样式改动。

验证口径

  • GET /api/admin/billing/manual-recharges 必须基于 Prisma/PostgreSQL 的 RechargeOrder 和关联 AccountTransaction 返回余额快照。
  • TC-BILLING-006 增加断言:充值记录“充值后余额”等于关联账务流水的 balanceAfter,与后续充值或消费后的当前余额无关。

已执行命令与结果

npm --prefix api test
npm --prefix api run build
npm run build
git diff --check
  • API 全量单测通过:12 个 test suites、113 个测试通过;新增 BillingService 覆盖两笔人工充值分别返回其历史余额。
  • API build 和前端 build 通过;前端仍有既有 Vite chunk size warning。
  • git diff --check 无空白错误,仅 Windows 工作区 LF/CRLF 提示。
  • 已按生产标准脚本部署到 8.160.169.106Prisma migration deploy 无待执行迁移,cmpp-apicmpp-gateway、Nginx、MinIO 均为 activeAPI/Gateway health、Redis 均通过。
  • 生产管理员真实登录后只读调用 GET /api/admin/billing/manual-recharges 成功返回 2 条记录,响应包含真实 balanceAfterCents10000、1000)。

2026-07-10 Batch 2 通道配置真实链路

本轮修复

  • 运营端通道编辑/新建页的“通道流速”不再固定提交 100;输入值按 1-2000 TPS 校验后写入 SmsChannel.rateLimitPerSecond,发送链路和通道测试继续从该真实字段生成 Gateway SubmitCommand.route.rateLimitPerSecond
  • “扩展位数”仅允许 0/2/4/6,持久化到 SmsChannel.config.extensionDigits;编辑页回填该值,普通发送和通道测试均将其放入 Gateway SubmitCommand.cmpp.extensionDigits
  • NestJS 更新通道时修正 config 合并行为:传入的配置会与既有 JSON 配置合并,不会再被 desiredConnections/windowSize 规范化过程静默丢弃。
  • 网关密码保持安全策略:编辑时不回显已配置密码,留空不覆盖;输入新密码才更新真实通道配置。

已执行命令与结果

npm --prefix api test -- channels.service.spec.ts --runInBand
npm --prefix api run build
npm run build
go test ./internal/queue ./internal/upstream
git diff --check
  • ChannelsService 和 SendChainService 定向测试通过:2 个 test suites、55 个测试通过;ChannelsService 单独测试 23 项,覆盖流速、扩展位数持久化和非法配置拒绝。
  • API build、前端 build、Gateway queue/upstream 测试通过;前端仍有既有 Vite chunk size warning。
  • 已重新部署生产验证环境;Prisma migration deploy 无待执行迁移,cmpp-apicmpp-gateway、Nginx、MinIO 均为 activeAPI/Gateway health 正常。生产运行源码已确认包含流速校验、扩展位数持久化及 Gateway 队列字段。
  • 通道组名称为空时已有前端提示“请输入通道组名称”,保存会在调用真实创建/更新 API 前中断;本轮复核后不重复改动。
  • 通道编辑密码保持掩码且不回显:编辑时明确提示“留空保持不变,填写新密码才更新”;新建通道仍要求填写密码。
  • 上述密码交互调整已于 2026-07-10 生产验证部署后再次核验:cmpp-apicmpp-gateway、Nginx、MinIO 均为 active,内外部 health/HTTP 检查通过。
  • 短信记录列表修复:企业、应用、手机号、状态之外的提交日期、短信内容、通道名称筛选改为传给 GET /api/admin/operations/messagesNestJS 通过 Prisma/PostgreSQL 执行内容、关联通道名和上海自然日范围查询,页面不再仅筛选已加载的前 500 条记录。
  • 生产只读复现确认:短信记录 9 条均有真实 SmsSubmitRecord,其中 4 条已有真实 SmsReceiptRecord3 个通道均有 CmppConnectionStateOperationLog 连接日志。按一条生产记录的日期、内容、通道关键词组合查询,9 条中仅返回 1 条且条件均匹配。
  • OperationsService 定向测试 12 项、API build、前端 build 均通过;已部署生产验证,cmpp-apicmpp-gateway、Nginx、MinIO 均为 activeAPI/Gateway health 正常。
  • 发送详情弹窗重组为真实状态摘要、短信内容、通道提交/回执轨迹、状态信息和分片补偿审计;提交轨迹新增真实 submitStatus,不再只展示时间和回执码。
  • 连接日志弹窗新增 CmppConnectionState 摘要(连接 ID、状态、当前/期望连接数、最近心跳、最近错误),日志内容以真实 OperationLog.detail 可读格式呈现,并仅对已返回日志做关键词筛选。
  • 通道测试成功后展示 API 返回的真实 testNo、提交数量、手机号与 SmsSubmitRecord.submitId,禁用重复提交,并提供跳转至短信记录入口;没有虚构“发送成功”或模拟回执。

2026-07-10 Batch 3 通道报备与通道组配置

  • 通道报备配置页新增返回通道列表入口,沿用现有 /admin/channels/:channelId/reports 路由的来源页面,避免运营人员进入配置页后没有回退路径。
  • 通道组“添加通道”弹窗不再使用固定省份数组:省份和候选通道均来自 GET /api/admin/channels,按真实运营商、地区和已绑定通道过滤;选中后展示通道代码、地区和真实连接状态。
  • 弹窗在省份、优先级或通道未选择时提供表单错误提示;没有符合条件的候选时显示可读空态。前端仅做交互约束,最终仍由 NestJS ChannelsService 校验运营商/地区兼容性、重复通道和优先级规则,并持久化到 SmsChannelGroupItem
  • 已执行 npm --prefix api test -- channels.service.spec.ts --runInBand23 项通过)、npm run buildgit diff --check;前端保留既有 Vite chunk size warning。
  • 已部署生产验证:Prisma migration deploy 无待执行迁移,cmpp-apicmpp-gateway、Nginx、MinIO 均为 activeAPI/Gateway health 正常;生产只读接口返回 3 个真实通道(其中 2 个启用)、1 个真实通道组和 2 个组成员。

2026-07-10 Batch 4 用户管理与会话失效

  • User.sessionVersion 真实持久化到 PostgreSQL;登录 token 携带该版本。浏览器携带 token 请求时,NestJS 会话中间件校验用户状态、删除状态和版本;禁用、删除、管理员改密和个人改密都会递增版本,使原会话在下一次请求被 401 拒绝,前端清理本地会话并跳回对应登录页。
  • 为避免破坏 Gateway 与现有服务间无浏览器会话链路,中间件仅校验带 Authorization 的浏览器 token;未携带该 header 的既有内部请求保持原行为。
  • 右上角“修改密码”补齐真实 POST /api/auth/password:要求当前密码、新密码(至少 6 位)和确认密码一致;成功后当前会话立即失效并回到登录页,写入操作日志。
  • 运营端和客户端用户新建补齐姓名、至少一个联系方式、初始密码/企业关联等前端校验,提交中禁用按钮并展示 API 错误;用户禁用操作改用通用 warning 语义色。
  • 已执行 npm --prefix api run prisma:generatenpm --prefix api test -- auth.service.spec.ts session-validation.middleware.spec.ts users.service.spec.ts --runInBand3 suites、8 项通过)、npm --prefix api run buildnpm run buildgit diff --check;前端保留既有 Vite chunk size warning。
  • 已部署生产验证:第 25 条 Prisma migration 20260710153000_add_user_session_version 成功应用;cmpp-apicmpp-gateway、Nginx、MinIO 均为 activeAPI/Gateway health 正常。生产管理员新登录 token 为版本格式且可读取真实用户列表;伪造旧版本 token 被 401 拒绝,验证会话版本失效生效。

2026-07-10 Batch 5 审核与企业配置

  • 修复 Dashboard 待审核聚合:短信审核的真实状态存储在 SmsSendTask.status=pending_review,原逻辑错误统计 SmsBatchTask.auditStatus=pending。聚合现统一模板、签名、企业认证和风险审核的真实待审状态。
  • 生产 PostgreSQL 与对应 API 在部署后均显示四类待审为 0,Dashboard 也为 0,当前数据口径一致;无非零待审样本,未将该 0 值当作非零场景的充分验收。
  • 任务进度、企业应用、企业模板、企业签名与引流字段页面均使用真实 NestJS API;生产只读接口成功返回任务、应用、模板、签名和引流字段数据,不存在 mock/localStorage 回退。
  • 已根据下载的瑕疵文档修复 5.2-5.6:任务进度不重复累计未知/超时,企业应用启停语义色与搜索区,模板中文审核状态,签名三网状态驱动边框且移除人工状态选择,引流信息标题、链接展示、操作列和人工状态选择。
  • 已执行 npm --prefix api test -- operations.service.spec.ts --runInBand(12 项通过)、前端 build 和 git diff --check;已部署生产验证,cmpp-apicmpp-gateway、Nginx、MinIO 均为 activeAPI/Gateway health 正常。

2026-07-10 瑕疵回归复查

  • 逐图复查下载的《短信平台第一版瑕疵》后,确认中文图片文件名乱码仍真实存在:生产 FileObject.fileName 中可见 UTF-8 被按 Latin-1 解释后的值。上传链路现先恢复 multipart 文件名编码;历史记录由前端展示层兼容解码,避免签名材料和企业认证页继续显示乱码。
  • 通用输入框、文本框去除内部填充色;同时覆盖 Chromium 自动填充产生的蓝色内层背景。企业认证页此前额外写死的灰色输入背景已移除。
  • 已执行 FilesService 定向单测(3 项通过)、API build、前端 build 和 git diff --check;生产部署后四个服务均为 activeAPI/Gateway health 正常。通过真实 POST /api/admin/files/upload 上传 营业执照-编码回归.png,响应和 FileObject 持久化文件名均为正常中文。
  • Batch 6 的 6.1、6.2、7.1、8.1 仍为待修,不得因之前的前端构建通过而标记完成;其余 8.x 与客户端菜单顺序将继续按原始文档逐项复核。