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

70 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 支付配置动态加载能力规范
## 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_id``amount`
- **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_id``enterprise_id`)与当前登录用户是否匹配
- **THEN** 若当前用户无权访问该配置,返回 `{code: 403, msg: "无权限访问该支付配置"}`
#### Scenario: 平台用户无限制访问
- **WHEN** 平台管理员的操作需要加载任意支付配置
- **THEN** 系统跳过归属权限检查,允许访问所有配置(仅限用户操作场景)