fix: harden admin and CMPP delivery workflows
This commit is contained in:
@@ -6,6 +6,18 @@
|
||||
|
||||
当前确认:第一版保留短信业务,排除彩信功能;账户按现金余额和授信额度计费,人工充值和充值记录进入第一版开发范围,套餐、短信余量、账单流水页面和公开交易查询 API 不进入第一版。彩信服务、彩信应用/签名/模板 Tab,以及运营端彩信相关菜单标记为“待开发”;业务性能指标为“平台可稳定入队并调度 500 条短信/秒,实际向通道 submit 受通道限速配置控制”。
|
||||
|
||||
### 0.1 运营端细节要求(2026-07-15)
|
||||
|
||||
- 企业签名的站点字段统一显示为“引流信息”,列表、表单和详情不展示引流信息提交时间。
|
||||
- 企业应用的企业代码必须始终等于 CMPP 6 位账号,由系统同步且不可单独编辑;账号留空时,创建应用时自动生成二者。每任务号码数超过应用上限时拒绝整个任务并提示拆分,不允许静默截断。
|
||||
- 手机号段支持真实删除;报备字段库展示被通道报备配置引用的通道数,引用数大于 0 时前后端均禁止删除,未引用字段才允许真实删除。
|
||||
- 企业应用连接详情只展示当前已连接会话;断开或心跳超时会话从活跃连接表删除,不保留为连接历史。
|
||||
- 短信审核批量通过必须基于明确勾选,只处理已选待审核任务;不得默认通过当前筛选结果或全部数据。
|
||||
- 下游投递记录支持创建日期范围筛选,并将日期条件下推 PostgreSQL 列表与 Dashboard 聚合。
|
||||
- 短信模板变量插入到文本框当前选区或光标位置,插入后光标移动到变量之后。
|
||||
- 运营端短信记录使用自适应信息卡片,发送详情按概览、短信内容、通道回执、状态和分片审计分组,失败原因使用独立警示区域突出;该项只调整前端展示,不改变短信记录后端语义。
|
||||
- 人工充值弹窗不要求填写操作人,操作身份从当前登录会话和后端操作日志取得。
|
||||
|
||||
## 1. 项目目标
|
||||
|
||||
建设一个短信平台第一版,支持企业客户在客户端完成短信应用、模板、签名、号码导入、短信发送、批量任务查询、发送明细查询、上行短信查询;支持运营端完成企业管理、企业应用/签名/模板管理、审核、通道配置、通道签名报备、报备任务导出/回执导入、发送监控、任务进度、短信记录、上行记录、安全控制和系统管理。
|
||||
@@ -144,7 +156,8 @@
|
||||
- 客户端批量任务列表、详情、短信明细和取消操作必须同时校验当前企业和 `sourceType=client`。
|
||||
10. 所有来源的短信,包括平台批量任务、API 调用、CMPP 对接发送,全部按手机号维度进入短信记录。
|
||||
11. 任务进度、发送详情和短信记录实时或准实时更新。
|
||||
12. 企业应用“不符合模板的短信”配置为 `manual_review` 时,合法的 CMPP Submit 在模板不匹配后进入人工审核;配置为 `reject` 时仍直接拒绝并返回 `REJECTD` Deliver Receipt,其他模式不得被人工审核聚合逻辑误接管。
|
||||
12. 企业应用“不符合模板的短信”配置为 `manual_review` 时,合法的 CMPP Submit 在模板不匹配后进入人工审核;配置为 `reject` 时直接拒绝并返回 `REJECTD` Deliver Receipt;配置为 `direct_send` 时必须识别并绑定已审核通过的完整括号签名,继续执行风控、余额、通道组路由、具体通道签名报备和 Gateway 真实提交,不得因模板未匹配落入 `reject`,也不得绕过其他发送校验。
|
||||
- CMPP 入站模板匹配必须支持模板正文中的 `${variable}` 占位符。固定文本需完整匹配,占位符至少匹配一个字符;同名占位符重复出现时取值必须一致。匹配成功后应绑定真实 `templateId`,并将提取的变量值传入风控,不能只用整段正文数据库精确相等判断。
|
||||
13. CMPP 模板不匹配审核支持短窗口内容指纹聚合:只有同一企业应用、同一 CMPP 账号、规范化后内容 SHA-256 完全一致且位于同一时间窗口的短信才能合并为一个审核任务。默认窗口 10 秒,可通过 `CMPP_TEMPLATE_REVIEW_WINDOW_MS` 调整。
|
||||
14. 聚合审核不合并短信记录、计费或回执:每个手机号仍有独立 `SmsMessageRecord/messageId/sequenceId`。审核通过后逐条进入真实路由和上游提交;审核驳回后逐条释放冻结并产生客户侧 `REJECTD` 回执。
|
||||
15. 人工审核只覆盖模板不匹配;签名必须以完整中文中括号前缀 `【签名】` 识别,并使用包含中括号的完整名称匹配签名库。入站候选签名只要求 `auditStatus=approved`,不得以全局 `reportStatus` 提前拒绝;报备通过状态必须在后续路由和最终提交前按具体通道校验。签名不合法、风控直接拒绝或余额不足不得因内容聚合而绕过。
|
||||
@@ -263,10 +276,11 @@
|
||||
- 已实现“上游可能已受理但 submit resp 丢失”场景的保守补偿第一版:Gateway 在 receipt 事件中补充手机号;NestJS 对无法按 `messageId/gatewayMessageId` 精确命中的回执,只在“同通道、同手机号、72 小时窗口内、且仅存在 1 条 `timeout + gatewayMessageId=null` 的 submit 记录”时才回填并接收该回执,避免误绑到其他短信。
|
||||
- 已实现 SubmitCommand 死信治理第一版:Go Gateway 对多次处理仍失败的 `SubmitCommand` 不再无限滞留在 PEL,而是按阈值写入 NestJS 真实 `GatewaySubmitDeadLetter` 表;运营端后端接口可分页查询死信,并支持人工将原始 `SubmitCommand` 重新写回 Redis Stream。
|
||||
- 已实现客户侧下游投递重试第二版:客户系统负责断线后重连;平台在客户离线或投递失败时把 Deliver Receipt/上行 Deliver 保留在 `CmppDownstreamDelivery`,客户 bind 成功后立即拉取 pending,且 Gateway 会对当前在线账号周期补投;超过重试上限后转 `failed` 并写失败审计。
|
||||
- 已实现下游投递失败审计与人工重投第一版:运营端后端与页面可分页查看 `CmppDownstreamDelivery` 的 pending/failed/delivered 记录,支持按状态、类型、应用和关键字筛选,并可对单条记录执行人工重投,真实调用 Gateway `/downstream/receipt` 或 `/downstream/uplink`。
|
||||
- 已实现下游投递失败审计与人工重投第一版:运营端后端与页面可分页查看 `CmppDownstreamDelivery` 的 pending/awaiting_ack/failed/unconfirmed/rejected/delivered 记录,支持按状态、类型、应用和关键字筛选,并可对非 `awaiting_ack` 记录执行人工重投,真实调用 Gateway `/downstream/receipt` 或 `/downstream/uplink`。主记录必须分开保存自动重试次数 `retryCount`、人工重投次数 `manualRetryCount` 和最近人工重投时间 `lastRetriedAt`,操作日志保留重投前状态与自动重试次数。
|
||||
- 已实现下游投递批量重投第一版:运营端可在当前页勾选多条 `pending/failed` 下游投递记录,调用真实批量接口逐条重投并返回成功/失败汇总,不允许用前端循环假装成功。
|
||||
- 已实现下游投递告警第一版:运营看板与右上角通知基于真实 `CmppDownstreamDelivery` 聚合显示下游投递告警数,当前告警口径包括“pending 超过阈值仍未投出”和“最近失败记录数”,用于提醒运营及时进入下游投递记录页处理。
|
||||
- 已实现下游投递 Dashboard 第一版:运营端“下游投递记录”页面顶部新增真实聚合总览,直接按 `tenantId/applicationId/deliveryType` 统计投递总量、pending/delivered/failed、积压告警、按类型分布、重试压力分布和应用告警排行,数据源必须来自 `CmppDownstreamDelivery`,不能靠前端本地汇总。
|
||||
- 下游投递的 `pending` 展示必须结合真实尝试字段:自动与人工次数均为 0 时显示“待首次投递”,`retryCount > 0` 时显示“等待自动重试”,`manualRetryCount > 0` 时显示“人工重投排队中”。人工重投可重置新一轮自动重试预算,但不得把记录伪装成从未投递。
|
||||
- 已实现下游投递告警统一口径:运营看板、侧栏通知、下游投递 Dashboard 和应用告警排行必须基于同一组真实 `CmppDownstreamDelivery` 条件统计:`pending` 超过积压阈值、`awaiting_ack` 超过 `ackDeadlineAt`,以及最近失败窗口内的 `failed/unconfirmed/rejected`。默认积压阈值为 10 分钟,最近失败窗口为 1 小时,可分别通过 `CMPP_DOWNSTREAM_ALERT_PENDING_MINUTES` 和 `CMPP_DOWNSTREAM_ALERT_RECENT_FAILED_HOURS` 覆盖。
|
||||
- 已实现下游投递 Dashboard 第一版:运营端“下游投递记录”页面顶部新增真实聚合总览,直接按 `tenantId/applicationId/deliveryType` 统计投递总量、pending/awaiting_ack/delivered/failed/unconfirmed/rejected、积压告警、ACK 超时告警、按类型分布、重试压力分布和应用告警排行,数据源必须来自 `CmppDownstreamDelivery`,不能靠前端本地汇总。应用告警排行只统计满足统一告警时间窗的记录,不得将新创建的 `pending` 或超出最近窗口的历史失败永久累加为告警。
|
||||
- 已实现下游连接映射持久化第一步:Gateway 在客户 CMPP 账号 bind 成功、下游 submit 建链和回执/上行下发时,会把账号在线状态、实例标识、最近活跃时间写入 Redis presence;该状态不再只保留在 Gateway 进程内存中,为后续“Gateway 重启后的 pending 恢复”提供外部状态基础。
|
||||
- 已实现下游连接映射持久化第二步:Gateway 启动时会读取 Redis presence 与当前内存在线账号,形成“恢复候选视图”,并通过控制面 `GET /downstream/recovery-candidates` 暴露候选账号列表,供后续恢复逻辑与运维排查使用;本阶段仍不等同于自动恢复 pending 投递。
|
||||
- 已实现下游 pending 恢复执行第一版:Gateway 启动后会立即按恢复候选账号拉取真实 `CmppDownstreamDelivery.pending`,后续每轮补投周期也会继续扫描恢复候选;若账号已有可用下游连接则继续推送回执/上行,若账号尚未重连则保持 `pending` 等待后续恢复,不能因为 Gateway 重启就把未投递记录误标成失败。
|
||||
|
||||
@@ -23,6 +23,19 @@
|
||||
| 号码 | 合法号码、重复号码、非法号码、企业黑名单号码、全局黑名单号码。 |
|
||||
| 账户 | 现金余额与授信额度组合后的和为正数、0、负数;授信额度覆盖正数、负数和 0;不配置套餐余量。 |
|
||||
| 企业认证 | 未认证、待审核、已通过、已驳回四类企业认证资料。 |
|
||||
|
||||
## 2.1 2026-07-15 运营端细节回归
|
||||
|
||||
| 用例编号 | 优先级 | 验证内容 | 预期结果 |
|
||||
| --- | --- | --- | --- |
|
||||
| TC-ADMIN-UI-0715-01 | P1 | 新建/编辑企业应用并留空或修改 CMPP 账号 | 企业代码控件不可编辑且实时跟随账号;API 最终持久化二者相等;超过每任务号码上限时整个任务被拒绝并有拆分说明。 |
|
||||
| TC-ADMIN-DICT-0715-02 | P1 | 删除手机号段;分别删除引用数为 0 和大于 0 的报备字段 | 号段从 PostgreSQL 删除;字段列表显示真实使用通道数,未引用字段删除成功,已引用字段按钮禁用且直接调用 DELETE 也返回 400。 |
|
||||
| TC-ADMIN-CMPP-0715-03 | P1 | 建立连接后主动断开,再制造心跳超时 | 连接详情只显示 active 连接;断开/超时行从 `CmppDownstreamConnection` 删除,操作日志仍保留断开审计。 |
|
||||
| TC-ADMIN-AUDIT-0715-04 | P0 | 不勾选、勾选部分任务分别点击批量操作 | 未勾选时按钮禁用;只通过已选任务,未选任务状态不变;确认弹窗数量等于选择数。 |
|
||||
| TC-ADMIN-DOWNSTREAM-0715-05 | P1 | 选择下游投递创建日期范围 | 列表及页面 Dashboard 使用同一日期范围查询真实数据库,范围外记录不计入。 |
|
||||
| TC-ADMIN-TEMPLATE-0715-06 | P1 | 将光标置于模板中间并插入推荐/自定义变量 | 变量在光标或选区处插入,原选区被替换,光标停在变量后;运营端和客户端一致。 |
|
||||
| TC-ADMIN-RECORD-0715-07 | P1 | 查看桌面/窄屏短信记录及失败详情 | 卡片不产生页面横向滚动,信息分组清晰;失败原因独立突出;详情仍读取真实 submit、receipt 和分片审计 API。 |
|
||||
| TC-ADMIN-MISC-0715-08 | P2 | 查看签名引流信息、零待审核通知和充值弹窗 | 使用“引流信息”标题且无提交时间;0 为黑字灰底;充值弹窗无操作人字段。 |
|
||||
| 客户 | 正常客户、停用客户、欠费客户、未认证客户、跨租户客户、客户联系人和开票资料。 |
|
||||
| 导入文件 | UTF-8 CSV、GBK CSV、TXT、超 20 MB 文件、含空行/重复/非法号码/非法字符文件。 |
|
||||
| 非法内容 | 控制字符、emoji、换行、不可见字符、超长变量、签名外置内容、敏感词内容。 |
|
||||
@@ -1167,6 +1180,21 @@
|
||||
- 全局 `reportStatus=reporting` 不在入站阶段触发 `SIGNATURE` 拒绝,短信进入真实人工审核聚合链路且不产生签名失败回执。
|
||||
- 审核通过后只允许选择签名任务为 approved 的主通道,不能选择 pending 的备用通道;最终提交前继续执行同一通道级校验。
|
||||
|
||||
### TC-SEND-039B CMPP 变量模板匹配与 direct_send 策略
|
||||
|
||||
- 优先级:P0
|
||||
- 前置条件:应用 A 存在审核通过模板 `【航天信息信诺网】您本次操作的验证码是${code},有效时间10分钟。`;应用 B 配置 `templateMismatchMode=direct_send`。两个应用均配置已审核签名、余额、真实通道组及至少一个签名报备通过且在线的通道。
|
||||
- 步骤:
|
||||
1. 应用 A 通过 CMPP 提交 `【航天信息信诺网】您本次操作的验证码是715021,有效时间10分钟。`。
|
||||
2. 查询 `SmsMessageRecord/SmsBatchTask/SmsSendTask`,并检查进入风险评估的模板和变量。
|
||||
3. 应用 B 提交签名合法但没有任何模板匹配的短信。
|
||||
4. 分别将应用 B 的签名改为未审核、账户改为余额不足、具体通道签名报备改为未通过后重复提交。
|
||||
- 预期结果:
|
||||
- 步骤 1 按固定正文和 `${code}` 占位符匹配模板,保存真实 `templateId`,向风控传入 `code=715021`,不得产生 `TEMPLATE/REJECTD` 失败回执。
|
||||
- 应用 B 的模板不匹配短信按 `direct_send` 继续进入风控、余额、队列和真实通道路由;消息保存识别出的 `signatureId`,不能被模板拒绝分支截断。
|
||||
- `direct_send` 只跳过模板匹配要求,不跳过企业/应用状态、签名审核、风控、余额、具体通道报备、通道在线状态和 Gateway 提交校验;任一校验失败时按真实失败原因拒绝或失败。
|
||||
- `reject` 与 `manual_review` 的既有行为不变;CMPP SubmitResp、失败 Deliver Receipt 和最终上游回执仍按既有异步语义处理。
|
||||
|
||||
### TC-GW-007 CMPP 客户到上游 SMSC 完整闭环
|
||||
|
||||
- 优先级:P0
|
||||
@@ -1298,7 +1326,9 @@
|
||||
- 页面列表来自真实 `/api/admin/operations/downstream-deliveries`,不是前端静态数组或本地状态拼装。
|
||||
- 详情展示真实 payload、`retryCount/nextRetryAt/deliveredAt/lastError`。
|
||||
- 人工重投调用真实 `/api/admin/operations/downstream-deliveries/{id}/requeue`,由后端实际触发 Gateway `/downstream/receipt` 或 `/downstream/uplink`。
|
||||
- 重投后记录状态、失败原因和系统日志都与真实后端处理结果一致。
|
||||
- 人工重投后 `manualRetryCount` 递增、`lastRetriedAt` 更新,新一轮 `retryCount` 从 0 开始;系统日志保留重投前状态、原自动重试次数和新人工重投次数。
|
||||
- 重投后若尚未真正写出,列表显示“人工重投排队中”,不得误显示“待首次投递”;自动失败退避中的 pending 显示“等待自动重试”。
|
||||
- `awaiting_ack` 记录在前端不可选且后端拒绝并发重投,不能仅依赖按钮禁用。
|
||||
|
||||
### TC-GW-015 下游投递指数退避
|
||||
|
||||
@@ -1326,17 +1356,18 @@
|
||||
- 后端逐条执行真实重投,返回 `total/successCount/failedCount/results`。
|
||||
- 成功和失败记录都会保留真实后端状态与错误信息;空选择时接口拒绝执行。
|
||||
|
||||
### TC-GW-017 下游投递告警聚合
|
||||
### TC-GW-017 下游投递告警统一聚合
|
||||
|
||||
- 优先级:P1
|
||||
- 前置条件:真实 `CmppDownstreamDelivery` 中准备一批 `pending` 记录,其中部分已超过告警阈值;同时准备一批最近失败的 `failed` 记录。
|
||||
- 前置条件:真实 `CmppDownstreamDelivery` 中准备阈值内/外的 `pending`、未超时/已超过 `ackDeadlineAt` 的 `awaiting_ack`、最近窗口内/外的 `failed/unconfirmed/rejected` 及正常 `delivered` 记录,且覆盖多个应用。
|
||||
- 步骤:
|
||||
1. 访问运营端 Dashboard 和右上角通知区域。
|
||||
2. 调用真实 `/api/admin/operations/dashboard/statistics`,核对返回的下游投递告警聚合。
|
||||
3. 点击“下游投递告警”通知,跳转到下游投递记录页进一步筛查。
|
||||
- 预期结果:
|
||||
- Dashboard 返回真实 `downstreamDeliverySummary`,至少包含 `pending/failed/delivered/stalledPending/recentFailed/alertCount`。
|
||||
- 右上角通知中的“下游投递告警”数量与真实 Dashboard 聚合一致,不是前端写死值。
|
||||
- Dashboard 返回真实 `downstreamDeliverySummary`,至少包含 `pending/failed/delivered/stalledPending/stalledAck/recentFailed/alertCount`。
|
||||
- `alertCount` 精确等于“超阈值 pending + 超时 awaiting_ack + 最近窗口内 failed/unconfirmed/rejected”,阈值内 pending、未超时 awaiting_ack、历史失败和 delivered 不计入。
|
||||
- 侧栏/首页的“下游投递告警”数量与下游投递 Dashboard 在同一筛选范围下一致,不是前端写死值。
|
||||
- 点击通知后可以进入真实下游投递记录页继续处理。
|
||||
|
||||
### TC-GW-018 下游投递 Dashboard 聚合视图
|
||||
@@ -1349,10 +1380,10 @@
|
||||
3. 切换应用和类型筛选,确认顶部 Dashboard 与下方记录列表同时切换到同一筛选范围。
|
||||
- 预期结果:
|
||||
- 顶部 Dashboard 必须来自真实聚合接口,不能由当前页列表条目在前端临时汇总。
|
||||
- `summary` 中 `total/pending/delivered/failed/stalledPending/recentFailed/alertCount` 与数据库真实结果一致。
|
||||
- `summary` 中 `total/pending/awaitingAck/delivered/failed/unconfirmed/rejected/stalledPending/stalledAck/recentFailed/alertCount` 与数据库真实结果一致。
|
||||
- `typeBreakdown` 能正确区分 `receipt` 和 `uplink` 的状态分布。
|
||||
- `retryBuckets` 真实反映 `pending/failed` 记录的重试压力分布。
|
||||
- `topApplications` 以告警量优先排序,切换筛选后结果实时刷新。
|
||||
- `topApplications` 使用与 `summary.alertCount` 相同的时间窗和状态条件统计,各应用告警数之和与同范围总告警一致,并以告警量优先排序。
|
||||
|
||||
### TC-GW-019 下游在线账号 Presence 持久化
|
||||
|
||||
|
||||
@@ -1,5 +1,37 @@
|
||||
# 第一版系统化测试进度
|
||||
|
||||
## 2026-07-15 CMPP 变量模板与 direct_send 修复(未提交、未部署)
|
||||
|
||||
- 生产只读诊断确认:10:52:58 账号 `910887` 向 `18821203795` 提交验证码短信,应用已于 10:52:36 保存 `templateMismatchMode=direct_send`,且存在审核通过的 `${code}` 变量模板;原实现用正文精确相等查询,实际验证码无法匹配占位符,同时模板为空时仅识别 `manual_review`,导致 `direct_send` 错误落入 `TEMPLATE/REJECTD`。
|
||||
- `resolveInboundTemplateCandidate` 先保留精确匹配,再对同应用变量模板执行固定正文全量匹配,提取非空变量值;同名变量重复出现必须取值一致。匹配成功后保存真实 `templateId`,并将变量值传给真实风控评估。
|
||||
- 新增 `direct_send` 分支:模板不匹配时识别并保存已审核完整括号签名,继续执行风控、余额冻结、真实队列、通道组路由和具体通道签名报备校验;只跳过模板要求,不做无条件放行。`reject/manual_review` 行为保持不变。
|
||||
- 新增变量模板验证码和 `direct_send` 两项回归;SendChainService 1 suite/49 项通过,API 全量 17 suites/169 项通过,Prisma validate、API build、前端 build 和 `git diff --check` 通过,前端仅有既有 Vite chunk size warning。按用户要求未提交、未推送、未部署,未重投 10:52:58 的短信。
|
||||
|
||||
## 2026-07-15 运营端细节修复批次(未提交、未部署)
|
||||
|
||||
- 企业签名引流字段统一为“引流信息”并隐藏提交时间;人工充值弹窗移除操作人;待审核通知中的 0 使用黑字灰底。
|
||||
- 企业应用表单补充每任务号码上限的整任务拒绝说明;企业代码控件不可编辑并跟随 CMPP 6 位账号,NestJS 创建/更新也强制持久化两者相等。
|
||||
- 手机号段新增真实 DELETE;报备字段 API 返回真实通道引用数,未引用可删除,引用数大于 0 时前端禁用且后端返回 400。
|
||||
- 客户 CMPP 连接详情只展示已连接会话;Gateway 上报断开时删除活跃连接行,心跳超时扫描也删除,新增 migration 清理旧非 connected 行,断开操作日志仍保留。
|
||||
- 短信审核新增逐行/全选勾选,批量按钮只处理已选任务;下游投递列表与 Dashboard 增加统一创建日期范围参数并下推 Prisma/PostgreSQL。
|
||||
- 运营端和客户端短信模板变量均插入当前光标/选区位置;短信记录前端改为自适应卡片和分组详情,失败原因独立警示,不改变短信记录后端接口与业务语义。
|
||||
- 定向 API 测试 `dictionaries/sms-config/operations` 为 3 suites、49 项通过;API 全量 17 suites、167 项通过,Prisma validate、API build、前端 build、Gateway 全量 Go 测试和 `git diff --check` 均通过,前端仅有既有 chunk size warning。本地真实 PostgreSQL 已应用连接清理 migration,43 条 migration 全部齐全。
|
||||
- 应用内浏览器已验证本地构建的运营端登录路由标题为“聆界短信管理平台”、DOM 非空且无框架错误覆盖;受 HttpOnly 会话和图形验证码限制,未绕过认证进入受保护页面。后续浏览器连接因桌面插件版本热更新失败,未以独立 Playwright 或 mock 页面替代。按用户要求保持未提交、未推送、未部署。
|
||||
|
||||
## 2026-07-15 下游人工重投状态追踪修复(未提交、未部署)
|
||||
|
||||
- 根因确认:人工重投会将 `CmppDownstreamDelivery` 重置为 `pending/retryCount=0`,前端又将所有 pending 固定翻译为“待首次投递”,导致已人工重投的记录被误展示为从未投递。
|
||||
- 新增 `CmppDownstreamDelivery.manualRetryCount/lastRetriedAt` 及真实 Prisma migration;人工重投时递增人工次数、保存时间,并在 `OperationLog` 中记录重投前状态、原自动重试次数和新人工次数。自动重试次数仍可为新一轮重置为 0,但不再丢失人工重投轨迹。
|
||||
- 列表和详情改为基于真实字段显示:初始 pending 为“待首次投递”,仅自动失败为“等待自动重试”,存在人工重投时为“人工重投排队中”;分开展示自动/人工次数和最近人工时间。
|
||||
- 后端新增 `awaiting_ack` 并发重投拦截,避免绕过前端禁用直接调 API 造成重复投递。本地 PostgreSQL 42 条 migration 全部齐全,Prisma validate/status 通过,SendChainService + OperationsService 定向回归 2 suites/62 项通过,前端 build 通过(仅既有 Vite chunk size warning)。API build 曾在本次改动完成后通过;随后工作区并发出现的非本任务修改在 `sms-config.service.ts:300` 引入未定义的 `application`,当前 API 全量回归被该编译错误阻断,未覆盖或回退该并发修改。本修复未提交、未推送、未部署。
|
||||
|
||||
## 2026-07-15 下游投递告警口径统一(未提交、未部署)
|
||||
|
||||
- 修复前存在三套口径:侧栏/首页只统计超阈值 pending 和最近 failed;详情页额外统计超时 awaiting_ack 与最近 unconfirmed/rejected;应用排行则将全部 pending 和所有历史失败累加为告警,造成同一时刻数量不一致。
|
||||
- 统一为“超阈值 pending + 超过 `ackDeadlineAt` 的 awaiting_ack + 最近窗口内 failed/unconfirmed/rejected”;默认积压阈值 10 分钟、最近失败窗口 1 小时,继续支持环境变量覆盖。
|
||||
- `OperationsService.dashboard()` 和 `downstreamDeliveryDashboard()` 复用同一时间窗生成逻辑,首页/侧栏补齐 `stalledAck` 与三种最终异常状态;应用告警排行改为单独按统一告警 where 聚合,不再将普通 pending 和历史失败永久累加。
|
||||
- 已补实 OperationsService 定向单元测试,覆盖首页三类告警条件和应用排行统一条件。API 完整 17 suites、163 项通过,API build 和前端 build 通过;前端仅有既有 Vite chunk size warning。本批按要求保持未提交、未推送、未部署。
|
||||
|
||||
## 2026-07-14 生产发送 Worker 配置缺失修复
|
||||
|
||||
- 生产号码 `18821203795` 的最新短信于 18:24:59 审核通过后恢复为 queued,BullMQ 已生成 job,但一直停留在 `bull:sms.send.queue:prioritized`,无通道、`submitId` 和 `SmsSubmitRecord`。
|
||||
|
||||
Reference in New Issue
Block a user