积分与会员 · 账本可回溯与对账保障方案¶
IT 开发 / 运营日查用 · 2026-07-21 产品规则依据:家纺 AI 生图平台《积分与会员系统规则》v1.0(1 元 = 10 积分;三类积分;版本化价目与购时快照;追加式账本)。 现状对照:现行实现为「会员方案 → 单一
usage_quotas扣点 + 订单分佣」,见 membership-agent-sales-guide.md。本文描述目标账务架构,用于改造设计与验收,不代表已全部落地。
0. 目标一句话¶
钱怎么来、积分怎么到、怎么扣、怎么提成——每一步都有不可改写的凭证;余额可由账本重放得出;每天能对上「支付通道 / 积分总账 / 提成」三本账。
1. 与现行系统的差距(改造必知)¶
| 维度 | 现行 | 目标规则 |
|---|---|---|
| 汇率 | 隐式「买方案送配额」 | 显式 1 元 = 10 积分 |
| 积分桶 | 单一 generation 配额 |
登录 / 充值 / 赠送 三桶,消耗优先级固定 |
| 单价 | 按 task_type + 分辨率附加 | 价目表版本:1K=12、2K=18、视频=84/10s |
| 会员权益 | 方案字段即时读 | 购时权益快照;到期降级体验档 |
| 提成 | 购会员订单比例分佣 | 仅充值积分消耗 计提成 + 首两单实付提成 |
| 账本 | transaction_ledger 偏流水 |
追加式、幂等、可回放、可对账 |
改造原则:先立账本与价目版本,再迁余额;禁止直接 UPDATE 余额而不写分录。
2. 核心设计原则(必须全部满足)¶
| # | 原则 | 含义 |
|---|---|---|
| P1 | 追加式账本(Append-only) | 余额变动只 INSERT 分录;禁止改历史行;纠错用冲正分录(reversal) |
| P2 | 余额可派生 | balance = Σ(entries)(或按桶聚合);库内余额字段仅为物化缓存,对账以账本为准 |
| P3 | 价目版本化 | 单价、套餐权益、赠送比例存在 price_catalog_version;改价只发新版本,旧单仍按旧版 |
| P4 | 购时权益快照 | 支付成功瞬间固化 entitlement_snapshot;运行期权益读快照,不读「当前价目最新版」 |
| P5 | 业务幂等 | 支付回调、扣点、签到、提成计提均带 idempotency_key;重复请求返回同一结果 |
| P6 | 双凭证 | 人民币侧有 payment_records;积分侧有 point_ledger;提成有 commission_ledger;三者可交叉引用 |
| P7 | 日切与冻结 | 自然日(建议业务时区 Asia/Shanghai)切日后只允许当日及未结账期间的业务;已日结批次只读 |
3. 版本化价目表(Price Catalog Versioning)¶
3.1 表设计建议¶
price_catalog_versions
id / version_code (如 2026.07.21.1) / status(draft|active|retired)
effective_from / effective_to / published_at / published_by
note
price_catalog_items # 某一版本下的计价项
version_id / item_key (image_1k|image_2k|video_10s|…)
unit / points_cost / amount_cny_display
cost_ref_usd / cost_ref_cny # 仅核算,不参与扣费
member_plan_versions # 会员档位版本(可与价目同版本或独立)
version_id / plan_tier (trial|basic|…)
price_cny / cycle (month|quarter|year) / cycle_days
bonus_rate / login_points_per_day
sub_accounts / concurrency / storage_gb
priority_generate / cs_level
feature_flags (JSONB: image_all, video_seed, video_story, premium_video_quota…)
first_purchase_points / cycle_login_points / cycle_total_points # 可存校验用计算结果
3.2 规则¶
- 同时仅一个
active价目版本对外售卖;draft供运营预览。 - 改价 / 改套餐 = 发布新版本,旧版本
retired,历史订单catalog_version_id不变。 - 扣费时读取:优先用「用户当前权益快照上的
catalog_version_id」;若无快照(极端兜底)禁止静默用最新价,应告警。 - 种子数据写入版本表,验收用固定
version_code,避免环境间价差。
3.3 校验公式(发布前自动跑)¶
首充到账积分 = round(价格 × 10 × (1 + 赠送%))
周期登录积分 = 登录积分/天 × 周期天数
周期总积分 = 首充 + 周期登录
发布 member_plan_versions 时 CI/Admin 校验与规则表一致,失败禁止发布。
4. 购时权益快照(Entitlement Snapshot)¶
支付成功(或 Admin 补发)时一次写入、永不改写:
user_entitlement_snapshots
id / user_id / order_id (可空=运营补发)
catalog_version_id / plan_version_id
snapshot_json # 完整权益拷贝:档位、赠送%、登录点/天、子账号、并发、存储、功能开关、客服等级…
starts_at / expires_at
status (active|superseded|expired)
created_at
运行期读法¶
| 场景 | 读什么 |
|---|---|
| 能否用种草视频 / 并发上限 / 存储 | 当前 active 快照(若过期则合成「体验档默认快照」) |
| 充值赠送比例 | 下单瞬间的快照或当时 active 价目(写进订单行) |
| 每日登录积分额度 | active 快照的 login_points_per_day |
| 扣费单价 | 快照绑定的 catalog_version_id → price_catalog_items |
升级 / 续费:旧快照 superseded,新快照 active;不修改旧快照 JSON。
到期:定时任务将快照标 expired;权益降级为系统内置体验档模板(仍建议落一条「降级虚拟快照」便于审计)。
5. 三类积分账户 + 追加式账本¶
5.1 账户桶(Point Buckets)¶
| bucket | ID | 来源 | 有效期 | 计提成 | 消耗优先级 |
|---|---|---|---|---|---|
| login | 1 | 每日签到 | 到账后 24h | ❌ | ① |
| purchase | 2 | 实付兑换 | 终生 | ✅ | ② |
| bonus | 3 | 充值/套餐附赠 | 终生 | ❌ | ③ |
物化余额(缓存):
user_point_balances
user_id
login_points / login_expire_at
purchase_points
bonus_points
version (乐观锁) / updated_at
真相源仍是账本;日对账发现不一致时以账本回放修复余额。
5.2 追加式积分账本¶
point_ledger_entries # 禁止 UPDATE/DELETE(DB 权限或触发器)
id (UUID)
entry_no (全局单调雪花/序列,便于回放排序)
user_id / master_user_id # 子账号消耗记 master
bucket (1|2|3)
direction (credit|debit)
points (正整数)
balance_after_bucket # 该桶变动后余额(便于抽查)
biz_type # login_claim|purchase_grant|bonus_grant|consume|expire|reversal|adjust…
biz_id # 关联业务主键
idempotency_key UNIQUE # 全局或 (user_id, key) 唯一
catalog_version_id # 消耗类必填
price_item_key # image_1k / image_2k / video_10s…
ref_order_id / ref_task_id / ref_payment_id
actor_type / actor_id # user|admin|system
memo / created_at
一笔业务消耗若跨桶,拆成多行分录 + 一行汇总消耗单:
point_consume_tickets
id / user_id / master_user_id
product_type (image_1k|image_2k|video)
total_points
login_used / purchase_used / bonus_used # 与规则文档一致,供提成
catalog_version_id / unit_points / quantity
task_id / idempotency_key UNIQUE
status (held|posted|reversed)
created_at / posted_at
流程建议(可审计):
请求(idempotency_key)
→ 预检余额(三桶按优先级模拟)
→ INSERT ticket(held) + 预占分录 或 行锁余额
→ 上游生图成功
→ ticket.posted + 正式 debit 分录
→ 失败则 reversal 冲正(仍追加,不删 held)
登录积分过期:定时任务扫描 login_expire_at,写 biz_type=expire 的 debit,金额=剩余 login;禁止直接把余额改 0。
5.3 人民币侧仍追加¶
orders / payment_records # 现状可保留并强化
money_ledger_entries # 可选:实付、退款、冲正同样追加式
amount_cny / direction / payment_channel / transaction_id
idempotency_key / order_id
积分发放必须挂支付成功凭证:
支付 success
→ money 入账(若有)
→ purchase_points credit = floor(实付元 × 10)
→ bonus_points credit = floor(实付元 × 10 × 赠送%) 或套餐表约定
→ 写 entitlement_snapshot
同一 payment.notify 的 idempotency_key 保证只入账一次
6. 幂等性设计¶
| 场景 | idempotency_key 建议 |
|---|---|
| 支付回调 | pay:{channel}:{transaction_id} |
| 下单 | Header Idempotency-Key 或 client_request_id(现状已有) |
| 签到领登录分 | login_claim:{user_id}:{biz_date} |
| 生图扣点 | consume:{task_id} 或 consume:{client_request_id} |
| 登录分过期 | expire_login:{user_id}:{claim_entry_id} |
| 提成计提 | comm:{consume_ticket_id}:{beneficiary_id}:{role} |
| 退款冲正 | reversal:{original_entry_id} 或 refund:{order_id} |
实现要点:
- 唯一约束在账本表;冲突则返回原结果(查询同 key)。
- 业务事务:先插幂等占位 / 账本,再改余额缓存;失败整单回滚。
- 支付通道验签 + 本地幂等,防止重放攻击导致双倍加点。
7. 账本回放(Replay)¶
7.1 用途¶
- 余额修复、迁移校验、纠纷举证、灾备演练。
7.2 算法¶
输入: user_id, [from_entry_no, to_entry_no]
初始化三桶 = 0(或从某 checkpoint 快照)
按 entry_no ASC 回放 credit/debit
输出: 三桶余额 + 与 user_point_balances 差异
7.3 Checkpoint(加速日查)¶
point_balance_checkpoints
user_id / as_of_entry_no / as_of_time
login / purchase / bonus
checksum
每日日切后对活跃用户写 checkpoint;回放从最近 checkpoint 开始。
7.4 只读 API / Admin¶
POST /admin/ledger/replay:指定用户回放并返回差异。- 禁止生产环境「静默改余额」;修复必须出 adjust 分录(双人审批)。
8. 三方对账(Reconciliation)¶
每日(建议 T+0 日切后 + T+1 上午复核)三本账对齐:
| 账本 | 数据源 | 对什么 |
|---|---|---|
| A 支付通道 | 微信/支付宝对账单 | payment_records.success 实付合计 |
| B 积分总账 | point_ledger_entries |
当日 purchase credit ≈ 实付×10;bonus ≈ 赠送规则 |
| C 提成账 | commission_ledger |
当日 purchase_used÷10×费率 与消耗票一致 |
8.1 对账批次表¶
recon_batches
id / biz_date / type (payment|points|commission|cross)
status (running|matched|mismatch|resolved)
expected_json / actual_json / diff_json
created_at / resolved_by / resolved_at
8.2 交叉勾稽恒等式(示例)¶
Σ payment.success.amount_cny(日) × 10
== Σ point_ledger.purchase.credit(日, biz_type in purchase_grant)
Σ consume_tickets.purchase_used(日)
== Σ point_ledger.purchase.debit(日, biz_type=consume)
== Σ commission_ledger.purchase_points_consumed(日) # 若每人一笔
Σ user_point_balances.purchase
== Σ ledger.purchase (全量回放或 checkpoint+增量)
差异分类:missing_credit / double_credit / balance_drift / rate_mismatch / orphan_commission。
9. 提成账本(与消耗拆分绑定)¶
commission_ledger_entries
id / idempotency_key
beneficiary_id / role (sales|agent_a|agent_b)
user_id / consume_ticket_id / order_id(首两单)
basis (first_two_orders|purchase_consume)
purchase_points_consumed / amount_cny_basis
rate / commission_amount_cny
month / status (accrued|payable|paid|clawed_back)
created_at
规则强制:
- 仅
purchase_used > 0的消耗票计提消耗提成。 login_used/bonus_used不得产生消耗提成行。- 退款 / 消耗冲正 → 追加
clawed_back分录,不改历史 accrued 行金额。
10. 研发与运营「日查」清单¶
10.1 自动日任务(建议 每日 00:30 / 09:00)¶
| 检查项 | 通过标准 | 告警 |
|---|---|---|
| 支付↔购点 | 实付×10 = purchase credit(容差 0) | P0 |
| 赠送比例 | bonus credit 符合订单快照赠送% | P0 |
| 余额漂移 | 抽样 N 用户回放 = 物化余额 | P0 |
| 登录分过期 | expire 分录覆盖所有超 24h 未清零 | P1 |
| 消耗拆分 | ticket 三桶之和 = total_cost | P0 |
| 提成勾稽 | purchase_used 与 commission 一致 | P0 |
| 价目一致性 | 当日消耗 catalog_version 均已 retired/active 合法 | P1 |
| 快照过期 | expires_at 已过仍 active 的快照数 = 0 | P1 |
10.2 运营日查看板(Admin)¶
- 昨日实收 / 购点 / 赠点 / 消耗(三桶拆分) / 提成计提
- 对账批次状态:绿灯 / 红灯差异列表
- 异常用户:余额为负、login 过期未清、重复幂等冲突次数
- 一键「导出差异 CSV」给财务
10.3 研发日查¶
- 失败重试是否产生双分录(查同 idempotency_key)
- 死信队列:支付已成功但积分未到账
- 回放任务耗时与 checkpoint 覆盖率
11. 其他保障账目准确的方案(建议一并落地)¶
| 方案 | 作用 |
|---|---|
| 冲正而非修改 | 一切纠错追加 reversal;保留审计链 |
| 双人审批调账 | Admin adjust 需 maker-checker;强制 memo + 工单号 |
| 行级乐观锁 / 账户锁 | user_point_balances.version 或 SELECT FOR UPDATE,防并发超扣 |
| 消耗两阶段 | held → posted,失败冲正,避免「图没出却扣点」或「图出了没扣点」长期不一致 |
| 子账号共用主账户 | 所有分录 master_user_id 指向主账号;子账号禁止独立充值(接口层拒绝) |
| 业务日 + 时区统一 | 签到、提成月结、对账统一 Asia/Shanghai |
| 不可变存储 | 账本表 PG 权限撤销 UPDATE;或同步写对象存储 WORM 备份 |
| 哈希链 / 日终 Merkle(可选增强) | 每日对 entry 做链式 hash,防篡改举证 |
| 影子记账 / 双写校验期 | 迁移期旧配额与新三桶并行,每日 diff,达标后切流 |
| 财务关账 | 月结后锁定该月 commission 批次,补提只能记入下月调整 |
| 合同级验收用例 | 用规则文档中的数值(如基础档 6468/900/7368)做 golden test |
| 成本核算旁路 | 成本参考($0.027 等)只进核算报表,永不进入用户扣费路径 |
| 告警与值班 | 对账 mismatch → Alertmanager;超时未 resolve 升级 |
| 定期外部审计导出 | 标准格式:分录全量 + 价目版本 + 快照,交财务/审计 |
12. 关键状态机(摘要)¶
stateDiagram-v2
[*] --> OrderPending: 下单
OrderPending --> Paid: 支付成功(幂等)
Paid --> PointsCredited: 购点+赠点分录
PointsCredited --> Entitled: 写入权益快照
Entitled --> Consuming: 生图/视频
Consuming --> TicketHeld: 预占
TicketHeld --> TicketPosted: 成功入账三桶拆分
TicketHeld --> TicketReversed: 失败冲正
TicketPosted --> CommissionAccrued: 仅purchase_used>0
Entitled --> Expired: 到期降级体验档
13. 落地节奏建议¶
| 阶段 | 内容 |
|---|---|
| M1 | 价目版本表 + 权益快照 + 三桶余额 + 追加式 point_ledger + 幂等键 |
| M2 | 消耗票拆分 + 登录分领取/24h过期 + 扣费走价目版本 |
| M3 | 提成改「充值积分消耗」+ 首两单实付;commission 账本 |
| M4 | 日对账任务 + Admin 日查看板 + 回放修复工具 |
| M5 | 旧 usage_quotas 迁移脚本 + 影子对账 + 切流 |
14. 验收标准(账务)¶
- 任意用户任意时刻:回放三桶 = 物化余额。
- 重复支付回调 / 重复扣点请求:积分与提成不双记。
- 改价后:旧用户按旧快照单价扣;新购按新版。
- 仅消耗登录/赠送分:提成表无新增消耗提成。
- 日对账三方恒等式连续 7 天无 P0 差异。
- 人工调账必有冲正分录 + 审批记录。
15. 版本记录¶
| 版本 | 日期 | 说明 |
|---|---|---|
| v1.0 | 2026-07-21 | 初版:版本化价目、购时快照、追加式三桶账本、幂等、回放、三方对账、日查与其它保障项 |