Files
junhong_cmp_fiber/openspec/changes/add-payment-merchant-pools/design.md
break 370fd3e67f
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 10m49s
update
2026-09-03 09:28:28 +08:00

5.7 KiB
Raw Blame History

Context

现有 tb_wechat_config 同时承担支付渠道配置;订单、充值和 tb_payment 通过 payment_config_id 供回调加载创建时配置。tb_payment 已有非敏感 merchant_identity 快照,但不足以区分商户池、服务商和完整路由。新模型必须让新单和旧单分流,不能把历史订单指向迁移后新商户。

Decisions

独立实体与不可变路由快照

新增商户、商户池、池成员、微信授权配置及金额/笔数统计事实;支付单扩展实际商户和商户池 ID 及非敏感快照。商户凭证只留在商户表受控字段,支付单/审计不复制。被引用后锁定商户支付方式、服务商与身份,避免历史验签与退款语义漂移。

路由和统计在支付创建/成功边界闭合

支付创建在事务内读取唯一启用池、按方式选择成员并冻结路由;无成员/池失败即返回。金额/笔数统计只在现有“支付成功首次生效”路径按实际商户条件递增,以支付 ID 唯一约束避免重复回调累计;不在预下单预占。时间方式由当前时间和受控起点计算,不写逐次路由日志。

新旧配置双读切换

新支付单具有 merchant ID 时支付加载、回调验签、查询和退款均从商户加载服务商凭证merchant ID 为空的历史单保持现有 payment_config_id 路径。迁移先复制生效配置中完整凭证,再发布新支付路径;不可将现有记录批量回填为新商户,因为其实际历史身份无法保证一致。

敏感配置边界

后台管理响应按 PRD 向两类已认证管理角色完整返回凭证;所有 logger、错误、审计 payload、支付单快照和导出只允许写 ID、名称和脱敏/非敏感身份。更新凭证后使现有配置加载缓存失效;历史回调读取最新有效凭证以支持轮换。

管理与支付动作契约

以下路径为本 Change 新增后台管理契约;所有管理写操作仅限超级管理员和平台用户,金额均为分,敏感凭证只在已认证管理请求的写入/详情响应中传输,绝不进入支付快照、审计、日志或导出。

商户

  • POST /payment-merchants:请求 namepayment_methodwechat/alipay)、provider_typemerchant_identitycredentialsenabledremark。同一支付方式下身份标识不得重复;凭证缺失或与服务商类型不匹配时拒绝。
  • PUT /payment-merchants/:id:未被任何支付单引用时可修改全部字段;被引用后仅可改名称、凭证、启停、备注,修改支付方式、服务商类型或商户身份返回“已被支付单引用,不能修改收款身份”。
  • DELETE /payment-merchants/:id:被引用或仍属于任一商户池时拒绝;删除前必须显式二次确认。停用不影响已冻结该商户的查单、验签和退款。

商户池

  • POST /payment-merchant-pools:请求 namepayment_methodenabledstrategy(金额/笔数/时间)、策略参数和有序 member_ids。成员均须存在、启用、与池支付方式一致且不重复;同一支付方式最多一个启用池,冲突返回“该支付方式已有启用商户池”。
  • PUT /payment-merchant-pools/:id:修改阈值只保留当前统计;修改金额/笔数统计周期、时间周期、起始时间或每轮成员排序时开启新统计周期;自然周期仅调整排序时保留未移除成员累计。成员移除后不再选择,但历史支付快照不改写。
  • POST /payment-merchant-pools/:id/enable/disable:启用时再次校验唯一启用池和可用成员;停用后新支付创建明确失败,不回退综合支付配置。

微信授权配置

  • GET /wechat-authorizations:最多返回一个启用配置;仅管理角色可读取。PUT /wechat-authorizations/current 创建或更新唯一配置,写入公众号 H5/JSSDK、小程序登录及支付 AppID 所需字段。
  • 启用第二个配置返回“平台已有启用微信授权配置”;停用后 C 端微信登录/OpenID/微信支付 AppID 不得静默回退其他支付商户或旧配置。

新旧支付分流

  • C 端套餐订单、资产钱包充值、代理在线预存款创建支付时,在同一事务内读取对应支付方式唯一启用池并冻结 merchant_idmerchant_pool_id、非敏感收款身份与轮询快照;无可用成员返回“暂无可用商户”。
  • merchant_id 非空的支付,在回调、查单、退款时加载该商户当前凭证;为空的历史支付仅按既有 payment_config_id 处理。不得按当前启用池为历史单推断商户。
  • 首次支付成功消费者以支付 ID 唯一记账金额/笔数统计;重复回调不重复累计。预下单、失败、关闭和退款均不变更统计。

Risks / Trade-offs

  • 并发成功回调超过阈值:这是“只统计成功、不预占”的明确结果,下一次选路才跳过。
  • 商户停用后的退款:停用不阻断历史退款,实际调用仍由凭证/渠道结果决定。
  • 迁移缺失凭证:不造空商户池,受影响新支付明确失败。
  • 旧回调误入新路径:以支付单 merchant ID 为唯一分流条件,严禁按当前启用池推断。

Migration Plan

  1. 新增成对迁移创建商户/池/成员/微信授权表、唯一启用约束、支付单路由列和成功统计索引。
  2. 在迁移事务中从唯一生效综合配置复制完整凭证并创建单成员池;全过程禁止日志输出密钥/证书。
  3. 隔离库验证微信直连、富友、支付宝、空配置、停用历史商户、回调兼容、三种轮询及 up/down/up。
  4. 回滚前停止新支付创建;有新路由单时仅回退应用流量,不执行会破坏新支付事实的 down。