feat: harden CMPP delivery and platform workflows
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
# 2026-07-20 回执身份与报表口径迁移说明
|
||||
|
||||
## 升级
|
||||
|
||||
1. 发布前按生产流程备份 PostgreSQL、运行源码和环境配置并校验归档。
|
||||
2. 依次应用 `20260720110000_add_receipt_identity`、`20260720113000_add_report_business_metrics` 与 `20260720114500_add_receipt_phone_number`。三者为历史回执生成不冲突的 `receiptKey`,增加回执文本、目的号码和匹配索引,并增加报表失败数及利润退款金额列。历史目的号码先从原关联主记录回填;对已知错绑记录仍须依据生产提交记录、通道和原始 Gateway 日志专项复核,不能仅靠该回填自动改绑。
|
||||
3. 先重启 Gateway,再重启 API;检查 Redis Stream、活动通道、TPS key、API/Gateway health 和近期错误日志。
|
||||
4. 对 T-4 至 T-1 及需修复的历史日期重复执行报表重算,核对查询与 CSV 的发送、成功、失败、收入、退款、成本、利润和到达时长。
|
||||
|
||||
## 回滚
|
||||
|
||||
应用代码可回滚到上一版本,但新增列和索引默认保留,避免丢失已接收的回执身份、错误文本和重算结果。若确认不存在新版本写入且必须做结构回滚,应先备份,再依次删除两个报表新增列、回执新增列及索引;删除 `receiptKey` 唯一约束前必须确认旧代码不会再次以模糊条件消费回执。生产禁止未经审批直接执行破坏性回滚。
|
||||
@@ -764,7 +764,7 @@
|
||||
### 9.5 发送
|
||||
|
||||
- sms_batch_task:批量任务。
|
||||
- sms_message_record:单号码发送记录,所有平台任务、API 调用、CMPP 对接发送均进入此表。
|
||||
- sms_message_record:单号码发送记录,所有平台任务、API 调用、CMPP 对接发送均进入此表。客户 CMPP Submit 的 `DestUsrTl/DestTerminalId` 包含多个号码时,Gateway 和 NestJS 必须按目标号码拆分为多条独立记录,每个号码分别执行模板/签名、风控、余额、计费、路由、上游提交和回执处理;同一客户 Submit 仍只返回一个 CMPP SubmitResp/Msg_Id,后续 Deliver Receipt 以该 Msg_Id 与各自 `DestTerminalId` 区分。所有拆分记录必须持久化同一 Submit 分组消息 ID,使 Gateway 重启后仍能重建客户最初收到的 Msg_Id。任何目标号码格式非法时必须在落库前拒绝整包,禁止返回成功后只处理首号码。
|
||||
- sms_api_request:API 调用批次记录。
|
||||
- cmpp_submit_session:CMPP 对接提交会话或批次记录。
|
||||
- sms_submit_record:通道提交记录。
|
||||
@@ -1543,3 +1543,30 @@
|
||||
4. 参数复制必须兼容平台当前 HTTP 页面:优先使用 Clipboard API;浏览器因非安全上下文或权限拒绝时,使用受控 textarea 复制降级,并向用户明确反馈成功或失败,不得无提示失败。
|
||||
5. `cmppMaxConnections` 必须在 Gateway 登录时按应用和活动 TCP 会话真实计数并限制,同时由 API 的连接事件校验兜底。连接关闭或异常断开后必须及时释放连接名额并回写断开事件。
|
||||
6. CMPP IP/CIDR 白名单必须在登录和连接事件中校验;运营端修改白名单、关闭接口、停用应用或降低最大连接数后,Gateway 应在下一次心跳校验时关闭不再符合条件的存量连接,不能只限制后续 Submit。
|
||||
|
||||
## 2026-07-18 手工验收瑕疵收口要求
|
||||
|
||||
1. 图片上传单文件不得超过 2MB,其他文件不得超过 10MB;前端选择文件时即时提示,NestJS 接口与 MinIO 入库前必须再次校验,不得只依赖页面限制。
|
||||
2. 企业统一社会信用代码仅允许英文字母和数字,前后端同时校验;上传文件名需换行,营业执照预览和下载使用一致的操作样式。
|
||||
3. HTTP 由未开通切换为开通时,默认开启发送、状态查询、回执 Webhook、上行查询、上行 Webhook 和客户自助凭据全部能力,回执与上行默认使用 HTTP Webhook;参数复制页须展示业务化投递方式,不直接暴露 `cmpp/http/both/none` 原始值。
|
||||
4. 企业应用、短信记录的“查询”和“重置”即使条件未变也必须重新请求真实 API;CMPP 连接详情不得依赖水平滚动,长 AppID/连接 ID 必须可换行。
|
||||
5. 短信审核列表时间统一为 `YYYY-MM-DD HH:mm:ss`;审核人和审核时间由当前 HttpOnly 会话在服务端写入,列表用“更多信息”展示;操作成功后待审角标立即重新请求真实仪表盘 API。
|
||||
6. 短信详情同时展示客户提交时收到的接入号和平台送往上游的接入号;运营商区分规则显示中文名称并支持真实 DELETE API。
|
||||
7. 所有登录用户发起且成功的 POST/PUT/PATCH/DELETE 操作必须写入 PostgreSQL `OperationLog`,至少保存操作人、方法、路径、资源 ID、状态码、IP 和 User-Agent;不得记录密码、密钥或请求体。
|
||||
|
||||
## 2026-07-20 回执、报表、安全与公开 HTTP 接口收口要求
|
||||
|
||||
1. 上游回执按内部消息 ID,或 `channelId + gatewayMessageId + DestTerminalId` 对提交记录作唯一匹配;同账号多通道不得互相认领。每个回执事件必须有数据库唯一键,并发或重复事件不得重复生成记录、退款、计费或下游投递。
|
||||
2. 成功回执统一更新短信主记录状态、回执状态、到达时间、真实通道、通道消息号、原始回执码和文本;失败、超时和未知回执保留可解释状态,最终失败只退款一次。
|
||||
3. 对账、利润和质量报表统一以短信记录计费条数为发送量,以唯一主记录终态统计成功/失败;收入取扣费流水,返还取退款流水,成本取真实提交通道单价,利润等于收入减成本。到达时长按提交至成功回执计算,延迟回执由 T+1 和 T-4 至 T-1 重算覆盖;查询、页面和 CSV 共用同一聚合表。
|
||||
4. 运营端与客户端用户接口使用各自安全 DTO,禁止输出密码散列、会话版本、登录失败内部计数和密钥字段。后端禁止自删除/自停用、禁止删除或降权最后一个平台管理员及企业管理员,并强制校验跨租户操作;唯一冲突返回 HTTP 409 和明确字段。
|
||||
5. HTTP 单发公开契约使用 `mobile`、`content` 和可选 `clientMessageId`,不要求内部签名或模板 ID;服务端按 CMPP 同一规则识别已审核签名、模板及变量,复用风控、余额、计费、路由和队列。成功返回可查询 messageId,业务拒绝返回对应 4xx,不得在已创建记录后返回“批次不存在”。
|
||||
6. 客户发送候选只返回 approved 签名和模板,管理视图可查看历史状态。模板变量必须拒绝空变量、未闭合、中文或非法名称、重复名称及超长名称;客户端签名视图仅返回必要报备汇总状态。
|
||||
7. 报备资料提供官方 XLSX 模板和按当前筛选导出;导入拒绝空文件、错误扩展名、超限文件以及公式/脚本单元格。分析、提交和导出日志记录操作人、文件名、筛选条件、成功数、失败数和 IP,不保存密钥或完整请求体。
|
||||
|
||||
## 2026-07-20 客户端用户管理移动操作可达性要求
|
||||
|
||||
1. 客户端用户管理在`≤780px`使用键值卡片时,编辑、改密、禁用/启用、删除四项操作不得继续沿用不可换行的桌面横排;采用2×2网格或可访问的“更多操作”菜单,任何允许动作都不得因容器裁切而消失。
|
||||
2. 390×844和375×667下四项操作必须全部可见、可聚焦、可命中,触控热区高度至少44px;操作组应具有包含目标用户名称的可访问名称。
|
||||
3. 删除仍必须走真实客户端用户API与确认流程,不得通过前端隐藏或静态数据冒充;页面验收只打开并取消确认时,不得产生DELETE请求或数据库状态变化。
|
||||
4. 1440×900、1366×768和768×1024必须同步回归。1366桌面宽表若仍需内部横向滚动,滚动条必须可发现且操作可到达;固定操作列和邮箱列宽另按全站Table整改治理。
|
||||
|
||||
@@ -1159,7 +1159,7 @@
|
||||
- 步骤:
|
||||
1. 启动 Go Gateway,确认 `GATEWAY_CMPP_ADDR=0.0.0.0:17890`。
|
||||
2. 使用 gocmpp 或真实 CMPP 客户端连接 `17890`,`Source_Addr` 填应用 `cmppAccount`,密码填应用 CMPP 参数 `passwordCipher`。
|
||||
3. 分别发送 CMPP 2.0 和 CMPP 3.0 SubmitReq,手机号和内容匹配已审核模板。
|
||||
3. 分别发送 CMPP 2.0 和 CMPP 3.0 单号码 SubmitReq;再发送 `DestUsrTl=2`、两个合法 `DestTerminalId` 的多号码 SubmitReq,手机号和内容均匹配已审核模板。
|
||||
4. 再发送一条不匹配审核模板的 SubmitReq,检查客户收到的 SubmitResp 和 Gateway 日志。
|
||||
5. 查询 NestJS 数据库和运营端短信记录。
|
||||
- 预期结果:
|
||||
@@ -1167,10 +1167,10 @@
|
||||
- bind 阶段调用真实 NestJS API 校验账号、密码、企业状态、认证状态、应用状态、短信接口开关和 IP 白名单。
|
||||
- CMPP2.0 和 CMPP3.0 连接分别返回对应版本 ConnectResp,后续 Submit/Deliver 按该 TCP 连接协商版本解包和组包,不发生字段错位。
|
||||
- 密码错误、应用停用、企业停用、短信接口关闭、IP 不在白名单时 connect/login 被拒绝。
|
||||
- submit 被接受后返回 CMPP SubmitResp 成功,并在真实数据库创建 `sourceType=cmpp` 的发送记录,进入真实发送链路。
|
||||
- submit 被接受后返回 CMPP SubmitResp 成功,并在真实数据库创建 `sourceType=cmpp` 的发送记录,进入真实发送链路。多号码 Submit 仍只返回一个 SubmitResp/Msg_Id,但必须为全部目标号码分别创建 `SmsMessageRecord` 和内部批次,分别校验、计费、路由和提交;每个号码的 Deliver Receipt 使用同一原 Submit Msg_Id,并以各自 `DestTerminalId` 区分。Gateway 重启后从持久化分组消息 ID 和 Submit Sequence_Id 恢复时,所有号码的回执 Msg_Id 仍必须与原 SubmitResp 完全一致。
|
||||
- `sourceType=cmpp` 的内部批次不出现在运营端或客户端“短信任务进度”;客户端不能通过任务 ID 读取该内部批次的详情、短信明细或执行取消。
|
||||
- Submit 应用身份使用 bind 已鉴权账号;`MsgSrc` 使用应用级企业代码并独立校验。企业代码与登录账号不同时仍能正确定位应用,企业代码不匹配时返回失败。
|
||||
- 鉴权失败、IP 白名单不符、手机号等协议参数不合法时返回非零 SubmitResp,且不创建短信记录。
|
||||
- 鉴权失败、IP 白名单不符、任一目标手机号等协议参数不合法时返回非零 SubmitResp,且整包不创建短信记录;禁止多号码 Submit 返回成功后只保存或发送首号码。
|
||||
- 已鉴权且参数合法的 Submit 必须先返回成功 SubmitResp 和平台 Msg_Id;内容不匹配审核模板、签名/报备未通过、余额不足、应用在 bind 后停用、无可用通道、上游 Submit 最终失败时,均须真实创建短信记录、`SmsReceiptRecord` 和 `CmppDownstreamDelivery`,并向客户下发 `undelivered/REJECTD` Deliver Receipt,不得仅以 SubmitResp 失败替代回执。
|
||||
- Gateway 对每次 submit 记录 `submit_received` 和 `submit_accepted`/`submit_rejected`;日志可按账号、IP、sequenceId、号码和 messageId 定位,拒绝时包含 NestJS 真实业务原因和 CMPP result,但不包含明文短信正文。
|
||||
- CMPP 包在进入 handler 前因长度、命令字、读包或 Unpack 失败时,Gateway 记录 `read/unpack packet failed`、远端地址、协议模式、错误类型和原始错误,不得静默断开。
|
||||
@@ -3518,3 +3518,38 @@ npm run verify:phase8
|
||||
| TC-HTTP-WEBHOOK-002 | 回调依次返回 500、429、408、400、302 和 200,并模拟超时。 | 500/429/408/网络错误按既定退避重试,400 和重定向终结,2xx 成功;每次尝试、状态码、耗时和截断响应写 PostgreSQL,可授权手工重投。 |
|
||||
| TC-HTTP-WEBHOOK-003 | 保存指向 localhost、RFC1918、链路本地、共享地址、云元数据 IP、会解析到私网的域名和发生 DNS 重绑定的 URL。 | 保存或投递前被 SSRF 校验拒绝;不跟随重定向;生产 HTTPS 约束开启时 HTTP URL 被拒绝。 |
|
||||
| TC-HTTP-CLIENT-001 | 客户端打开“接口对接”五个页签,切换应用、创建凭据、配置回调、查看文档与日志;API 断开后重试。 | 所有状态来自真实 API/PostgreSQL/Redis;应用卡片显示 HTTP 状态;API 失败展示错误,不使用 localStorage 或前端静态数据伪造成功。 |
|
||||
|
||||
### 17.15 手工验收瑕疵回归
|
||||
|
||||
| 用例编号 | 操作 | 预期结果 |
|
||||
| --- | --- | --- |
|
||||
| TC-DEFECT-001 | 分别选择 2MB 与超过 2MB 的图片、10MB 与超过 10MB 的普通文件,并绕过前端直接请求上传 API。 | 边界值可上传至 MinIO,超限在前端即时拒绝且 API 再次返回 400,MinIO 无超限对象。 |
|
||||
| TC-DEFECT-002 | 新建/编辑企业,输入中文、标点和英文数字信用代码,上传长文件名执照并预览/下载。 | 非英文数字被拒绝,合法值真实入库;文件名换行且两个操作样式一致。 |
|
||||
| TC-DEFECT-003 | 编辑一个 HTTP 未开通的应用,切换为开通并保存,刷新后查看/复制 HTTP 参数。 | 六项能力全部开启,回执/上行为 HTTP Webhook,配置真实写入 PostgreSQL,复制内容不显示原始枚举值。 |
|
||||
| TC-DEFECT-004 | 企业应用列表保持相同条件连续点击查询/重置,打开包含长 ID 的 CMPP 连接详情;短信记录同样操作。 | 每次均有真实 API 请求且数据更新;弹窗无水平滚动,长 ID 自动换行。 |
|
||||
| TC-DEFECT-005 | 通过/驳回一条待审短信并查看列表、更多信息及导航角标。 | 审核人/时间由当前会话写库,时间格式正确,列表不额外占列,角标不等待 30 秒轮询即更新。 |
|
||||
| TC-DEFECT-006 | 打开真实短信详情,再新增后删除一条运营商区分规则。 | 详情分别展示 `clientSrcId` 与通道 `srcId + applicationExtension`;运营商显示中文,DELETE API 真实删库并刷新。 |
|
||||
| TC-DEFECT-007 | 用登录运营用户修改企业应用及其他任一写操作,再查看系统日志;另构造失败请求。 | 成功写操作均有操作人、路径、资源和结果日志;失败请求不写伪成功日志,日志不含请求体、密码或密钥。 |
|
||||
|
||||
### 17.16 2026-07-20 缺陷回归
|
||||
|
||||
| 用例编号 | 操作 | 预期结果 |
|
||||
| --- | --- | --- |
|
||||
| TC-RECEIPT-IDENTITY-001 | 两个通道使用同一下游账号及相同通道 Msg_Id,分别向两个号码提交,再乱序返回回执。 | 以通道、通道 Msg_Id 和号码唯一关联提交记录;主记录写入正确通道、到达时间、原始状态和文本,无跨通道抢占。 |
|
||||
| TC-RECEIPT-IDEMPOTENT-001 | 顺序和并发重复发送相同 DELIVRD,随后重启服务并再次发送。 | `receiptKey` 唯一约束保证只保存一次、只下发一次客户回执,且不重复计费或退款;重启后行为一致。 |
|
||||
| TC-REPORT-RECALC-001 | 插入一条成功、一条失败及扣费/退款流水,执行指定日期重算两次,再查询应用和通道报表及 CSV。 | 两次结果一致;发送 2、成功 1、失败 1;收入、退款、成本和利润使用相同金额单位且 `利润=收入-成本`;平均到达时长来自真实提交/回执时间。 |
|
||||
| TC-USER-SAFE-001 | 分别查询运营端、客户端用户列表和详情,并尝试跨租户访问。 | 响应不含 `passwordHash`、`sessionVersion`、密钥或认证内部字段;跨租户查询、更新、改密、禁用和删除由 API 拒绝。 |
|
||||
| TC-USER-CONTINUITY-001 | 当前用户删除/停用自己,删除或降权最后一个平台管理员、最后一个企业管理员,并创建重复用户名。 | 前三类操作返回 403;最后管理员保护生效;唯一冲突返回 409 和冲突字段,不出现 500。 |
|
||||
| TC-HTTP-SEND-002 | 仅传 `mobile/content`,正文使用已审核签名及 `${code}` 模板,调用公开发送接口并重放同一幂等键。 | 自动识别签名/模板并提取合法变量,经真实发送链返回 202、稳定 messageId;相同请求返回同一结果,不出现批次 404。 |
|
||||
| TC-TEMPLATE-VARIABLE-001 | 提交空变量、未闭合、中文、重复、超长和非法字符变量,再查看发送候选。 | 前后端均拒绝非法变量;候选只含 approved 签名/模板,disabled/rejected 仅在历史管理视图显示。 |
|
||||
| TC-REPORT-MATERIAL-SAFE-001 | 下载官方 XLSX;按筛选导出;导入空文件、错误扩展名、超限文件、含公式/脚本单元格及部分错误行文件。 | 模板和导出为真实 XLSX;危险文件在入库前拒绝,部分失败保留行级原因;日志含操作人、文件名、筛选和计数,不含敏感请求体。 |
|
||||
|
||||
### 17.16 客户端用户管理移动操作可达性回归
|
||||
|
||||
| 用例编号 | 操作 | 预期结果 |
|
||||
| --- | --- | --- |
|
||||
| TC-UIUX-P0-001 | 使用真实企业管理员登录客户端并打开`/client/users`,依次设置390×844和375×667。 | 真实`/api/client/users`返回的用户以卡片显示;编辑、改密、禁用/启用、删除形成2×2操作网格,全部位于视口和卡片裁切范围内。 |
|
||||
| TC-UIUX-P0-002 | 在390和375视口测量四个操作按钮并逐项执行命中测试。 | 每项高度至少44px,中心点命中自身按钮,页面根节点无横向溢出;操作组可访问名称包含目标用户。 |
|
||||
| TC-UIUX-P0-003 | 在375视口点击删除,读取确认内容后点击取消。 | 确认层显示目标用户名;取消后用户仍在列表,PostgreSQL记录保持active且没有执行删除。 |
|
||||
| TC-UIUX-P0-004 | 依次设置768×1024、1366×768、1440×900并复核同一用户。 | 平板四项操作全部可见且热区≥44px;1440首屏完整;1366即使存在内部横向滚动,滚动后删除必须完整可达,且页面级无横向溢出。 |
|
||||
| TC-UIUX-P0-005 | 完成五视口操作后检查浏览器控制台并执行前端/API构建与用户服务回归。 | 无新增console error/warn;前端与API build通过,用户服务测试通过,`git diff --check`通过。 |
|
||||
|
||||
@@ -2008,3 +2008,44 @@ git diff --check
|
||||
- 工作区完整功能提交 `faa716b8d07ea77fae3ec41c858b52f6a341e6b9` 和重启恢复修正提交 `23a1f6fa15445dbe6d2e4738b10b545b7c657472` 已 push。两次发布前备份分别位于 `/opt/cmpp-platform/backups/releases/20260716-175500` 和 `/opt/cmpp-platform/backups/releases/20260716-180244`,PostgreSQL、运行源码和环境配置均通过 gzip/tar 完整性及 SHA-256 校验;最终发布包本地与服务器 SHA-256 均为 `c34c0fb627b77aa0c1a3d08169b3aff8d04587544ed9c1d83d8c0cd41b007272`。
|
||||
- 生产 migration `20260716150000_expand_money_precision_to_four_decimals` 已应用,53 条 migration 齐全,`SmsApplication.customerUnitPrice` 等金额列已为 `BIGINT`。生产 API/Gateway health、PostgreSQL、Redis PONG、MinIO、Nginx 及 `12026/17890/8090/3000/9000` 监听均正常;两个真实通道 TPS key 均为 100,`gateway.submit.commands` 为 `pending=0、lag=0`,部署后 API/Gateway 无 error 级日志。
|
||||
- 生产公网 CMPP 参数已配置为 `8.160.169.106:17890`。不符合白名单的 `715011 / 183.194.97.158` 陈旧连接在超时窗口后自动清除,合法账号 `910887` 由新 Gateway 建立新连接并持续更新心跳,证明白名单和重启后连接名额恢复逻辑真实生效。Chrome/Playwright 复核运营登录、390px 客户端登录和客户 Swagger 文档均为 200、无横向溢出、无 console/page error;未绕过验证码、未修改账号、未发送短信。
|
||||
|
||||
## 2026-07-18 CMPP 多号码 Submit 首号码静默丢弃修复(未提交、未部署)
|
||||
|
||||
- 生产只读复现确认:账号 `695829` 的 CMPP 3.0 Submit 日志记录 `dest_count=2`,Gateway 返回 `result=0`,但只将首号码 `188****3795` 传入 NestJS 并创建一条 `SmsMessageRecord`;随后单独提交第二个号码 `131****0092` 才产生第二条记录。核查期间未修改生产配置、数据或进程。
|
||||
- 根因为 Gateway 已完整解码 `DestTerminalId[]`,但处理时固定读取下标 `0`;Gateway→NestJS 契约和 `submitInboundMessage` 也只有单数 `phoneNumber`,NestJS 固定以 `phoneTotal=1` 创建内部批次和短信记录。当前行为属于“返回成功但静默丢失后续号码”,不是可接受的单号码范围限制。
|
||||
- Gateway 入站契约新增完整 `phoneNumbers`,保留首号码字段兼容;NestJS 在任何业务落库前校验全部目标号码,并以最多 10 个并发的有界批次逐号码复用现有真实模板/签名、风控、余额、计费、队列和失败回执链路。每个号码创建独立 `sourceType=cmpp` 内部批次和 `SmsMessageRecord`,API 返回全部内部 messageId 映射。
|
||||
- 一个客户 Submit 仍只返回一个 CMPP SubmitResp/Msg_Id。Gateway 将该 Msg_Id 同时关联到本包全部内部 messageId,后续每个号码的 Deliver Receipt 使用相同原 Submit Msg_Id,并通过自己的 `DestTerminalId` 区分;连接断开时同步清理同一连接下全部消息映射。新增 migration `20260718130000_add_cmpp_submit_group_message_id`,为每条拆分记录持久化同一 `cmppSubmitGroupMessageId`;Gateway 重启恢复时结合该分组 ID 与原 Sequence_Id 重建相同 Msg_Id,不再按各内部 messageId 算出不同结果。
|
||||
- 新增 API 回归覆盖两号码分别落库、分别生成失败回执,以及任一号码非法时整包落库前拒绝;Gateway 真实 CMPP 3.0 TCP 集成用例改为一次提交两个号码,并验证第二个内部消息的 Deliver 携带第二个号码且 Msg_Id 与原 SubmitResp 相同,另覆盖重启恢复时两个内部 messageId 仍重建同一 Msg_Id。API 定向测试 1 suite/60 项、API 全量 20 suites/215 项、Gateway `internal/inbound` 定向测试、Gateway 全量 `go test ./...`、API TypeScript build、前端 TypeScript/Vite build、Prisma generate/validate 均通过;本地 PostgreSQL 已应用 54 条 migration 且 schema 最新,前端仅有既有 chunk size warning。
|
||||
- 使用真实本地 NestJS API、PostgreSQL 和 Redis 创建临时接口关闭应用,向 `/api/gateway/events/inbound/submit` 一次提交两个合法号码:API 返回 `phoneCount=2` 和两个内部 messageId,数据库真实生成 2 个 `sourceType=cmpp` 内部批次、2 条短信记录、2 条失败回执和 2 条下游投递;两条记录的 Sequence_Id 与 `cmppSubmitGroupMessageId` 分别一致,下游 payload 只有 1 个分组 ID。再提交“一个合法号码 + 一个非法号码”返回 HTTP 400,记录数保持不变。临时企业、应用、白名单、批次、短信、回执和投递已全部清理,未连接上游 Gateway、未发送短信。
|
||||
|
||||
## 2026-07-18 手工验收瑕疵修复(未提交、未部署)
|
||||
|
||||
- 已实现图片 2MB/其他文件 10MB 前端与 NestJS 双层校验,通用文件和报备材料上传不再允许 20MB/100MB;企业信用代码收紧为英文字母与数字,营业执照操作样式和长文件名换行已修复。
|
||||
- 企业应用 HTTP 开通时默认开启六项能力并使用 HTTP Webhook,参数复制改为中文业务文案;应用列表查询/重置每次重请真实 API,CMPP 连接详情改为无水平滚动的自适应卡片;桌面侧栏强制隐藏移动端关闭按钮。
|
||||
- 审核 API 从当前登录会话写入审核人,列表时间格式化,审核人/时间收入“更多信息”弹窗,审核成功即时刷新导航角标。短信记录查询/重置重请 API,详情新增客户提交接入号与上游发送接入号。
|
||||
- 引流列表移除重复的“引流信息”列并改名“引流url或号码”;运营商规则改为中文标签,新增真实 NestJS/Prisma DELETE 链路。成功登录由用户服务写入 `auth.login_success`,其他会话用户成功写操作由统一 `OperationLog` 中间件兜底,不记录请求体和密钥。
|
||||
- 定向验证通过:API TypeScript build;文件、企业、风控审核、用户登录与人工操作日志 5 个 Jest suites/27 项;前端 TypeScript/Vite build;Prisma validate;`git diff --check`。前端仅有既有 chunk size warning。API 全量 Jest 已尝试,21 suites 中 20 suites、219 项中 218 项通过;唯一失败是另一会话正在修改的 `send-chain.service.spec.ts` 用例在本地 Redis `127.0.0.1:6379` 未运行时连接超时,本次未改动该套件。未在生产写入业务数据,未发送短信。
|
||||
- 生产只读排查:`MSG-22a27cd0-b671-4ae8-8beb-6608eaf04517` 已有真实未达回执,但无 `CmppDownstreamDelivery`/HTTP Webhook 事件;该问题与另一会话正在修复的 CMPP 多号码 Submit/Msg_Id 分组链路相互耦合,本次未修改 send-chain、Gateway inbound、Prisma schema 及其 migration,避免覆盖并行修复。“今日返还”数据核查发现当前包含发送链在路由/模板校验前的冻结后释放,余额、日限、校验顺序与返还口径待并行发送链修复后再联合回归。
|
||||
|
||||
## 2026-07-20 LG 缺陷修复与本地真实链路验证(未提交、未部署)
|
||||
|
||||
- 保留并识别并行会话的 CMPP 多号码 Submit、分组 Msg_Id 和 Gateway 入站差异,本轮未覆盖或重写其 Gateway 文件;既有两号码、混合非法号码及重启恢复测试随 Gateway/API 全量测试通过。
|
||||
- 回执关联改为内部消息 ID 或 `channelId + gatewayMessageId + phoneNumber` 的唯一提交记录,新增稳定 `receiptKey` 数据库唯一约束和并发冲突兜底。主记录同步保存真实通道、通道消息号、原始状态、文本和到达时间,重复 DELIVRD 不再重复客户投递。
|
||||
- 对账、应用/通道利润和质量报表统一补充失败数、退款、真实成本、利润及到达时长,并由既有 T-4 至 T-1 重算覆盖延迟回执。真实 PostgreSQL 重算样本为发送 2、成功 1、失败 1、收入 352、退款 352、成本 400、利润 -48、平均到达 5000ms;重复执行一致,临时数据已清理。
|
||||
- 用户接口增加运营端/客户端安全 DTO,移除密码散列、会话版本和认证内部字段;后端阻止自删除/自停用、最后一个平台/企业管理员删除或降权,并将 Prisma 唯一冲突映射为 409。逻辑删除后的用户名继续保留,确保历史审计关联稳定。
|
||||
- HTTP 单发改为仅凭 `mobile/content` 自动识别已审核签名、模板和变量,复用 CMPP 发送规则;修复 API 来源批次创建后按客户端来源读取导致的 404,OpenAPI 增加稳定请求 Schema 和示例。客户端发送候选默认只返回 approved 签名/模板,变量拒绝未闭合、空、中文、重复、非法或超长名称。
|
||||
- 报备资料新增官方 XLSX 模板和按筛选导出接口,导入拒绝公式及公式注入单元格;分析、提交、导出日志保存当前操作人、文件名、筛选和成功/失败数。黑名单重复唯一冲突返回 409,逻辑删除记录按既定规则恢复。
|
||||
- 本地 Redis `PING=PONG`,真实 NestJS API health 返回 ok。使用真实 PostgreSQL、Redis 与 `/api/gateway/events/receipt` 验证同一通道 Msg_Id 双通道场景:A 保持 submitted,B 正确 delivered,重复回执返回同一消息且仅一条回执记录。回执目的号码已持久化并建立三字段匹配索引;Prisma 本地 57 条 migration 已应用且 schema 最新。
|
||||
- 验证通过:API 全量 Jest 21 suites/237 tests、回执与报备材料定向 2 suites/68 tests、用户安全与报备材料定向 2 suites/17 tests、API TypeScript build、Gateway `go test ./...`、前端 TypeScript/Vite build。Jest 仍有既有异步句柄退出提示,断言全部通过;前端仍有既有大 chunk 警告。生产未写入数据、未发送短信,代码未提交、未 push、未部署,生产仍需获批发布后复测。
|
||||
- `npm run verify:phase8` 两次完整尝试都在同一个 BullMQ 15,000 条性能门槛停止,分别为 375.00 TPS 和 404.53 TPS,未达到 500 TPS;同一脚本隔离复测为 907.93 TPS 并通过。因此功能与契约断言未失败,但完整阶段命令受本机共享 Redis/瞬时负载影响,按“环境性能不稳定”记录,不能标记为完整通过。
|
||||
- Browser 插件已打开真实本地运营端,登录页、验证码和前端到 NestJS API 代理正常;登录后报表页面验收受图形验证码安全约束阻塞,本轮未代解或绕过验证码,不能标记为页面通过。本地临时管理员、角色及关联数据已清理,临时 API/前端进程已关闭。
|
||||
- 另通过真实本地登录 API、HttpOnly 会话、PostgreSQL 与 NestJS 路由完成后端验收:`GET /admin/users` 找到临时用户且 `passwordHash/sessionVersion/failedLoginCount` 泄漏字段为空;当前用户自删返回 403;官方签名资料模板下载返回 200、XLSX 6952 字节;利润查询返回真实聚合行。数据库 `OperationLog` 记录 `report_material.template_downloaded`、正确操作人、文件名、成功数和非空 IP;所有临时用户、角色、关联和日志随后已清理。
|
||||
|
||||
## 2026-07-20 平台LG二轮UI/UX阶段A启动与LG2-P0-01修复(未提交、未部署)
|
||||
|
||||
- 已完整读取二轮最终报告、执行进度、基线、页面矩阵、设计规范、可访问性、五视口、性能稳定性、高风险、会话导航、角色边界,以及阶段A相关客户端组件/核心流程、运营核心流程、表单、列表和弹窗专项报告;查看了375/390手机阻断截图与1280桌面列宽截图。在测试文档目录建立45项唯一问题整改台账和阶段A源码/测试/风险映射。
|
||||
- 根因确认:公共Table在`≤780px`已经转为卡片,但客户端用户页四个动作继续使用不可换行`.inline-actions`,父卡片`overflow:hidden`把末尾删除裁掉。修复仅修改`ClientUsersPage.tsx`并新增页面专用CSS;手机/平板操作区变为2×2网格、按钮高度44px,未修改已有并发变更的公共`global.css`或用户后端。
|
||||
- 真实本地链路验收:启动NestJS、Vite preview、PostgreSQL和Redis,创建唯一临时租户/企业管理员,经真实验证码、登录会话、`/api/client/users`读取数据。375视口点击删除只打开含目标用户名的确认层并取消,记录未删除;随后退出并精确清理临时租户、用户、角色关联和操作日志,复核`cleaned=true`。未发送短信、未充值、未修改生产数据。
|
||||
- 五视口Browser验收:375×667、390×844和768×1024四项操作全部可见、中心可命中、高度44px且页面无横向溢出;1440×900全部首屏可见;1366×768保留既有55px表格内部横向滚动,滚动后删除完整可达,该桌面列宽问题继续归入LG2-P1-03/P2-04。控制台`error/warn=0`。截图保存在测试项目`平台LG_UIUX二轮走查证据/整改_20260720_LG2-P0-01/`。
|
||||
- 自动化:API用户服务1 suite/11 tests、API TypeScript build、前端TypeScript/Vite build、Prisma validate/migrate status、Redis PONG和`git diff --check`通过;本地共有56条migration且schema最新。项目当前没有前端lint或组件测试脚本,未虚报通过。首次前端build被另一会话新增`includeHistory:boolean`查询类型拦截,已在`adminApi.ts`做字符串序列化的最小兼容,不改变业务语义。
|
||||
- `LG2-P0-01`在整改台账标记“已通过”;代码未提交、未推送、未部署,生产仍运行旧版本,生产P0尚未发布。
|
||||
|
||||
Reference in New Issue
Block a user