D03 订购与支付域 · 设计文档

本域总览见《账号计费中心 · 结构大纲》。全文分六段:定位与边界 / 角色与依赖 / 数据模型 / 核心流程 / 接口契约 / 关键约束与验收标准。


1. 定位与边界

定位:把「用户想买的东西」变成「账上可用的钱」。本域回答买什么、多少钱(商品与价目)、怎么付(渠道与下单)、钱何时算到账(回调、人工确认、关单与查单自愈),并承载订阅套餐账本与密钥台账。

核心概念

概念 口径
商品 kind 只取 recharge;商品行不承载售价,只有规格(meta)与可见性(status 取 listed / unlisted)。
售价版本 product_prices 的有效区间快照:当前价 = 区间未闭合那条;调价 = 关旧价 + 落新价。
价目规则版本 price_rules 按整版本发布,供计量方读单价;本域不二次核算扣费。
订单 购买意图事实行,幂等键 = order_no;下单定格商品与渠道快照,调价下架不回改历史单。
支付渠道 pay_channel_configs:四道闸门齐备且灰度放行才对客户可见;模式取 mock / sandbox / production / manual。
账户访问密钥 account_api_keys:明文仅创建时返回一次,库存哈希,消耗归因落到组。
订阅套餐账本 每客户每商品至多一个在营订阅;周期额度以新发额度包承载,到期即过期,等同于额度重置。

边界

关键口径

  1. 金额:元、6 位小数、字符串传输;目录定价以分存放,下单时换算为元。渠道收银台按 2 位小数比对,故下单与退款定额都要求等效 2 位小数,有效 3 位以上一律拒绝。
  2. 幂等两层:订单级 order_no(全局唯一)与下单意图级 client_request_id(同客户唯一,重复提交返回原单)。
  3. 「已入账」唯一判据:流水中 ref_order 等于订单号且类型为 recharge 的那行;赠金等类型同键不阻断入账。
  4. 在营态唯一:订阅按客户 × 商品在营唯一;渠道配置按渠道 × 模式唯一、按渠道至多一行启用。

2. 角色与依赖

参与角色:客户(门户下单人,订单与密钥归属工作区、操作人为成员本人)、组织 Owner / Admin(可处置全组织密钥行)、组管理员(密钥可见范围收窄到其管理的组与本人名下)、运营(带运营令牌与操作人标识)、在册平台员工(灰度判据,非权限体系)、数据面网关(以明文密钥现取校验台账)、计量方(读价目规则版本)、渠道(外部支付网关与对公资金账户)。

能力矩阵(组织角色与组内角色相互独立)

操作 Owner / 组织 Admin 组管理员 普通成员 运营
创建密钥(归属本人) ✓ 可指定本工作区任意启用组 ✓ 限本人所在组 ✓ 限所在组或默认组 ✗
改 / 停用 / 启用 / 软删密钥 ✓ 全工作区任意行 仅本人名下 仅本人名下 ✗
商品与价目维护 ✗ ✗ ✗ ✓
渠道配置、探活与灰度放行 ✗ ✗ ✗ ✓
对公人工确认 / 强制查单 ✗ ✗ ✗ ✓ 须在册且具出款范围

上游依赖

上游 依赖内容
账号与身份域 门户令牌解析出的用户;协议同意版本(下单出口按当前版本比对)
租户与组织域 工作区、成员与角色、组(含默认组)、组启停状态
钱包与账务域 入账原语(充值 → 现金余额)、流水幂等键、余额位数与欠费重算
运营管理域 平台员工在册事实与运营面配置权限范围

下游被引用

引用方 引用内容 语义
计量与计费域 price_rules 版本快照 按 model_glob 匹配,重叠取 priority 高者;无匹配即未定价
钱包与账务域 订单与 order_no 入账幂等键(ref_order)与流水归属
退款与对账域 订单状态机与渠道列 退款只接受已支付订单;对账按订单渠道过滤
数据面网关 密钥现取校验 明文现取 → 台账(归属组与工作区、状态、额度、过期)
风控与合规域 密钥台账只读视图 封禁 / 解封 / 停用 / 启用(详见 D09)

3. 数据模型

3.1 域内关联总览

售价版本区间订单定格商品快照下单客户在营订阅每周期新发额度包密钥归属工作区消耗归因落组密钥归属成员

products

uuid

id

PK

string

code

目录唯一标识

string

kind

取值 recharge

string

status

listed / unlisted

jsonb

meta

面额等规格

product_prices

uuid

id

PK

uuid

product_id

FK

bigint

price_cents

售价,分

timestamp

effective_from

timestamp

effective_to

未闭合即当前价

customer_orders

uuid

id

PK

uuid

customer_id

FK

string

order_no

业务幂等键,唯一

string

client_request_id

意图幂等键

string

product_code

商品快照

string

channel

string

status

九态状态机

numeric

amount

元,6 位小数

timestamp

expires_at

支付超时关单时点

customers

customer_subscriptions

uuid

id

PK

uuid

customer_id

FK

string

product_code

int

cycle_days

周期天数快照

bigint

quota_tokens

每周期发放额度

string

status

active / cancelled

timestamp

current_cycle_end

到期即额度重置

customer_grants

organizations

account_api_keys

uuid

id

PK

uuid

organization_id

FK

uuid

user_id

FK

uuid

group_id

FK

bigint

key_hash

库存哈希

jsonb

quotas

多周期额度

jsonb

ip_allowlist

来源白名单

timestamp

expires_at

临时密钥过期

timestamp

deleted_at

软删保流水追溯

groups

users

price_rules

uuid

id

PK

int

version

整版本号,只增

string

model_glob

通配匹配模式

bigint

unit_price_cents_per_1k_tokens

int

priority

重叠取高者

pay_channel_configs

uuid

id

PK

string

channel

string

mode

mock / sandbox / production / manual

boolean

is_active

人工开关

string

rollout_stage

internal / public

timestamp

probe_ok_at

调测证据

text

credentials_encrypted

凭据整体加密

图 1

customers / organizations / groups / users 由他域持有,本域只以归属列引用;订阅周期额度经额度账本的归属列关联(额度账本属钱包与账务域,本域只写归属、不持余额)。

3.2 域间引用

customer_orders
订单事实

钱包与账务域
入账原语与流水

退款与对账域
退款对象与对账

customer_subscriptions
订阅套餐账本

price_rules
计价规则版本

计量与计费域
单价参考

product_prices
售价版本

公开目录
当前价投影

pay_channel_configs
渠道配置

渠道侧
凭据与探活对端

account_api_keys
账户访问密钥

数据面网关
明文现取校验

风控与合规域
封禁与解封处置

图 2

3.3 表清单(7 表)

表 职责 关键字段
products 商品定义:仅现金充值面额,只控可见性 code / kind / name / meta / status
product_prices 售价版本的有效区间快照 product_id / price_cents / effective_from / effective_to
price_rules 计价规则整版本(单价参考) version / effective_from / model_glob / unit_price_cents_per_1k_tokens / tier / priority
customer_orders 订购订单事实,order_no 为业务幂等键 customer_id / order_no / client_request_id / product_code / amount / channel / status / channel_trade_no / channel_raw / meta / paid_at / expires_at / order_poll_attempt_at / order_last_polled_at
customer_subscriptions 订阅套餐账本:每客户每商品一个在营订阅 customer_id / product_code / cycle_days / quota_tokens / price_cents / status / current_cycle_start / current_cycle_end / cancel_reason
pay_channel_configs 渠道配置:每渠道每模式一行、每渠道至多一行启用 channel / is_active / mode / rollout_stage / probe_ok_at / last_probe_error / credentials_encrypted / gateway_url / notify_url / return_url / bank_account_name / bank_account_no / bank_name
account_api_keys 账户访问密钥台账(明文仅创建时一次) organization_id / user_id / group_id / name / key_prefix / key_hash / quotas / ip_allowlist / expires_at / status / deleted_at

3.4 设计约束

  1. 商品与售价分离:商品 code 唯一、kind 只取 recharge;售价只在 product_prices 上版本化。
  2. 售价区间快照:当前价恒为 effective_to 为空那条;调价先关旧价再落新价,新价生效时点不得早于当前价生效时点(不得抹掉价格历史)。
  3. 价目版本只增:按整版本发布、版本号自增、不提供单行改写。
  4. 订单双重唯一:order_no 全局唯一;(客户, client_request_id) 唯一(部分索引,空值互不相等,未携带该键的下单不受约束)。
  5. 订单状态集合固定:pending / paid / failed / cancelled / refunding / refund_processing / refunded / refund_failed / refund_unknown;expires_at 非空,金额为元 6 位小数。
  6. 订阅在营唯一:(客户, 商品) 至多一行在营订阅(部分唯一索引)。
  7. 渠道配置双唯一:(渠道, 模式) 唯一;每渠道至多一行启用(部分唯一索引,不同渠道可同时启用)。
  8. 凭据整体加密:凭据序列化后整体加密落单列,加密密钥经环境注入;对公收款账户面向付款用户公开,明文落库。
  9. 密钥不可逆取回:key_hash 唯一、明文不落库;软删(deleted_at 非空即视为不存在)保流水追溯。
  10. 密钥额度多周期:quotas 承载 day / week / month / total,缺省即不限;单值上界与请求口径同源(QUOTA_VALUE_MAX)。
  11. 来源白名单有上限:逐项须为地址或网段,去重保序,上限 20 条。

4. 核心流程

4.1 下单:意图幂等、撞号重试与快照定格

两者皆缺金额越界非等效 2 位通过否是未注册已知但不可用通过是且已有同键订单否 或 无同键订单撞意图幂等键撞订单号未用尽已用尽无冲突

下单请求(目录商品 或 自定义金额)

商品与金额互斥校验

422 product_or_amount_required

422 amount_out_of_range

422 amount_precision

协议版本是否为当前版本

403 terms_not_agreed

渠道可否下单(四道闸门)

400 unsupported_channel

403 channel_not_available

是否携带意图幂等键

重放:返回原单 + 重新生成收银台参数

定格商品与渠道快照,建待支付订单

落库是否撞唯一约束

回滚后取回先提交者订单,按重放返回

重试是否用尽

抛出原始冲突,交监控人工介入

生成支付参数,写下单审计

图 3

4.2 渠道支付回调:验签优先与幂等入账

钱包锁域订单与入账订购接口渠道钱包锁域订单与入账订购接口渠道alt[报文形态非法][无订单号][未知订单号]alt[订单已支付][订单非待支付][金额不一致][待支付]alt[验签失败][通过但未构成支付成功][通过但渠道不一致][通过且构成支付成功]支付结果通知取原始报文(预验签钩子先于订单定位)解析订单号422 invalid_callback_body(落拒绝审计)400 invalid_callback(落拒绝审计)以占位订单走完验签,不做差异化应答400 callback_signature_invalid验签(各渠道自有算法)400 callback_signature_invalid固定应答体,不入账409 channel_mismatch确认收款行锁 + 咨询锁串行化幂等返回,不重复入账409 order_not_payable400 amount_mismatch,不入账入账:余额原子自增 + 落充值流水(订单号为幂等键)订单置已支付,落渠道交易号与原始回执固定应答体
图 4

4.3 订单超时自动关单

否是

进程内周期扫描(间隔可配,0 即关闭自动扫描)

取已过期仍待支付的订单,逐行加锁

手动触发通道(部署侧定时或人工)

订单是否仍为待支付

跳过,不改状态

置已取消 + 落关单审计

提交并返回本次关单笔数

图 5

4.4 主动查单自愈与已关单复活

订单收敛渠道查单扫描订单收敛渠道查单扫描alt[渠道报支付成功且本地待支付][渠道报支付成功但本地已关单][渠道报已关闭且未收款][仍待支付 或 未找到]alt[距首次查单已达上限][未到点][到点]取候选:待支付 + 已关单但曾查过(仅网关型渠道)账龄与退避到点判定告警转人工,不再查跳过,下一轮再判查单(不持锁做网络调用)按确认收款入账(幂等)复活入账(仅查单路径可调)金额须与订单一致,否则告警并保持关单条件关单(仅当仍待支付)落查单回执 + 刷新退避锚点
图 6

4.5 对公转账人工确认

否是否是否是否是否是

运营发起对公确认

是否携带运营令牌

拒绝

操作人是否为在册平台员工且具出款范围

403 operator_forbidden

订单渠道是否为人工确认型

400 channel_not_confirmable

实收金额是否提供

422 amount_required

实收金额是否等于订单金额

400 amount_mismatch

按确认收款入账,审计动作与回调入账可辨

图 7

4.6 支付渠道生命周期:四道闸门与灰度

否是需要且未通过探活通过不需要启用:默认落灰度放行对外回退灰度停用

建配置行:草稿

凭据是否就绪

是否需要探活

待调测

可启用

灰度:仅在册平台员工可见

对外可见

图 8

4.7 渠道凭据托管与探活证据

是否是否成功失败

写入或编辑渠道配置

凭据字段是否有值

按渠道字段表摘出凭据,整体加密落单列

保留原凭据(留空即不修改)

是否触及探活相关字段

作废调测证据(探活通过时点清空)

保留调测证据

响应白名单:密钥类只回是否已配置布尔,标识类明文回传

探活调用

记探活通过时点 + 审计成功

保留原探活时点,只记最近一次错误与失败时间

图 9

4.8 售价版本与计价规则版本发布

新价生效时点早于当前价生效时点通过

新建商品(含初始当前价)

当前价区间未闭合

调价请求

422 拒绝:不得抹掉价格历史

关闭当前价:写入区间终点

落新价:区间起点 = 新价生效时点

发布计价规则

版本号 = 最大版本 + 1

同版本一次落全部规则行(匹配模式 / 单价 / 套餐级覆盖 / 优先级)

计量方按版本读快照,消耗时点定格

图 10

4.9 账户访问密钥生命周期与联动失效

未指定指定否是否是停用启用软删成员被移出工作区组被停用

创建密钥(任何成员可为本人创建)

是否指定组

落到工作区默认组

组属本工作区且启用

400 拒绝

调用者是否在本组内(组织 Owner / Admin 放行)

403 not_in_group

返回明文一次 + 展示前缀;库存哈希

后续动作

状态置停用(可逆)

标记删除时点并置停用:台账不再展示,流水仍可追溯

名下工作区内启用的密钥一并停用

组下启用的密钥一并停用(组恢复不自动恢复密钥)

图 11

4.10 订阅套餐账本与周期滚动

无有续费取消

下单入账(订阅商品)

该客户该商品是否已有在营订阅

开新订阅行:周期起止 + 每周期额度 + 当期价格快照

原行滚动周期:新周期起止 + 新发额度包

本周期额度包:到期时点 = 本周期结束

到期自然过期即额度重置(无独立重置任务)

是否续费

在营态收敛:本周期额度用到期,重新订阅时开新行

图 12

5. 接口契约

5.1 门户目录与渠道(/api/account)

方法 路径 语义
GET /api/account/products 公开目录:仅已上架商品,可按类型过滤
GET /api/account/products/{code} 商品详情:未上架与不存在一律 404
GET /api/account/price-rules 计费公示:仅当前有效版本;未发布返回空
GET /api/account/pay-channels 当前用户可见渠道(含对公收款账户明文)

5.2 门户订购(/api/account)

方法 路径 语义
POST /api/account/orders 下单 → 待支付订单 + 支付参数;带意图幂等键时重复提交返回原单
GET /api/account/orders 我的订单(时间倒序,最多 50 条)
GET /api/account/orders/{order_no} 订单详情(字段白名单,不透渠道原始回执)
POST /api/account/orders/{order_no}/refund-apply 申请退款(审批与出款详见 D07)
POST /api/account/payments/callback/{channel} 渠道支付回调:验签优先 → 订单定位 → 渠道一致性 → 金额一致性 → 幂等入账

5.3 内部商品与定价(/internal)

方法 路径 语义
POST /internal/products 新建商品 + 初始当前价(充值面额须等于售价)
PUT /internal/products/{code} 改规格与上架状态(编码与类型不可改)
POST /internal/products/{code}/prices 新价格版本:关旧价区间 + 落新价
POST /internal/price-rules 发布计价规则整版本
GET /internal/products 管理列表(含未上架):当前价
GET /internal/products/{code}/prices 价格历史(区间回查)
GET /internal/price-rules 计价规则版本快照(可按版本号读)

5.4 内部支付渠道(前缀 /internal/pay,下表为前缀内相对路径)

方法 路径 语义
GET /status 当前生效支付模式与来源(配置行优先,部署配置兜底)
GET /channels 配置列表(启用行在前;密钥类只回是否已配置)
POST /channels 新建配置(不自动启用;同渠道同模式只能一条)
PATCH /channels/{config_id} 部分更新:凭据留空不改;触及探活相关字段即作废调测证据
POST /channels/{config_id}/activate 启用(同事务清零同渠道其他行;默认落灰度)
POST /channels/{config_id}/rollout 灰度与对外切换
POST /channels/{config_id}/deactivate 停用(幂等)
DELETE /channels/{config_id} 删除配置(启用行拒绝,须先停用)
POST /channels/{config_id}/probe 探活:只读查询验签,落库为调测证据

5.5 内部订单(/internal)

方法 路径 语义
POST /internal/orders/{order_no}/confirm 对公人工确认 → 已支付 + 入账
POST /internal/orders/expire 超时关单(幂等,可重复触发)
POST /internal/orders/poll 主动查单(幂等、自愈、多副本安全)
GET /internal/orders 运营订单列表(可按状态筛选,含工作区名)
GET /internal/orders/{order_no} 订单详情(含渠道原始回执)

5.6 内部密钥现取校验(/internal)

方法 路径 语义
POST /internal/api-keys/lookup 哈希命中且未软删 → 台账(归属组与工作区、状态、额度、过期),不返回明文

5.7 运营面(/api/account/ops)

方法 路径 语义
GET /api/account/ops/payments/status 生效支付模式与来源
GET /api/account/ops/payments/channels 渠道配置列表
POST /api/account/ops/payments/channels 新建配置
PATCH /api/account/ops/payments/channels/{config_id} 编辑配置(凭据留空不改)
POST /api/account/ops/payments/channels/{config_id}/activate 启用渠道
POST /api/account/ops/payments/channels/{config_id}/rollout 灰度与对外切换
POST /api/account/ops/payments/channels/{config_id}/deactivate 停用渠道
POST /api/account/ops/payments/channels/{config_id}/probe 渠道探活
DELETE /api/account/ops/payments/channels/{config_id} 删除渠道配置
GET /api/account/ops/orders 运营订单列表
GET /api/account/ops/orders/{order_no} 运营订单详情
POST /api/account/ops/orders/{order_no}/confirm 对公人工确认(运营令牌路径)
POST /api/account/ops/orders/{order_no}/query 单笔强制查单(跳过退避)
POST /api/account/ops/orders/poll 整轮主动查单
GET /api/account/ops/orders/refunds/offline-pending 待线下打款核对清单(详见 D07)
GET /api/account/ops/orders/{order_no}/refund-risk 退款审批画像(详见 D07 与 D09)

6. 关键约束与验收标准

6.1 约束

  1. 单一幂等键入账:入账以 order_no 为幂等键、以 recharge 类型流水为唯一判据;重复回调、重复确认、查单收敛三源并发时净效果为恰好一次入账。
  2. 验签优先且不泄露存在性:回调在任何基于订单号的差异化应答之前完成验签;未知订单号与验签失败同姿态;渠道一致性校验置于验签之后。
  3. 非法迁移一律拒绝:只有待支付订单可转为已支付;已支付重复确认按幂等返回;其他状态一律拒绝,不产生状态回退。
  4. 金额一致性硬门禁:回调与人工确认的金额必须与订单金额一致,不一致即拒绝且不入账;2 位小数口径由下单门的精度校验前置保证。
  5. 关单与入账互斥:关单只在订单仍为待支付时生效,条件更新在单条语句内完成判定与写入,绝不覆盖在途入账结果。
  6. 复活路径唯一:只有主动查单可复活已关单订单,且金额必须一致;回调路径不放开。
  7. 渠道四闸门:凭据就绪、调测完成、人工开关、灰度放行四者齐备才可见可下单;启用与对外是两次动作;派生状态不作判定。
  8. 凭据单向可写:凭据整体加密落单列,读取只有一个入口,解密失败按未就绪处理;响应只出标识类字段与「是否已配置」布尔,密钥类明文永不回传。
  9. 探活证据随配置失效:触及探活相关字段即作废调测证据;探活失败不清空既有通过时点但必须留痕。
  10. 密钥零明文与可逆停用:明文只在创建响应出现一次,库存哈希;停用与启用可逆;软删保留追溯;成员移出与组停用触发名下令牌一并停用,组恢复不自动恢复密钥。
  11. 运营动作实人可追:入账与出款类动作必须带在册且有出款范围的操作人;申请与驳回类动作虽不设实人门禁,但操作人缺失必须显式落审计标记。
  12. 价目只增不改:售价按区间追加、计价规则按整版本追加;任何路径都不得抹掉价格历史或改写已发布版本。

6.2 验收标准

# 验收口径
1 同一意图幂等键重复下单返回同一订单号,不产生新订单与新流水;并发同键提交仅落一行
2 不带意图幂等键的下单撞订单号时自动重试,多次撞号后仍失败才抛冲突,不出现以撞号为由的 500
3 同一订单重复回调仅首次入账,其后幂等返回当前余额;余额取已提交真值,并发双充值下响应余额含本笔
4 回调金额与订单金额不一致 → 拒绝且余额不变;对公确认实收金额不一致 → 拒绝且余额不变
5 未知订单号的回调与签名错误的回调应答姿态一致;渠道不一致的回调被明确拒绝
6 已支付订单再收回调 → 幂等返回;已取消订单收回调 → 拒绝(不复活),由查单路径处置
7 超时关单只改写已过期的待支付订单;关单后渠道确认收款的订单可被复活入账,金额不一致时保持关单并告警
8 关单扫描多副本并发不产生重复关单审计;关闭自动扫描后手动触发仍可用
9 渠道未启用 / 凭据不全 / 未探活 / 灰度未放行时,既不出现在门户列表也不可下单(同一份判定)
10 启用渠道默认落灰度:非在册员工看不到;放行对外后普通用户可见;回退灰度后立即不可见
11 同渠道启用新行时旧行自动停用;不同渠道可同时启用;启用行删除被拒绝
12 修改密钥类凭据后调测证据被作废,渠道回到待调测态,无法直接放行对外
13 渠道配置响应中密钥类字段只出现「是否已配置」布尔,不出现明文;对公收款账户为明文
14 密钥创建响应含明文一次,此后任何查询都不返回明文;软删后现取校验返回未找到,流水仍可追溯
15 密钥额度按多周期生效,缺省即不限;来源白名单超过 20 条或含非法项 → 拒绝
16 成员移出工作区后其名下工作区内启用的密钥全部停用;组停用后组下启用的密钥全部停用,组恢复后密钥仍为停用
17 调价后新下单按下单时当前价定格;历史价格可按区间回查;新价生效时点早于当前价生效时点被拒绝
18 计价规则按整版本发布,同版本重叠命中取优先级高者;未发布时公开公示返回空
19 同客户同商品的并发订阅开通至多一行在营订阅;取消后可重新订阅开新行
20 运营令牌缺失或操作人非在册平台员工时对公确认被拒;非人工确认型渠道被拒;实收金额缺失被拒

6.3 待后续设计细化的开放项

  1. 订阅的开通与续费入口编排:周期滚动、取消与重新订阅的行级约束已定,门户侧入口与文案编排待与其他页面统一。
  2. 渠道对账的订单侧视图:本域只出订单与渠道配置,账单比对在退款与对账域;跨域差异处置口径需两侧联合定稿。
  3. 密钥额度在执行侧的落点:额度字段与口径在本域,扣减时的额度判定归属待与计量与计费域对齐(当前扣费只按金额扣钱包)。
  4. 计价规则的套餐级覆盖:字段已就位,套餐级单价的生效范围与切换时机待与计量与计费域共同细化。
  5. 渠道凭据轮换:密钥经环境注入、凭据整体加密;轮换期双写与历史密文重加密策略待定。