147 KiB
147 KiB
第一版系统化测试进度
2026-07-09 运营端通道测试短信闭环修复
- 生产验证发现运营端通道“短信测试”弹窗仅关闭页面,未调用后端;
POST /api/admin/channels/:id/test仍返回 phase-4 placeholder,不创建SmsMessageRecord/SmsSubmitRecord,也不写入 Gateway SubmitCommand,因此短信记录页面无记录。 - 已修复为真实链路:前端提交手机号、内容和可选接入号;NestJS 校验通道 active 且存在在线 CMPP 连接后,创建独立
SmsMessageRecord、SmsSubmitRecord和操作日志,并向 BullMQgateway.submit.queue与 Redis Streamgateway.submit.commands写入真实SubmitCommand。通道测试不绑定企业、企业应用或SmsBatchTask发送任务。 - 测试口径同步:
TC-ADMIN-003增加通道测试短信闭环要求,必须能从页面/API 发起真实测试短信,短信记录页面可查询到对应记录,Gateway submit worker 按通道真实 CMPP 配置消费发送。 - 已执行:
npm --prefix api test -- channels.service.spec.ts --runInBand、npm --prefix api run build、npm run build。待生产部署后用指定号码做一次真实发送验证,并回查 DB/短信记录。 - 2026-07-09 追加:按产品边界收窄通道测试短信,
SmsMessageRecord/SmsSubmitRecord/SmsReceiptRecord/SmsMessageSegmentAudit支持tenantId/batchTaskId为空;通道测试只记录短信、提交结果和回执,不进入企业账务、发送任务进度、客户侧 Deliver 推送或业务补发。 - 2026-07-09 追加:生产验证短信进入 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,确认只处理Cmpp3DeliverReqPkt,CMPP 2.0 回执 Deliver 即使到达连接也不会 ACK 或进入 receipt 事件链路。已修复为同时处理Cmpp2DeliverReqPkt/Cmpp3DeliverReqPkt,分别返回Cmpp2DeliverRspPkt/Cmpp3DeliverRspPkt,并统一 Deliver 解码、回执和上行处理。新增deliver_test.go覆盖 CMPP 2.0DELIVRD回执写入事件链路。 - 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新增interfaceEnabled、interfaceType持久化字段;企业应用创建、编辑、列表和 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:generate、npm --prefix api test -- sms-config.service.spec.ts send-chain.service.spec.ts、npm --prefix api run build、npm run build、git diff --check、npm --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,复制日志补充sourceStatus和copiedStatus,避免 active 通道副本自动占用上游连接。 - Gateway
ConnectChannel改为直接建立/复用真实上游连接池,并由连接池回写connected/failed/disconnected、currentConnections、最近错误和断开时间;连接丢失时状态随真实连接数变化更新。
- 通道复制后统一保存为
- 测试口径同步:
TC-ADMIN-003增加“连接状态必须来自真实上游连接池回写”的要求。TC-ADMIN-016明确复制 active 通道后副本默认disabled,且不会立即触发上游真实连接。
- 已执行:
npm --prefix api test -- channels.service.spec.ts --runInBand、npm --prefix api run build、go test ./internal/control ./internal/upstream、go build -o ..\\dist\\cmpp-gateway .\\cmd\\gateway。
2026-07-09 线上通道 CMPP 版本修复
- 线上生产验证发现 3 个赛邮行业通道配置均指向
121.40.172.212:7890,其中 2 个已触发 Gateway 真实连接并失败,CmppConnectionState.lastError为packetWriter.ReadBytes error: ReadBytes reads 14 bytes, not equal to 16 we expected。 - 生产机到上游
121.40.172.212:7890TCP 可连接,失败不是 API/Gateway 服务不可用,也不是网络完全不通;结合上游确认参数为 CMPP 2.0,根因定位为通道创建默认 CMPP 3.0 且运营端没有版本选择入口。 - 已修复通道创建/编辑:运营端新增 CMPP 2.0/3.0 版本选择,默认 2.0;NestJS 通道 API 默认
cmppVersion=2.0,并只允许 2.0 或 3.0;PrismaSmsChannel.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固化到SmsMessageRecord,BullMQ 入队按 priority/normal 写入不同 job priority,SubmitCommand 契约、示例和 Go Gateway 队列结构已增加queuePriority;当前实现覆盖优先队列插队的基础能力,持续高优先级流量下普通队列防饥饿策略仍需后续压测和调度增强。 - 2026-07-07 追加:Gateway 队列契约第 8 步已独立校验,
SubmitCommandschema/example 要求queuePriority,Go GatewaySubmitCommand结构可反序列化该字段,并通过npm run spike:contracts与npm run spike:gateway。 - 2026-07-07 追加:第 9 步收口验证通过:
npm --prefix api run prisma:generate、npm --prefix api test -- sms-config.service.spec.ts send-chain.service.spec.ts --runInBand、npm run spike:contracts、npm run spike:gateway、npm --prefix api run build、npm 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 --runInBandnpm --prefix api run buildnpm 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返回前转换为字符串,避免 PrismaBigIntJSON 序列化 500。
- 启动脚本在 MinIO 不可用时启用本地对象存储
- 已执行:
npm --prefix api test -- tenants.service.spec.ts files.service.spec.ts --runInBandnpm --prefix api run buildnpm run buildPOST http://localhost:3000/api/admin/files/uploadmultipart 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.exe、C:\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-storagefallback;启动完成提示会区分 MinIO 是否真实运行。 - MinIO 模式下对象存储服务会在上传/预签名前自动确认并创建
cmpp-platformbucket。 - 已执行:
npm --prefix api run buildnpm 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.drainageInfoJSON,文件上传走真实admin/files/upload并保存FileObject引用。 - 已执行:
npm --prefix api run prisma:generatenpm --prefix api test -- sms-config.service.spec.ts channels.service.spec.ts --runInBandnpm run buildnpm --prefix api run buildnpm --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 testnpm --prefix api test -- <spec>
- 根目录新增脚本:
npm run test:apinpm 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 Jest:5 个 test suite 通过,22 个测试通过。
- Gateway:
npm 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、Redislocalhost:6379、MinIOlocalhost: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 预签名上传、运营日志、发送链路追踪和账务对账聚合。
- PostgreSQL
- 第 4 步发送前置校验 smoke 通过:
TC-TEMPLATE-001、TC-TEMPLATE-002、TC-TEMPLATE-003 / TC-RISK-005、TC-RISK-001、TC-RISK-002、TC-RISK-003、TC-RISK-004、TC-BILLING-001 / TC-TEMPLATE-005、TC-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-004、TC-SEND-005、TC-SEND-006、TC-SEND-007、TC-SEND-008、旧版TC-SEND-009 / TC-SEND-010均通过。- 2026-07-03 新增的通道组真实路由用例
TC-SEND-010到TC-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-001、TC-BILLING-002 / TC-RECHARGE-001、TC-BILLING-003、TC-BILLING-004 / TC-BILLING-005 / TC-BILLING-006 / TC-BILLING-007、TC-BILLING-008 / TC-RECON-001 seed、TC-RECON-001、TC-DASHBOARD-001 / TC-STAT-001、TC-TRACE-001、TC-BILLING-009均通过。- 验证了费用预估、人工充值、余额检查、冻结、扣费、释放、退款、短信计费记录、账务流水、dashboard/statistics、trace 和 reconciliation。
- 自动计费探测发现发送任务不会自动生成短信计费记录、账户交易流水,消息金额默认为 0,已在
docs/testing-execution-step-6.md记录为发送计费集成缺口。
- 第 7 步客户/通道 CMPP 连接状态和 Gateway smoke 通过:
TC-GW-CONTRACT-001、TC-GW-001、TC-GW-002、TC-GW-003、TC-GW-004、TC-CMPP-STATUS-001 / TC-CHANNEL-001、TC-CHANNEL-ROUTE-001、TC-CHANNEL-METRIC-001、TC-CMPP-SESSION-001 / TC-CONNECTION-COUNT-001、TC-CMPP-STATUS-002 / TC-OPERATIONS-MONITOR-001、TC-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 TPS;Prisma 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增加scheduledAt、canceledAt字段和status/scheduledAt索引。CreateBatchTaskDto支持sendMode=scheduled、scheduledAt。- 新增定时任务取消和到点触发入口:
POST /api/client/send/batch-tasks/:id/cancel、POST /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 连接状态模型/API,Gateway 或本地 Gateway 模拟器可通过真实 API 回写连接状态,运营 dashboard 聚合连接状态。
- 新增应用密钥重置、应用/签名/模板状态变化、通道启停接口,并写入系统日志。
- 无效
createdById、reviewerId改为明确 400,不再冒泡数据库外键 500。
- 新增企业认证模型/API,提交、审核通过、驳回会同步
新增/更新测试
| 测试文件 | 新增覆盖 |
|---|---|
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_fields20260701110000_add_certification_and_connection_state
- API build 通过。
- API Jest:7 个 test suite 通过,34 个测试通过。
- 最终回归通过:
npm run verify:phase8通过,BullMQ 15000 条消息、并发 500、端到端 TPS 608.93,满足 500 TPS;Prisma 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:基于OperationLog和CmppConnectionState查询连接日志;保留/link-logs兼容旧前端。
- 安全控制补齐真实 API:敏感词、全局黑名单、企业黑名单支持 keyword/status 查询、创建、启停/软删除,并写操作日志。
- 企业黑名单修正为企业应用级黑名单:Prisma
EnterpriseBlacklist新增applicationId并改为applicationId + phoneNumber唯一;运营端页面按企业和短信应用新增/搜索;发送预览和风控只命中当前应用的 active 黑名单。 - 模板审核补齐真实查询:运营端模板列表支持 keyword/status,并返回企业、应用、签名信息;前端模板审核页已改为调用真实 API。
- 运营端企业模板管理新增短信模板时,后端直接写入
auditStatus=approved;短信模板审核页展示为“已通过”,客户端自行提交模板仍保留审核流。 - 企业认证审核补齐真实查询:列表支持 keyword/status,详情返回企业信息和认证 materials;前端企业认证审核页已改为调用真实 API。
- 前端新增
/apiVite 代理和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 Jest:8 个 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 新增浏览器和业务闭环用例执行
执行环境
- API:
npm --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 被占用后切换到 5174,Vite 首次依赖 bundling 长时间未完成,浏览器看到白屏;生产构建和 preview 渲染正常。- 运营端人工充值页面当前是前端本地状态 smoke,不能作为系统功能通过;真实入账闭环通过
POST /api/admin/billing/manual-recharges验证。 - 人工充值不需要审批,测试口径已同步修正为“有权限确认即入账,不产生 pending 审批态”。
真实后端缺口和 Bug 清单
| 编号 | 严重级别 | 问题 | 证据 | 期望修复 |
|---|---|---|---|---|
| BUG-FE-001 | P0 | 运营端人工充值页面未调用真实后端,提交后只更新前端本地表格状态。 | src/apps/admin/AdminRechargeRecordsPage.tsx 使用 rechargeRecordsSeed 和 useState,submitManualRecharge 只 setRecords。 |
页面提交调用 POST /api/admin/billing/manual-recharges,成功后刷新真实充值记录、账户余额、流水和日志。 |
| BUG-FE-002 | P0 | 运营端 Dashboard 仍使用 mock service 和静态排行,不能证明真实统计准确。 | src/apps/admin/AdminHome.tsx 引用 adminService、hourlySendTrend、auditTrend,指标从前端数组计算。 |
接入 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.tsx、src/apps/client/ClientSystemLogsPage.tsx 页面 smoke 可展示,但未证明调用真实日志 API。 |
接入真实日志 API,支持分页、筛选、详情、租户隔离,失败动作也可查。 |
| BUG-FE-005 | P0 | 企业应用 CMPP 状态和连接详情页面仍使用本地初始数据,未读取真实连接状态 API。 | src/apps/admin/AdminEnterpriseApplicationsPage.tsx 使用 initialSmsApps、setSmsApps,连接删除也是本地状态变更。 |
接入企业应用、连接状态、连接详情、连接删除/断开真实 API 或 Gateway 回写接口。 |
| BUG-API-001 | P1 | 通道创建参数缺失时返回 Prisma 500,而不是业务 400。 | 浏览器 smoke 第一轮 POST /api/admin/channels 缺少 code/gatewayHost/gatewayPort/account/passwordCipher/srcId,API 返回 Internal server error。 |
为通道创建 DTO 增加校验,缺失必填字段返回 400 和可读错误,并写失败日志。 |
| BUG-DEV-001 | P1 | npm run dev 在 5173 被占用后切到 5174,Vite 依赖 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 | 通道组省网/全国路由没有接入真实发送链路,手机号段库也未参与归属地识别。 | SmsChannelGroupItem 和 ChannelRouteRule 虽有 carrier/province 字段,PhoneSegment 有 prefix/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、连接connected、desiredConnections > 0且currentConnections > 0才可选;online/open仅作为旧 Gateway 回写兼容词入库归一化。 - BUG-CMPP-STATUS-001:新建/启用通道后若 Gateway 连接请求长时间无回写,API 后台兜底任务会将超过 30 秒的
connecting连接标记为failed,写入超时原因和连接日志,避免页面长期停留“连接中”。 - BUG-SEND-004:submit 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 Jest:10 个 test suite 通过,50 个测试通过。
- API build:通过。
- 前端 build:通过,仍存在既有大 chunk warning。
npm run verify:phase8:未通过,阻塞在spike:bullmq性能阈值;第一次 endToEndTps=464.58,复跑npm run spike:bullmqendToEndTps=495.97,第三次 endToEndTps=477.17,均低于 500 TPS 阈值。- 尚未执行真实 PostgreSQL/Redis/Gateway 端到端 smoke;需在生产验证或本地真实服务环境中覆盖
TC-SEND-010到TC-SEND-018、TC-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 build再vite 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 Jest:8 个 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 持久化字段:
email、phone、failedLoginCount、lockedUntil、lastLoginAt、deletedAt。 - 登录入口拆分为
/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.ts、auth.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 Jest:10 个 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_carrier20260703152000_add_application_customer_rate
- API Jest:10 个 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 位
cmppAccount,Prisma 迁移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/submit;NestJS 按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_received、submit_accepted、submit_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 断开不记为解包失败。 - 生产复现确认 CMPP2.0 客户 Submit 被固定 CMPP3.0 解包导致
MsgSrc/手机号/内容错位为空。现在 gocmpp server 按 CONNECTVersion将每条连接切换到 CMPP2.0/2.1/3.0 解包模式,并返回同版本 ConnectResp、SubmitResp 和 Deliver。 - Gateway 使用 bind 时已鉴权会话账号调用 NestJS 入站接口,Submit
MsgSrc改为与鉴权返回的应用级cmppEnterpriseCode独立比对,不再将企业代码误当登录账号。
验证状态
go test ./internal/inbound -count=1:通过。go test ./... -count=1:通过。go build ./cmd/gateway:通过。- 真实 TCP 非法包用例:向入站端口写入非法
total_length,确认业务 handler 未执行时仍产生read/unpack packet failed日志。 - CMPP2.0 真实集成用例:客户使用与登录账号不同的
MsgSrc=SP0001,完成 V20 ConnectResp、Cmpp2SubmitReq/Resp 和 Cmpp2Deliver Receipt,NestJS 收到的 account 仍为 bind 账号:通过。 - 已将合并后提交
bb4992f0部署到生产验证环境;Prisma 无待执行迁移,前端/API/Gateway 构建和标准健康检查通过,12026/3000/8090/17890 监听正常。生产账号910887重连日志确认requested_version=0x20 response_version=0x20;该测试应用的cmppEnterpriseCode已通过真实运营 API 同步为910887。
2026-07-07 Gateway 上游提交与下游 Deliver 闭环补齐
本轮修复
SubmitCommand契约、示例和 Go 结构增加upstream.gatewayHost/gatewayPort/account/passwordCipher/cmppVersion,API 发送链路在真实业务校验通过后保留 BullMQ 审计投递,同时写入 Redis Streamgateway.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/uplink,Gateway 向在线客户下发 CMPP Deliver Receipt 或普通 Deliver。 api/src/send-chain/send-chain.service.spec.ts覆盖 SubmitCommand 上游配置和 Redis Stream 发布;gateway/internal/inbound/server_test.go覆盖客户 submit 后平台下发 Deliver Receipt;Gateway 契约示例覆盖新 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 Streamgateway.submit.commands触发。worker 当前覆盖新消息>消费和 ack,pending 历史消息扫描与精细重试治理放入后续在途恢复阶段。 - 客户侧 Deliver Receipt/上行 Deliver 当前依赖 Gateway 内存在线连接映射;客户断线、Gateway 重启或映射丢失时尚未实现持久化缓存、重试和投递失败审计。
- 普通上行只有能关联 messageId 的事件可推送给客户;仅按接入号、手机号、应用和时间窗口匹配客户连接仍待产品化。
- 长短信拆分/重组、多连接窗口、窗口满、在途消息恢复、断线重连后的状态补偿仍待后续实现和压测。
2026-07-07 阶段 1:Gateway SubmitCommand 独立消费
本轮修复
- NestJS SendChain 取消主链路同步调用 Gateway
/upstream/submit;真实业务校验通过后创建 SmsSubmitRecord、保留 BullMQgateway.submit.queue审计/兼容投递,并向 Redis Streamgateway.submit.commands写入SubmitCommand。 - Go Gateway 新增
submitworker,启动时默认创建/复用 consumer groupcmpp-gateway,独立消费 Redis Stream 中的SubmitCommand,调用同一个上游提交管理器真实 submit 到上游 SMSC。 - Gateway
/upstream/submit保留为调试/运维补偿接口,不作为 API 主发送路径。 - Gateway worker 支持环境变量:
REDIS_URL、GATEWAY_SUBMIT_STREAM、GATEWAY_SUBMIT_GROUP、GATEWAY_SUBMIT_CONSUMER、GATEWAY_SUBMIT_WORKER_DISABLED=true。
验收口径
- API 入队后不再因为 Gateway 控制面短暂不可达而自己生成 timeout;SubmitResult 必须由 Gateway worker 真实消费和提交后回调。
- Gateway 停止时,SubmitCommand 留在 Redis Stream;Gateway 恢复后由 consumer group 继续消费新消息。
- BullMQ
gateway.submit.queue仅作为审计/兼容,不再是唯一主提交通道。
剩余边界
- 当前 worker 先覆盖新消息
>消费和 ack;pending 历史消息扫描、claim、重试退避和死信审计放到在途恢复阶段继续做。
2026-07-07 阶段 2/3:客户侧 Deliver 持久化重投与普通上行匹配
本轮修复
- Prisma 新增
CmppDownstreamDelivery,用于保存客户侧待投递 Deliver Receipt 和普通 Deliver 上行;状态覆盖 pending/delivered,记录 retryCount、nextRetryAt、lastError、payload、message/application 关联。 SmsUplinkMessage增加applicationId、messageRecordId、matchStatus、matchReason,并建立应用和匹配下发记录关系。- 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 阶段 4:Gateway 长短信拆分与长上行重组
本轮修复
- 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 阶段 5:Gateway 多连接窗口与窗口满控制
本轮修复
SubmitCommand.upstream契约、示例、Go 结构和 NestJS 生产者增加desiredConnections/windowSize,字段来自通道真实配置;未配置时默认desiredConnections=1、windowSize=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 阶段 6:CMPP 配置入口补齐
本轮修复
- 运营端通道创建/编辑表单新增上游
desiredConnections和windowSize输入,真实提交到 NestJS 通道 API,并规范化写入SmsChannel.config。 - NestJS
ChannelsService对desiredConnections/windowSize增加正整数校验;通道激活后的ConnectChannel请求和发送链路SubmitCommand.upstream均复用该真实配置。 - Prisma 为
SmsApplication新增cmppMaxConnections、cmppWindowSize字段;运营端短信应用创建/编辑表单新增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 阶段 7:SubmitCommand 在途恢复第一步
本轮修复
- 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 阶段 9:receipt 驱动的保守二次归因
本轮修复
- 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 阶段 10:SubmitCommand 死信治理第一版
本轮修复
- 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 阶段 18:Gateway 恢复候选视图
本轮修复
- 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 阶段 19:Gateway pending 恢复执行第一版
本轮修复
- Gateway 启动时会立即按恢复候选账号执行一次 pending 下游投递恢复扫描。
- 后续每轮补投周期除扫描当前内存在线账号外,也会继续扫描恢复候选账号,尝试恢复
CmppDownstreamDelivery.pending。 - 当前恢复策略是“能投就投,投不了继续 pending”:若账号尚无可用下游连接,Gateway 不会把记录误标成失败,而是等待客户重连后的后续恢复机会。
验证状态
go test ./internal/inbound/...:通过。go test ./internal/control/...:通过。go test ./cmd/gateway/...:通过。
剩余边界
- 当前恢复仍按固定扫描周期触发,尚未做更细的按账号退避、恢复批次追踪和恢复告警。
- 仍未覆盖更复杂的长短信分片恢复、跨实例抢占协调和恢复中的重复投递防抖。
2026-07-08 阶段 20:Gateway 恢复退避、锁与状态审计
本轮修复
- Gateway 新增账号级恢复锁,避免同一
cmppAccount被并发重复恢复。 - 恢复失败、等待连接和部分成功场景会写入真实恢复状态,并按指数退避计算下一次可恢复时间,减少无意义高频重试。
- 控制面新增
GET /downstream/recovery-statuses,可查看账号最近恢复状态、尝试次数、下一次重试时间和错误原因。
验证状态
go test ./internal/inbound/...:通过。go test ./internal/control/...:通过。go test ./cmd/gateway/...:通过。
剩余边界
- 当前恢复状态审计仍停留在 Gateway 控制面和 Redis,尚未同步到运营端页面或 NestJS 持久化审计表。
- 恢复退避当前按账号统一处理,尚未细分到回执/上行类型、失败类别或跨实例抢占优先级。
2026-07-08 阶段 21:Gateway 恢复总览与链路缺口收口
本轮修复
- 控制面新增
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/lockExpiresAt,Gateway 回传并由 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 APIhttp://localhost:9000、Consolehttp://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:认领后更新SmsUplinkMessage为matched,选中候选置为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 Jest:12 个 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-tasksHTTP 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 Jest:12 个 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/transactions和GET /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_location2026 年 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/1300001和nextCursor=1300001,下一页返回1300002/1300003,响应无total字段。 - 生产 API 搜索
1882120返回“中国移动/上海/上海”;搜索“上海”首屏响应约 80ms。 - 生产
cmpp-api、cmpp-gateway、PostgreSQL、Nginx 均为 active,API 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 企业充值流程瑕疵
本轮修复
- 企业新建/编辑页的图片“预览”改为站内弹窗展示,不再跳转或新开页面;下载仍走真实对象存储文件接口。
- 通用
Input、Select、Textarea根据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.106;Prisma migration deploy 无待执行迁移,cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,API/Gateway health、Redis 均通过。 - 生产管理员真实登录后只读调用
GET /api/admin/billing/manual-recharges成功返回 2 条记录,响应包含真实balanceAfterCents(10000、1000)。
2026-07-10 Batch 2 通道配置真实链路
本轮修复
- 运营端通道编辑/新建页的“通道流速”不再固定提交
100;输入值按1-2000 TPS校验后写入SmsChannel.rateLimitPerSecond,发送链路和通道测试继续从该真实字段生成 GatewaySubmitCommand.route.rateLimitPerSecond。 - “扩展位数”仅允许
0/2/4/6,持久化到SmsChannel.config.extensionDigits;编辑页回填该值,普通发送和通道测试均将其放入 GatewaySubmitCommand.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-api、cmpp-gateway、Nginx、MinIO 均为 active,API/Gateway health 正常。生产运行源码已确认包含流速校验、扩展位数持久化及 Gateway 队列字段。 - 通道组名称为空时已有前端提示“请输入通道组名称”,保存会在调用真实创建/更新 API 前中断;本轮复核后不重复改动。
- 通道编辑密码保持掩码且不回显:编辑时明确提示“留空保持不变,填写新密码才更新”;新建通道仍要求填写密码。
- 上述密码交互调整已于 2026-07-10 生产验证部署后再次核验:
cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,内外部 health/HTTP 检查通过。 - 短信记录列表修复:企业、应用、手机号、状态之外的提交日期、短信内容、通道名称筛选改为传给
GET /api/admin/operations/messages;NestJS 通过 Prisma/PostgreSQL 执行内容、关联通道名和上海自然日范围查询,页面不再仅筛选已加载的前 500 条记录。 - 生产只读复现确认:短信记录 9 条均有真实
SmsSubmitRecord,其中 4 条已有真实SmsReceiptRecord;3 个通道均有CmppConnectionState和OperationLog连接日志。按一条生产记录的日期、内容、通道关键词组合查询,9 条中仅返回 1 条且条件均匹配。 OperationsService定向测试 12 项、API build、前端 build 均通过;已部署生产验证,cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,API/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 --runInBand(23 项通过)、npm run build和git diff --check;前端保留既有 Vite chunk size warning。 - 已部署生产验证:Prisma migration deploy 无待执行迁移,
cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,API/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:generate、npm --prefix api test -- auth.service.spec.ts session-validation.middleware.spec.ts users.service.spec.ts --runInBand(3 suites、8 项通过)、npm --prefix api run build、npm run build、git diff --check;前端保留既有 Vite chunk size warning。 - 已部署生产验证:第 25 条 Prisma migration
20260710153000_add_user_session_version成功应用;cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,API/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-api、cmpp-gateway、Nginx、MinIO 均为 active,API/Gateway health 正常。
2026-07-10 瑕疵回归复查
- 逐图复查下载的《短信平台第一版瑕疵》后,确认中文图片文件名乱码仍真实存在:生产
FileObject.fileName中可见 UTF-8 被按 Latin-1 解释后的值。上传链路现先恢复 multipart 文件名编码;历史记录由前端展示层兼容解码,避免签名材料和企业认证页继续显示乱码。 - 通用输入框、文本框去除内部填充色;同时覆盖 Chromium 自动填充产生的蓝色内层背景。企业认证页此前额外写死的灰色输入背景已移除。
- 2026-07-11 回归发现此前金额展示验收不充分:充值记录和多处金额页面仍混用整数、两位或四位小数。现统一金额展示为人民币元三位小数,并新增输入框聚焦底色与文本选中高亮;需求和
TC-BILLING-006已同步。 - 已执行 FilesService 定向单测(3 项通过)、API build、前端 build 和
git diff --check;生产部署后四个服务均为 active,API/Gateway health 正常。通过真实POST /api/admin/files/upload上传营业执照-编码回归.png,响应和FileObject持久化文件名均为正常中文。 - Batch 6 的 6.1、6.2、7.1、8.1 仍为待修,不得因之前的前端构建通过而标记完成;其余 8.x 与客户端菜单顺序将继续按原始文档逐项复核。
2026-07-11 文档瑕疵二次闭环
- 基于本地《短信平台第一版瑕疵.docx》重新逐项复查,撤销“代码已改即已验收”的旧口径;本轮必须以源码、真实 NestJS API 返回、测试和生产页面复核共同作为完成条件。
- 通道扩展位数改为真实 API 与页面共同约束
0-20的整数;流速仍由 NestJS 约束为1-2000 TPS并继续下发 Gateway。 - Dashboard API 新增四类真实待审明细:企业认证、短信审核、模板、签名;运营首页和右上角通知分别展示并跳转到各自真实审核入口。
- 手机号段接口从 cursor-only 响应升级为带
total/page/pageSize的 PostgreSQL 分页,页面获得总页数、首页、末页和跳转能力;短信记录与通用 Table 同步补齐完整分页控制。 - 统一修复充值记录不展示操作人、客户端标题、引流详情名称、用户初始密码显示/隐藏与随机生成、时间秒级格式、输入框无填充焦点状态,以及发送页真实应用单价三位小数显示。
- 已执行:
channels.service.spec.ts(24 项通过)、dictionaries.service.spec.ts(4 项通过)、operations.service.spec.ts(12 项通过)、API build、前端 build 与git diff --check均通过;前端仍仅有既有 chunk size warning。 - 已部署生产验证:
cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,API/Gateway health 均通过。真实认证 API 返回四类待审明细并与总数一致;手机号段第 2 页返回 25 条、总数 516217、page=2/pageSize=25,证明页面分页不再依赖 cursor 猜测总页数。 - 浏览器自动化在登录页连接阶段超时,未使用 CAPTCHA 绕过或修改生产数据;登录后页面视觉验收需在下一轮以人工登录或可用浏览器会话补充截图。其余项目以源码、真实 API 和构建结果验收,不能将该未完成的视觉截图记录成已完成。
2026-07-11 运营端查询控件与手机号段库重做
- 企业应用、企业签名、企业模板管理页的查询与重置统一为通用
Button操作组:查询提交当前条件到真实 NestJS 列表 API,重置清空条件后重新加载真实列表,不再依赖输入即筛选或状态更新竞态。 - 系统管理的用户管理、手机号段库、报备字段库、系统日志均增加查询和重置;用户与报备字段使用已加载真实数据的显式筛选,系统日志使用已提交筛选条件请求真实日志 API。
- 手机号段库重做为概览、关键词筛选、号段/运营商规则双视图和统一分页工作台。号段和规则均使用 PostgreSQL 返回的
total/page/pageSize,不使用静态数组或 cursor 猜测总页数。 - 已执行前端
npm run build和git diff --check;已部署生产验证,cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,API/Gateway health 通过。生产源码和已构建静态资源均包含新的查询操作组与手机号段工作台样式;手机号段 API 继续返回真实total/page/pageSize。
2026-07-11 CMPP 业务失败回执闭环
- 修复下游 CMPP 入站的审计缺口:客户已完成 bind、账号可识别且手机号参数合法后,NestJS 会先创建真实
SmsBatchTask、SmsApiRequest和SmsMessageRecord,再执行模板、签名/报备、风控和余额校验;不再因模板未报备等业务失败而直接丢弃客户 Submit。 - 协议、鉴权、源 IP 和手机号参数错误仍由 Gateway/NestJS 返回非零 SubmitResp,且不创建短信记录。其余业务失败返回成功 SubmitResp 与平台 Msg_Id,并创建真实
SmsReceiptRecord(rawStatus=REJECTD)和CmppDownstreamDelivery,客户通过 Deliver Receipt 获得undelivered结果。 - 同一回执策略覆盖最终通道签名报备失败、无可用路由,以及上游 Submit rejected/timeout 在补发耗尽后的终态失败;失败记录、错误码和错误原因均可在运营端真实短信记录链路查询。
- Gateway 在客户 Submit 成功并建立 messageId-连接映射后立即冲刷该账号 pending 下游投递,避免 API 先创建失败回执时只能等待周期补投。
- 已执行
npm --prefix api test -- --runInBand send-chain.service.spec.ts(34 项通过)、npm --prefix api run build、go test ./...(Gateway 全量通过)。待本轮全量 API/前端构建及生产验证完成后补充最终部署结果。
2026-07-11 企业应用下游 CMPP 连接状态修复
- 修复企业应用列表误用上游
CmppConnectionState的问题。新增 PostgreSQLCmppDownstreamConnection,一条记录对应一个已鉴权的客户 CMPP TCP bind 会话,按应用保存账号、企业代码、客户端 IP、协议版本、建立时间、最近心跳、最近 Submit、最近 Deliver、断开时间和错误原因。 - Gateway 在客户 bind 成功、
ACTIVE_TEST、Submit 和下游 Deliver 写入成功/失败时通过真实 NestJS API 回写连接事件;运营端只以该表的connected会话统计当前连接数,不再把上游通道连接数显示为企业客户连接数。 - API 列表/详情查询会将最近心跳超过
CMPP_DOWNSTREAM_HEARTBEAT_TIMEOUT_MS(默认 90 秒)的会话标记为heartbeat_timeout;运营端展示真实客户端 IP、企业代码与最近心跳。移除了不能真正关闭 TCP 连接的运营端“删除连接”伪操作。 - 已执行
sms-config.service.spec.ts(17 项通过)、API 全量测试(13 suites、121 项)、Gateway 全量go test ./...、API build 和前端 build;前端仅有既有 chunk size warning。 - 已部署生产验证:第 26 条 Prisma migration
20260711193000_add_cmpp_downstream_connections已成功应用,CmppDownstreamConnection表存在。cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,12026/17890/8090监听及 API/Gateway health 均通过。部署时没有保持在线的客户 bind 会话,故新表初始为 0 条;下一次真实 CMPP bind 将作为生产数据验收样本写入该表。
2026-07-11 短信号码运营商与省份持久化
- 确认发送链路在进入应用通道组路由后,会先按真实
PhoneCarrierRule正则识别号码运营商,再按PhoneSegment号段库识别省份。本轮不扩展地市字段。 SmsMessageRecord新增carrier/province,路由阶段完成号码识别后立即持久化;即使后续缺少通道组或无在线通道而失败,短信记录仍保留识别结果。选中通道时与channelId/submitId再次同步写入;Prisma migration 使用真实号段库和生效运营商规则回填已有短信记录。- 运营端短信记录列表、发送详情和 CSV 导出展示记录上的号码省份/运营商,不再以通道发送地区或通道本体 carrier 冒充号码归属。
- 短信任务进度详情中的“号码运营商分布”和“号码省份分布”均直接聚合任务内真实短信记录的
carrier/province。 - 已执行
npm --prefix api test -- --runInBand send-chain.service.spec.ts(35 项通过)、npm --prefix api run build、npm run build和git diff --check;前端仅有既有 chunk size warning。 - 已将
7b8424d9部署生产,migration20260711210000_add_message_route_identity成功应用。cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,12026/17890/8090/3000监听、API/Gateway health 及外部12026HTTP 均通过。生产 11 条已有短信已全部回填运营商和省份:移动 9 条、电信 1 条、联通 1 条,省份均为上海。
2026-07-12 全页面固定条数截断与总数口径整改
- 生产核查确认企业管理只返回前 100 条,但 PostgreSQL 实际有 106 个企业(未删除 105 个);企业应用只返回前 100 条,实际有 204 条。页面将截断后的数组长度展示为“企业总数/共找到”,属于真实数据口径 Bug。
- 已系统审计页面主列表 API,移除会把前
100/200/500条直接作为页面全量的固定截断。覆盖企业、企业应用、企业认证、用户/角色/权限、签名、模板、通道/通道组/路由规则、报备字段/材料/任务/记录、账务、文件、审计、风控、敏感词/黑名单/引流字段、短信任务/记录/提交/回执/上行等真实列表。 - 企业应用的“今日发送/到达率”不再每应用加载最多 1000 条
SmsMessageRecord后用数组长度计算,改为 PostgreSQL 按applicationId/status的groupBy全量聚合。 - 短信任务进度不再为每个任务最多加载 100000 条短信后统计,改为 PostgreSQL 按
batchTaskId/carrier/province/status聚合总数、成功数和计费条数,任务运营商/省份分布不再受 10 万条截断影响。 - 保留的固定条数均属于明确的近期日志/监控窗口、超时扫描单批、导出保护、单消息重试尝试或唯一候选判定,这些响应不被页面展示为业务总数。
- 已执行 API 全量测试(13 suites、122 项通过),及受影响服务定向测试(5 suites、91 项通过)、API build、前端 build 与
git diff --check;前端仅有既有 chunk size warning。 - 已将
390b9700部署生产,部署前完成 PostgreSQL 和当前发布源码备份,Prisma 确认 27 条 migration 均已应用。cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,12026/17890/8090/3000监听、API/Gateway health 和外部12026HTTP 均通过。使用生产平台管理员会话调用真实受保护 API:企业管理返回 105 条未删除企业,企业应用返回 204 条,不再封顶 100。
2026-07-12 客户批量任务与 CMPP 内部批次隔离
- 短信任务进度的产品口径回归为“客户在客户端提交的批量发送任务”。运营端和客户端任务列表统一强制
SmsBatchTask.sourceType=client,不再展示每条 CMPP Submit 创建的sourceType=cmpp内部批次或通道测试批次。 - CMPP 内部批次仍保留在 PostgreSQL,继续承载模板/签名/报备校验、风控、冻结/计费、队列、补发和 Deliver Receipt 关联;所有 CMPP 号码仍进入短信记录。
- 客户端任务详情、任务短信明细和取消接口同时校验当前
tenantId和sourceType=client,不能通过内部批次 ID 读取或操作 CMPP 内部任务。 - 生产现状只读核对:
sourceType=cmpp2 个、sourceType=admin_channel_test1 个、sourceType=client0 个。部署后任务进度应显示 0 个客户批量任务,但不删除现有内部批次数据。 - 已执行
send-chain.service.spec.ts + operations.service.spec.ts(2 suites、50 项通过)、API 全量测试(13 suites、125 项通过)、API build 和前端 build;前端仅有既有 chunk size warning。已随8b6ec92f部署生产,受保护任务进度 API 返回 0 个客户批量任务,未将现有 2 个 CMPP 内部批次和 1 个通道测试批次误展示。
2026-07-12 CMPP 模板不匹配短窗口聚合审核
- 只有企业应用配置
templateMismatchMode=manual_review时,CMPP 模板不匹配短信才进入人工审核。reject继续逐条失败并下发REJECTD;其他模式不被聚合逻辑接管。 - 新增
SmsSendTask.sourceType/aggregationKey/contentHash/windowStartedAt/windowEndsAt,以应用、CMPP 账号、规范化内容 SHA-256 和默认 10 秒窗口生成唯一聚合键。SmsMessageRecord.reviewTaskId/signatureId保留每条成员与审核任务、真实签名的关联。 - 聚合前仍校验签名审核/报备、风控直接拒绝和账户余额,并按每条短信独立冻结。审核通过后逐条恢复到各自
sourceType=cmpp内部批次并入队;驳回后逐条释放冻结、写入失败记录并生成客户侧 Deliver Receipt。 - 运营端短信审核页新增“审核来源”和“聚合号码数”,区分 CMPP 模板不匹配聚合与普通风控审核。
- 聚合窗口关闭前,任务不返回到待审列表且审核接口拒绝提前操作,避免窗口内后到短信加入已完成任务。
- Prisma migration:
20260712113000_add_cmpp_review_aggregation。已执行 API 全量测试(13 suites、129 项通过)、API build、前端 build、Prisma validate 和git diff --check。 - 已将
8b6ec92f部署生产,部署前完成 PostgreSQL 和发布源码备份,migration 已成功应用。SmsSendTask5 个聚合字段、SmsMessageRecord.reviewTaskId/signatureId均已存在;生产应用中manual_review3 个、reject201 个。审核 API 返回 200,当前无待审样本,未为验收人工注入短信或修改业务数据。cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,12026/17890/8090/3000监听、API/Gateway health 和外部12026HTTP 均通过。
2026-07-12 报备字段库到企业签名/引流资料完整链路
ChannelReportField通过drainageFieldId真实关联报备字段库,并增加reportType=signature/drainage/both;通道报备配置页改为选择字段库字段和报备用途,不再在通道内手工复制字段编码、名称和类型。- 新增企业应用报备字段解析 API,按生效的应用路由规则遍历通道组及组内通道,以字段库 ID 求合集;同字段任一通道必填即整体必填,并返回全部来源通道。
- 企业签名与引流信息弹窗根据所选企业应用动态加载字段合集。签名只展示签名/共用字段,引流项只展示引流/共用字段;文件字段继续走真实 MinIO/对象存储上传,文本值和文件对象 ID 均提交 NestJS API。
- API 在写签名前执行必填校验,防止绕过前端;保存后同步写入各目标通道的
SignatureReportMaterial和新增的DrainageReportMaterial,删除引流项时同步清理旧材料。 - 为避免运营人员面对动态资料时无法理解来源,签名和引流编辑页增加“通道组数/通道数/字段数/必填数”摘要、字段级来源说明和“为什么需要这些资料”解释弹窗;弹窗按企业应用、通道组、通道逐级展示字段用途及必填口径。每次保存同时在签名 JSON 中固化
reportRequirementSnapshot,记录当时的字段与来源通道,供配置变化后的历史追溯。 - Prisma migration:
20260712150000_link_report_field_library。已执行 Prisma generate/validate、channels.service.spec.ts + sms-config.service.spec.ts(2 suites、44 项通过)、API build 和前端 build;前端仅有既有 chunk size warning。 - 已提交并 push
87ae4a20,随后以该提交生成发布快照并部署生产;部署前备份 PostgreSQL 和运行源码,migration20260712150000_link_report_field_library已成功应用。生产.deployed-commit=87ae4a20,cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,12026/17890/8090/3000监听,API/Gateway health 和外部 HTTP 均通过。 - 生产数据库已确认
ChannelReportField.drainageFieldId/reportType和DrainageReportMaterial存在。当前生产DrainageField=0、ChannelReportField=0,因此不会凭空展示动态资料区;需要先按真实业务配置创建字段库和通道字段后再做页面来源弹窗的有数据验收。 - 浏览器可打开生产登录路由并识别页面标题“CMPP 短信平台”,但读取 DOM/控制台时浏览器连接连续超时,未将解释弹窗点击交互标记为已通过;待生产产生真实字段配置后补测。
- 2026-07-12 追加:报备字段库字段类型收窄为字符串、图片、文件三种;前端筛选和新增弹窗移除整数、网址、电话、日期,API 严格拒绝三种之外的类型。migration
20260712170000_normalize_report_field_types将历史其他类型及其通道字段副本统一归并为字符串。 - 2026-07-12 追加:按设计基线
131f344a^恢复“通道列表 → 报备详情”页面结构,不再把报备详情错误简化为字段配置表。页面按当前通道查询真实ChannelSignatureReportTask/ChannelSignatureReportRecord/SmsSignature.drainageInfo,展示签名任务、报备状态和时间,签名下引流信息默认收起并可展开;查看详情使用真实企业、应用和动态资料。发送统计没有数据库事实时明确显示“暂无统计”,不复用基线演示百分比。签名报备字段和引流信息字段配置保留为页面顶部两个入口,均从真实报备字段库选择。 - 本地验证:通道/字典定向测试 2 suites、31 项通过,API 全量 13 suites、134 项通过,API build、前端 build、
git diff --check通过。浏览器确认本地构建可加载且无框架错误覆盖,但本地未启动真实 API,认证验证码请求返回 502 并停留登录页,因此未把目标报备页面的登录后视觉交互标记为通过;没有绕过认证或注入 mock 数据。 - 2026-07-12 追加:报备状态改为通道任务唯一事实来源。新增统一批量状态变更 API,企业签名按应用当前通道组展示具体通道矩阵,通道详情修改当前任务,报备任务页人工修正任务;三个入口统一更新/创建
ChannelSignatureReportTask、写ChannelSignatureReportRecord,并重算三网汇总和SmsSignature.reportStatus。回执导入不再直接覆盖全局状态,同样调用汇总算法;新增但无任务的目标通道按未报备计入汇总分母。 - 已执行相关定向测试 2 suites、46 项及 API 全量测试 13 suites、135 项,API build、前端 build、
git diff --check均通过;前端仅有既有 Vite chunk size warning。 - 已提交并 push
eab05958后部署生产,部署前完成 PostgreSQL 与运行源码备份;migration20260712170000_normalize_report_field_types成功应用。生产.deployed-commit=eab05958,cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,12026/17890/8090/3000监听,API/Gateway health 和外部 HTTP 200。新统一状态接口对空 items 返回预期 400,证明路由已注册。生产当前DrainageField/ChannelReportField/ChannelSignatureReportTask/ChannelSignatureReportRecord均为 0,未为验收注入虚假字段、任务或人工状态;运营人员可从企业签名通道矩阵对真实目标通道首次设置状态并创建任务。
2026-07-13 部分通道报备通过的发送路由
- 修复发送链路先以
SmsSignature.reportStatus=approved一票否决、导致部分通道通过仍无法发送的问题。全局状态改为运营汇总展示;签名审核仍必须通过。 - 首次发送和失败补发均在路由阶段解析真实签名,只保留对应
ChannelSignatureReportTask.status=approved的候选通道,再结合运营商、省份、优先级、通道状态和实时连接选择通道。主通道未报备而备用通道已报备时允许走备用通道;没有已报备通过且在线的候选通道时明确失败。 - Gateway 提交前继续保留最终通道报备任务二次校验,覆盖路由完成后任务状态发生变化的竞态。
- 已执行
send-chain.service.spec.ts40 项通过,覆盖全局 reporting 可发、主通道未通过而备用通道通过时选备用,以及所有候选均未通过时拒绝;API build 和前端 build 通过。 - 已提交并 push
ade06058后部署生产;部署前完成 PostgreSQL 与eab05958运行源码备份,无待执行 migration。生产.deployed-commit=ade06058,cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,12026/17890/8090/3000监听,API/Gateway health 与外部 HTTP 200。生产源码已确认包含 approved 通道候选过滤;【安徽航天信息】当前仍为全局 reporting、一个通道 approved、一个通道 pending,未主动发送计费短信,交由用户使用真实业务流量验证只走 approved 通道。
2026-07-13 企业签名审核与通道报备状态展示分离
- 生产核查【安徽航天信息】确认状态保存成功:两个
carrier=all通道分别为 approved、reporting,三网真实汇总均为 reporting 且 1/2 通过;Bug 在于前端将 reporting 转换成旧 pending,再显示成“审核中”,并丢失通过数/总数。 - 企业签名列表和报备详情改为直接使用 API
carrierReportSummary.status/approved/total:展示未报备、报备中、部分通过(x/y)、全部通过(x/y)、资料待补充、报备失败和不适用;签名auditStatus另列显示草稿、待审核、已通过、已驳回。详情同时列出每个目标通道的真实状态,不再读取drainageInfo.carrierStatus冒充当前汇总。 - 按用户授权,本次将工作区其他会话的字段代码校验、Select 搜索、应用列表及样式等改动一并测试和发布;API 全量 13 suites、137 项通过,API build、前端 build、
git diff --check通过。 - 已将完整工作区提交
344b2afe部署生产,部署前完成 PostgreSQL 与ade06058运行源码备份,无待执行 migration。生产.deployed-commit=344b2afe,四项服务 active,12026/17890/8090/3000监听,API/Gateway health 与外部 HTTP 200;发布产物已确认包含“部分通过(x/y)”“全部通过(x/y)”“签名审核”。生产【安徽航天信息】仍为 auditStatus=draft、reportStatus=reporting、1/2 通道 approved,刷新后应展示签名审核“草稿”和三网“部分通过(1/2)”。
2026-07-13 企业页面可用性与报备展示修正
- 企业短信模板卡片改为自适应列宽,卡片和操作区允许换行,避免中等视口下固定三列造成水平滚动。
- 企业应用管理列表隐藏 AppID 列;共用
Select对标签中包含“企业”或“应用”的下拉自动提供名称搜索,选项仍来自各页已接入的真实 API。 - 报备字段代码在前端和 NestJS API 双层限制为
A-Z/a-z/0-9;API 会拒绝下划线、中文、空白等非法代码,防止绕过页面写入 PostgreSQL。 - 运营端浏览器标题更新为“聆界短信管理平台”。通道报备详情和签名详情弹窗在展示前剔除数据中已存在的外层中/英文括号,统一只渲染一层中括号。
- 本地验证:API 全量 13 suites、137 项通过,API build、前端 build 和
git diff --check通过;前端仅有既有 chunk size warning。应用内浏览器确认本地运营端登录路由、非空 DOM、无框架错误覆盖,且标题为“聆界短信管理平台”;因本地未启动真实 API,验证码请求返回 502,无法进入登录后页面完成模板响应式、下拉搜索和签名实数据的视觉点击验收,未注入 mock 或绕过认证。截图阶段应用内浏览器页面挂载超时,未将截图标记为通过。
2026-07-13 运营端企业模板与企业签名布局优化
- 确认上一次自适应修正落在客户端
/client/templates,而运营端/admin/enterprise-templates仍使用累计最小宽度约 1820px 的表格,操作列必须水平滚动才能看到。 - 企业模板管理改为响应式列表行:将模板名称/审核状态、企业/应用/签名归属、两行内容摘要/变量数、更新时间和操作分区展示。在 1180px 以下重排为三列,860px 以下变为单列,预览/编辑/删除始终保留在当前视口。分页仍基于真实 API 结果,每页 10 条。
- 企业签名管理将三网报备标签与
(approved/total)数量拆开,容器可换行但文字和数量各自保持完整;报备详情/报备状态/编辑/删除固定为两列两行。同时修正签名摘要网格少一列导致“引流信息”和操作区被挤到下一行的布局问题。 - 本地验证:API 全量 13 suites、137 项通过,API build、前端 build、
git diff --check通过;前端仅有既有 chunk size warning。Chrome 当前无已登录生产标签,部署前未绕过图形验证码或注入 mock 数据。 - 已将功能提交
19d47b45push 到origin/main并部署生产。部署前备份 PostgreSQL 为/opt/cmpp-platform/backups/cmpp-20260713-103205.sql(约 61MB),备份运行源码为/opt/cmpp-platform/backups/source-20260713-103205.tar.gz(约 63MB);发布快照本地/服务器 SHA-256 一致。生产无待执行 migration,.deployed-commit=19d47b45,cmpp-api、cmpp-gateway、Nginx、MinIO 均为 active,12026/17890/8090/3000监听,API/Gateway health 和外部 HTTP 200。生产index.html已引用新资源index-HtuLnrXL.js/index-C5Tf8YiT.css,源码已确认包含企业模板响应式行和签名操作区两列布局。 - 生产浏览器确认路由可加载、标题为“聆界短信管理平台”、DOM 非空、无 console error/warn 和框架错误覆盖。由于浏览器没有已登录运营端会话,访问受保护页面按预期落到登录界面;未经用户确认不代解图形验证码,因此登录后真实数据截图和点击交互留待用户刷新生产页面验收。
2026-07-13 签名审核与引流信息通道报备闭环
- 生产只读核查确认:运营端新建的【安徽航天信息】仍为
auditStatus=draft;引流资料保存在SmsSignature.drainageInfo.links,动态字段可写DrainageReportMaterial,但缺少引流项维度的真实通道报备任务和记录。 - 将
/admin/signatures从占位页替换为真实签名审核页,支持状态查询、资质/动态资料详情、通过和带原因驳回,调用现有 NestJS 审核 API 并写AuditRecord。运营端新建签名直接写auditStatus=approved,同时写admin_create_approved审核记录;客户端提交审核流不变。 ChannelSignatureReportTask增加reportType=signature/drainage和drainageItemId。保存引流资料时,根据企业应用的真实路由通道及其drainage/both字段自动生成 pending 任务和 create 记录;删除引流项时同步清理对应材料和任务。- 企业签名引流列表、通道报备详情、报备任务页均按引流项和通道读取/修改同一任务,共享报备记录、导出和回执链路。企业签名三网状态改为引流任务真实汇总,不再使用
drainageInfo.links.mobile/unicom/telecom静态值。 - 短信发送选路和最终通道二次校验明确增加
reportType=signature,引流通过任务不会误放行未报备签名。Prisma migrations:20260713153000_add_drainage_report_tasks、20260713154000_backfill_drainage_report_tasks、20260713155000_unique_report_task_scope;后两者分别回填已有引流材料的 pending 任务/记录,并保证同一报备对象和通道仅一个任务。 - 本地真实 PostgreSQL 已成功应用 3 条新 migration;API 全量 13 suites、139 项通过,Gateway 全量 Go 测试、Prisma validate、API build、前端 build 和
git diff --check通过,前端仅有既有 chunk size warning。应用内浏览器确认本地运营端登录路由标题正确、DOM 非空、无框架错误覆盖且 console 无 error/warn;真实图形验证码阻止进入受保护页,未代解验证码、未绕过认证、未注入 mock。