Files
junhong_cmp_fiber/openspec/specs/payment-dynamic-config/spec.md
huang d9de704d73
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 49s
归档
2026-04-14 12:14:29 +08:00

3.6 KiB
Raw Blame History

支付配置动态加载能力规范

ADDED Requirements

Requirement: 从支付配置 ID 动态加载支付实例

系统在处理支付验签(订单支付回调、充值确认等)时,应根据订单/充值记录中的 payment_config_id 字段动态加载对应的支付配置,而不是使用全局单例 s.wechatPayment

Scenario: 订单支付回调验签

  • WHEN 微信支付回调到达 /api/callback/wechat,系统解析回调中的商户号和订单数据
  • THEN 系统根据订单表中的 payment_config_id 从 RedisTTL 1h或数据库加载对应的支付配置
  • THEN 系统使用该配置的私钥和证书验签回调数据
  • THEN 若配置不存在或当前用户无权限访问该配置,返回 {code: 1103, msg: "支付配置不存在或无权限"}

Scenario: 充值订单确认支付

  • WHEN 代理用户在充值页面点击"确认支付",提交 recharge_order_idamount
  • THEN 系统根据充值订单表中的 payment_config_id 动态加载支付配置
  • THEN 系统调用该配置对应的支付 SDK 创建预支付单(微信 JSAPI 或 H5
  • THEN 若配置无效或超配额,返回 {code: 1103, msg: "支付配置无效,请联系商户"}

Requirement: 支付配置 Redis 缓存

系统应缓存支付配置到 Redis减少数据库查询。

Scenario: 首次加载配置

  • WHEN 调用 PaymentConfigLoader.LoadConfig(ctx, configID) 且 Redis 中不存在该配置
  • THEN 系统从数据库查询配置,存入 Rediskey: payment:config:{configID}TTL: 1 小时)
  • THEN 返回加载的配置对象

Scenario: 配置缓存命中

  • WHEN 调用 PaymentConfigLoader.LoadConfig(ctx, configID) 且 Redis 中存在该配置
  • THEN 系统直接返回 Redis 中缓存的配置
  • THEN 不查询数据库

Scenario: 配置变更后清除缓存

  • WHEN 支付配置被修改(通过管理后台)
  • THEN 系统主动删除 Redis 中的该配置缓存(DEL payment:config:{configID}
  • THEN 下次加载时重新从数据库读取最新配置

Requirement: 支付配置访问控制

系统在加载支付配置时,根据调用场景采用不同的校验策略:

场景分类说明

  • 回调场景:微信支付回调到达 /api/callback/wechat,请求来自微信服务器,无登录态,无用户身份上下文
  • 用户操作场景:代理用户在前端主动发起的支付相关操作(如创建充值单、查询支付配置等),有完整的登录态和用户上下文

Scenario: 回调场景 — 商户号一致性校验

  • WHEN 微信支付回调到达,系统解析回调中的商户号(mchid
  • THEN 系统根据订单的 payment_config_id 加载配置,比较配置中存储的商户号与回调携带的商户号是否一致
  • THEN 若不一致,记录告警日志并拒绝处理,返回非 2xx 状态码(微信会重试)
  • NOTE 此场景不做用户身份鉴权,无"代理 A/B"概念,只做商户号匹配验证

Scenario: 用户操作场景 — 归属权限校验

  • WHEN 代理用户在前端主动操作(如创建充值单)需加载支付配置
  • THEN 系统检查该配置的归属(shop_identerprise_id)与当前登录用户是否匹配
  • THEN 若当前用户无权访问该配置,返回 {code: 403, msg: "无权限访问该支付配置"}

Scenario: 平台用户无限制访问

  • WHEN 平台管理员的操作需要加载任意支付配置
  • THEN 系统跳过归属权限检查,允许访问所有配置(仅限用户操作场景)