release: prepare RealeseV2.3

This commit is contained in:
hectorzhao
2026-08-06 10:48:36 +08:00
parent 57b58f1c40
commit 8ad8e61793
37 changed files with 997 additions and 64 deletions
+13 -2
View File
@@ -284,7 +284,7 @@
- 已实现 SubmitCommand 在途恢复第一版:Go Gateway submit worker 在消费新消息前会对 Redis Stream consumer group 中空闲超过阈值的 pending 命令执行 `XAUTOCLAIM`,重新提交并按正常成功路径 ack,避免 Gateway 重启后命令永久滞留在 PEL。
- 已实现上游连接断开时的 pending submit 状态补偿第一版:如果某条上游 CMPP 连接在收到 submit resp 前断开,Gateway 会立即唤醒该连接上等待中的 pending submit,请求返回 `timeout/CONNECTION_LOST`,由 NestJS 进入既有补发或释放冻结逻辑,不再只依赖固定超时。
- 已实现“上游可能已受理但 submit resp 丢失”场景的保守补偿第一版:Gateway 在 receipt 事件中补充手机号;NestJS 对无法按 `messageId/gatewayMessageId` 精确命中的回执,只在“同通道、同手机号、72 小时窗口内、且仅存在 1 条 `timeout + gatewayMessageId=null` 的 submit 记录”时才回填并接收该回执,避免误绑到其他短信。
- 已实现 Gateway 提交异常治理:Go Gateway 对多次处理仍失败的 `SubmitCommand` 不再无限滞留在 PEL,而是按阈值写入 NestJS 真实 `GatewaySubmitDeadLetter` 表(数据库表名和内部接口保留技术兼容名,页面统一称“Gateway提交异常”)。运营端 `/admin/gateway-submit-exceptions` 提供真实分页、筛选、汇总、脱敏详情和单条重新入队;原始 payload、密码、密钥不得返回浏览器。重新入队必须要求近期认证、填写原因、勾选“已确认上游未受理”,并校验短信尚未 accepted/submitted/delivered/unknown、通道 active 且 connected、人工次数小于 3;服务端以 pending 到 requeueing 的原子状态抢占防止重复点击,成功写回 Redis Stream 后记录操作人、原因、Stream ID 和时间。收到后续 SubmitResult 时必须将对应异常记录闭环为 resolved。
- 已实现 Gateway 提交异常治理:Go Gateway 对多次处理仍失败的 `SubmitCommand` 不再无限滞留在 PEL,而是按阈值写入 NestJS 真实 `GatewaySubmitDeadLetter` 表(数据库表名和内部接口保留技术兼容名,页面在“网关异常”的“提交异常”Tab展示)。运营端 `/admin/gateway-submit-exceptions` 提供真实分页、筛选、汇总、脱敏详情和单条重新入队;原始 payload、密码、密钥不得返回浏览器。重新入队必须要求近期认证、填写原因、勾选“已确认上游未受理”,并校验短信尚未 accepted/submitted/delivered/unknown、通道 active 且 connected、人工次数小于 3;服务端以 pending 到 requeueing 的原子状态抢占防止重复点击,成功写回 Redis Stream 后记录操作人、原因、Stream ID 和时间。收到后续 SubmitResult 时必须将对应异常记录闭环为 resolved。
- Gateway 提交异常重新入队必须使用“异常记录 ID + 下一次人工次数”的稳定幂等键,通过 Redis Lua 原子完成“检查幂等键、XADD、保存 Stream ID”;API 在 XADD 成功后宕机或数据库落账失败时,超时恢复扫描必须复用同一幂等键完成落账,不能再次产生 Stream 消息。Gateway 重复上报同一个原始 Stream 异常不得把 `requeued/resolved` 回退成 `pending`
- 已实现 Gateway 通道级 Redis 限速:NestJS 入队前保留业务层通道限速,Go Gateway 在真正调用上游 Submit 前再次按通道 ID 预约发送时隙;连接命令把权威 TPS 写入 Redis,提交按权威值与消息值的较小者执行。普通 Stream 消息在等待期间不 ACK、不转失败,多实例共同使用同一限速状态;worker 对同批消息并发调度,低 TPS 通道等待不阻塞其他通道。
- 已实现 Gateway 重启后的 active 上游通道恢复:部署先重启 Gateway 再重启 APIAPI 启动后从 PostgreSQL 读取 active 通道,重新下发连接命令,恢复 Gateway 内存连接池、真实连接状态和 Redis 权威 TPS key,不得继续沿用重启前的 connected 状态。
@@ -451,6 +451,7 @@
- 运营概览一级菜单下只保留运营看板、发送监控、数据统计;客户管理独立作为一级业务域展示,避免重复菜单。
- 右上角消息铃铛展示所有待审核任务总数,并按企业认证、短信审核、短信模板审核、签名审核等分类展示;点击分类跳转到对应审核页面。
- 新审核任务进入时,运营端应触发浏览器通知或站内提醒;提醒数据必须来自真实待审核数量接口,不得只写死前端数字。
- 全局导航首次加载、每 30 秒轮询、窗口重新获得焦点及审核完成后的角标刷新,必须调用独立轻量待审核数量接口;该接口只统计五类待审核数量,不得调用或复用包含发送、账务、连接、下游投递和趋势查询的完整运营看板聚合。
### 5.11 运营端客户与企业
@@ -1536,6 +1537,7 @@
- 单发复用现有 `SendChainService`,必须经过真实企业/应用、签名、模板、风控、余额、计费、通道路由和 Redis 队列链路;接收成功返回 202,不代表运营商提交或终端到达成功。
- 上行查询只返回已匹配或人工认领到当前应用的记录,默认最近 24 小时,单次范围和分页上限由应用配置控制;未匹配和歧义上行不得泄露给任一客户。
- 客户错误使用 `application/problem+json` 和稳定业务码。客户 Swagger 只包含四个 `/openapi/v1` 接口,不得包含 admin、client 管理或 gateway 内部接口。
- 客户 HTTP API 使用独立公网源地址配置;管理页面、参数复制和 Swagger 链接必须从真实后端返回的 `HTTP_API_PUBLIC_ORIGIN` 生成,不得沿用管理页面 `window.location.origin`。预生产固定为 `https://api.lisglo.com`,该灰云域名只暴露 `/api/openapi/v1/*`、客户 Swagger 和健康检查,不得暴露 admin/client 管理接口或前端页面。
### HTTP Webhook 与客户端页面
@@ -1754,7 +1756,7 @@
3. 编辑启用中的通道时,仅当网关地址、端口、账号、密码、CMPP版本、连接数、窗口或心跳参数的实际值发生变化才请求重连。名称、运营商、地区、单价、服务号、扩展位、企业代码及TPS限速等业务参数不得触发重连;启用和停用状态变更仍按原规则连接或断开。
4. 运营端短信记录首次进入及点击重置后,默认查询北京时间昨天和今天两天,仍允许用户选择其他日期。
5. 下游投递详情按时间线卡片展示每次投递,分别呈现中文状态、发送/ACK/截止时间、连接ID、Sequence_Id、Msg_Id、ACK Result和错误,不使用需要横向滚动的宽表。
6. Gateway提交异常列表标题区域必须与容器边框、表格留出清晰间距,并展示当前结果总数;分页区域具有独立分隔。
6. “网关异常”的“提交异常”Tab列表标题区域必须与容器边框、表格留出清晰间距,并展示当前结果总数;分页区域具有独立分隔。
7. 原提议的报表“T-4未知转失败”本轮明确取消,不改变既有日报未知状态、重算逻辑或历史数据。
## 2026-07-26 通道补发归因与发送详情补充要求
@@ -1904,3 +1906,12 @@
- `Registered_Delivery=0`的客户分片不生成CMPP状态报告;同一HTTP提交仍只生成一个消息级最终Webhook,不因供应商内部计费分片数而重复回调。
- 提交或未知状态满72小时仍无明确最终回执时,主记录转为`timeout`并写入`undelivered/EXPIRED/RECEIPT_TIMEOUT`。CMPP对每个请求状态报告的原始分片建立失败回执,HTTP建立一个明确失败Webhook;退款保持消息级一次。
- 超时状态变更与下游回执建单之间必须可恢复:仅在HTTP事件及全部应建CMPP分片投递均成功持久化后写`timeoutReceiptQueuedAt`;中途失败保留空标记,由后续定时扫描按稳定幂等键补齐,禁止出现“已转超时但永久没有下游回执”。
## 供应商长短信整条级成功回执与网关异常中心(2026-08-06)
- 通道配置增加“长短信成功回执口径”,默认值为`per_segment`(逐分片)。只有供应商明确约定长短信成功时仅返回一条、且该条代表整条短信全部分片成功,才允许人工配置为`message_level`(整条级);修改该业务口径不触发通道重连。
- `per_segment`保持既有严格规则:只收到一个成功分片时,其他未回执分片继续等待,主记录不得提前成功。`message_level`收到当前提交尝试的一条明确成功回执时,可将同次提交中尚无回执的分片标记为推断成功,并以`compensationType=supplier_message_level_receipt`保留推断依据;真实`SmsReceiptRecord`仍只保存供应商实际返回的一条回执,不伪造多条原始回执。
- 整条级成功推断只作用于当前通道、当前提交尝试和真实存在的多分片审计;已有明确失败的分片不得被成功推断覆盖。业务终态、退款、补发及对客户的CMPP/HTTP最终回执继续沿用既有幂等规则。
- 已按整条级成功形成`delivered`终态后,如果同一提交尝试又收到明确失败回执,平台保留原始回执和分片审计,但不得自动把已送达终态改成失败、重复退款或向客户推送互相矛盾的失败结果;系统按稳定异常键写入`SmsReceiptAnomaly`,重复矛盾回执累加发生次数。
- 运营菜单“Gateway提交异常”更名为“网关异常”,原路由保持兼容。页面使用“提交异常”和“回执异常”两个Tab,均查询真实后端和PostgreSQL;每个Tab必须在标题区说明其数据来源、业务含义、不能代表的结论及人工处理注意事项,避免运营人员间隔较久后误判。
- “提交异常”展示Gateway消费提交命令连续失败且没有明确供应商提交结果的死信,可在严格确认未被供应商接收后重新入队;“回执异常”展示供应商回执与平台既有终态冲突的结构化异常判定。回执异常详情必须指明真实回执保存在回执记录、原始CMPP报文在通讯交互日志,不得用异常摘要替代原始证据。