Files
one-pipe-system/openspec/changes/add-payment-merchant-pool-management/design.md
2026-09-10 16:50:06 +08:00

65 lines
4.4 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.
# 支付商户与商户池管理设计
## Context
接口文档把能力拆成支付商户、商户池和微信授权配置三部分。前端必须在同一个平台专属入口内完成管理,同时避免把商户凭证和内部路由细节带入页面状态。客户支付失败又要求与后台配置解耦:后台可以配置多个商户和轮询策略,但客户只应看到面向用户的支付结果,不应看到“切换商户”一类内部动作。
## Goals
- 通过一个后台入口管理支付商户、商户池和微信授权配置。
- 仅允许超级管理员和平台用户访问。
- 支持商户、商户池、授权配置的启停状态管理。
- 支持商户池成员拖拽排序、策略选择和阈值配置。
- 保证支付凭证只写、不回显、不持久化。
- 统一“暂无可用商户”和普通支付失败的用户提示。
## Non-Goals
- 前端不实现商户路由算法。
- 前端不保存、展示或恢复支付凭证明文。
- 不给客户支付端展示商户池内部配置。
- 不把“切换商户重试”作为用户可操作流程。
## Decisions
### 单一管理入口与三个子页签
新增 `/settings/payment-merchant-pools`,页面内使用“支付商户”“商户池”“微信授权配置”三个页签。这样与接口文档的结构一致,也便于统一权限检查和凭证清理策略。
替代方案是为三部分分别增加菜单项;该方案会让权限、路由和状态管理重复,暂不采用。
### 按 `user_type` 控制访问
现有路由守卫主要依赖角色,但需求约束是超级管理员和平台用户,因此新增显式的用户类型限制:`1``2` 可访问,`3``4` 不可访问。菜单隐藏与直接 URL 访问必须使用同一判断,避免仅做 UI 隐藏。
### 凭证只写且只存在于内存
商户 `credentials` 和微信授权敏感字段只允许在创建或显式更换时输入。读取响应不得回填这些字段;页面模型只在当前弹层或表单生命周期内保存输入值,提交、取消、关闭或卸载时清理。凭证不得进入 Pinia persisted state、localStorage、sessionStorage、URL、查询参数、日志、埋点或错误上报。
详情页不回显凭证内容,只显示“已配置/未配置”和 `credential_version`。如果后端读取接口意外返回敏感字段,前端适配层必须丢弃,而不是仅依赖模板隐藏。
### 成员数组顺序就是轮询顺序
商户池编辑使用拖拽排序。提交时直接把当前排序后的商户 ID 数组写入 `member_ids`,不新增独立的 `sort` 字段,也不在前端重新排序。成员选择默认限制为与商户池 `payment_method` 相同的商户,并禁止重复 ID。
### 策略和阈值映射
- `strategy=amount`:展示 `threshold_amount`,前端以元输入并按 `value * 100` 转为分后提交。
- `strategy=count`:展示 `threshold_count`,只接受正整数。
- `strategy=time`:展示 `time_period_unit``time_period_value`,并按需提交 `time_period_started_at`
- `statistic_cycle`:支持 `round``day``month`;只在接口允许的金额或笔数策略下提交有效值。
- `routing_epoch`:仅展示后端返回的当前路由统计世代,前端不编辑。
### 无可用商户使用稳定错误码
接口简版没有给出支付失败错误码,实施前必须与后端确认稳定的机器可读值。前端只按错误码映射,不按 `msg` 文本判断。无论后端使用何种最终编码,命中该语义时客户界面都只显示“暂无可用商户”。
普通支付失败统一使用“支付失败,请重新发起支付”。前端不自动切换商户,也不重放同一支付请求;用户再次操作时按支付接口的新请求语义重新发起。
## Risks and Trade-offs
- 接口文档未定义 `credentials` 的字段结构。实现时需要后端补充各 `provider_type` 的写入 schema或继续保持单个只写对象但不得把结构暴露为可回显配置。
- 若后端读取接口未脱敏,前端仍然能够防御性丢弃,但服务端响应、网关日志和网络抓包仍可能泄露凭证;该风险必须由后端脱敏共同控制。
- 客户支付端若不在当前仓库,文案和错误码任务需要跨仓库联调;本提案负责固化契约,不能仅通过后台页面上线完成验收。
- 金额阈值若直接按分展示会降低可读性,因此采用元输入、分传输;需要测试防止小数点精度和空值转换错误。