Merge pull request 'docs: add promotion rebate chain PRD' (#388) from worktree-prd-promotion-rebate-chain into main

Reviewed-on: CYL/wordpress-theme-aksrt#388
This commit is contained in:
2026-08-05 16:46:41 +08:00
+281
View File
@@ -0,0 +1,281 @@
# 推广返佣与收益中心全链路重做
## Problem Statement
当前 AKSRT 已有邀请关系、付费内容返佣、创作收益、现金钱包和提现审核的零散能力,但它们没有形成一条可审计、可提现、可在用户中心完整查看的推广收益闭环:
1. 当前推广关系以邀请注册为中心,订单返佣只覆盖部分付费内容订单;会员订单没有进入返佣链路。
2. 返佣台账已有 pending/settled/cancelled 等概念,但结算实现把金额写入积分账户,而提现和收益中心读取现金钱包,导致返佣无法正确进入可提现余额。
3. 返佣没有自动结算任务,用户中心没有返佣明细、结算状态或推广佣金统计;现有收益页主要展示创作收益和现金钱包。
4. 现有原生后台、管理 REST 和用户 REST/前端对提现状态的处理不完全一致,存在拒绝后冻结金额未退回、状态与通知分叉等风险。
5. 退款没有可靠的返佣冲正和已提现佣金追缴模型;佣金比例、邀请关系和订单快照也没有统一的不可变账务边界。
6. 参考主题提供了需要复刻的产品体验:单级直接推广、佣金比例与适用范围、我的佣金聚合、返佣明细、提现中的状态展示、人工收款码打款和原生运营页;但参考实现存在权限、退款、幂等和状态筛选缺陷,不能原样复制。
本次工作将把推广返佣重做为现金账本驱动的完整闭环,并将用户中心的推广中心与收益中心分开组织。按用户决定,现有邀请码/注册积分与成长值奖励链整体替换为参考主题式 `ref` 推广契约,不保留旧新双路、兼容读取或数据迁移层。
## Current State
### 已存在
- 用户关系、邀请码、注册处理、邮箱验证、邀请奖励、内容付费订单、创作收益、现金钱包和提现审核均有独立实现。
- 内容现金订单支付成功后可根据推广人和比例创建 pending 返佣记录,并在订单侧保存推广人和佣金快照。
- 创作收益已经能以现金形式结算到钱包;现金钱包具备冻结、提现、拒绝退回和原生后台审核能力。
- 后台已有推广返佣、创作分成、提现审核的原生运营入口,以及支付相关设置页和部分管理 REST。
- 用户中心已有推广/邀请与收益标签的壳、邀请链接/记录请求和现金提现交互。
### 必须替换或补齐
- 将当前邀请码/注册奖励关系替换为唯一的 `ref` 推广关系;不再保留邀请码奖励配置、邀请码捕获或旧关系的兼容读取。
- 将会员订单和付费内容订单统一接入单级订单返佣;其他交易类型不参与本期佣金。
- 将返佣从积分账户迁移为现金钱包账务的唯一来源。这里的“迁移”不是运行时数据迁移:实现只提供新的前向存储契约,不回填旧记录、不双读旧字段。
- 用不可变订单佣金快照、调整记录、幂等键和现金流水替换当前“状态先更新、资金操作后执行”的非原子结算。
- 增加 7 天观察期后的定时批量结算、失败重试、退款冲正、已提现欠款约束和管理员补跑。
- 增加仅限当前用户的收益概览、佣金分页明细、提现分页记录和收款码管理 API;管理员读取和处理必须经过独立运营权限。
- 统一用户 REST、管理 REST、原生 WP 后台和前端使用同一提现状态机;删除不可达的第二套运营页面,不保留分叉实现。
## Solution
### 推广与归因体验
- 每个用户获得一个不可枚举、稳定的推广码,推广链接使用 `?ref=<推广码>`。
- 未注册访客第一次访问推广链接时锁定归因,保存 30 天;后续推广链接不能覆盖已保存的首次触达来源。
- 用户注册成功后立即绑定首次触达的推广人,关系永久固定,不允许换绑、自邀、循环绑定或将已绑定用户重新归因给其他推广人。
- `ref` 同时承担注册归因和订单佣金归因;当前邀请码、独立邀请码、注册积分/成长值奖励链整体移除,不与 `ref` 并存。
- 推广中心展示推广码、推广链接、复制反馈、当前佣金比例、适用订单类型、推广人数和有效付费人数;不展示被推广用户的完整订单或敏感收益。
### 订单返佣体验
- 仅会员订单和付费内容订单可产生推广佣金;免费订单、积分订单、充值/余额购买、自购、自邀、取消订单和不满足支付条件的订单不产生佣金。
- 一笔订单只归因给一个直接推广人,不产生二级或团队佣金。
- 返佣基数是订单实际支付的可返佣金额;优惠、抵扣和订单级让利后的有效金额进入基数,非返佣项目不进入基数。
- 全站统一佣金比例,初始默认 5%,后台可调整。订单产生返佣时同时保存基数、比例和金额快照;比例变更只影响新订单。
- 支付成功后返佣进入待结算,7 天观察期结束后由定时任务批量转为可用现金。结算任务支持幂等、失败重试和管理员补跑。
- 全额退款冲销整笔对应佣金;部分退款按退款金额占原可返佣金额的比例生成负向调整。待结算金额直接减少,可用金额扣减;已提现金额形成用户欠款,欠款未偿还前暂停新的提现申请。
- 原始佣金记录不可被覆盖,退款、手续费、欠款回收和人工更正均以带来源的调整流水表示。
### 收益中心体验
用户中心新增独立“收益中心”标签,推广中心只负责推广动作和归因信息,收益中心只负责现金收益和提现:
- 顶部聚合卡展示当前佣金比例、累计产生佣金、待结算佣金、可用佣金、提现中、已提现、推广人数和有效付费人数。
- 佣金明细支持分页、状态筛选和订单类型筛选;每行展示会员/付费内容类型、订单标识、产生时间、可返佣基数、比例快照、佣金金额、当前状态、结算时间和冲正信息。买家信息只保留必要的脱敏标识。
- 提现记录展示毛额、手续费率、手续费、净额、收款渠道、申请时间、审核时间、打款时间、当前状态和管理员备注。
- 用户可以维护支付宝和微信收款码,并在提现申请时选择渠道;申请保存收款凭证快照,后续修改个人收款码不改变已提交申请。
- 可用佣金达到最低 50 元且没有未偿欠款时,用户可以提交提现申请。默认手续费为 5%,费率、毛额和净额在申请时锁定,手续费不得超过毛额。
- 提现状态依次为待审核、已批准、已打款或已驳回。管理员必须先在线下完成收款码付款,再将申请标记为已打款;驳回会原子释放冻结金额并记录原因。
- 加载中、无数据、权限失败、余额不足、低于门槛、已有待处理申请、收款码缺失、佣金欠款和网络失败均提供明确反馈,不显示误导性金额。
- 桌面和移动端均使用用户中心现有壳、导航、响应式布局和设计 token;佣金卡、明细、提现表单不要求横向滚动。
### 管理员体验
- 配置面仅负责开关、全站佣金比例、适用订单类型、结算观察期、最低提现金额、手续费比例、可用收款渠道、提现协议和展示文案。
- 运营面使用原生 WP 支付中心:管理员可以按订单类型、推广人、用户、状态和时间筛选佣金记录,查看不可变快照和调整历史,执行补结算/取消待结算记录,并处理退款冲正异常。
- 原生提现页支持待审核、已批准、已打款、已驳回筛选,展示收款码快照、毛额/手续费/净额、关联佣金流水、欠款约束和操作历史;通过和拒绝都要求 nonce、权限和幂等检查。
- 管理 REST 与原生页面调用同一个领域服务,不复制状态转换、余额冻结或通知逻辑。
- 运营权限只向明确授权的管理员开放;普通用户不能通过修改用户 ID、分页参数或订单号读取他人收益或提现数据。
## User Stories
1. **推广用户**:我可以生成不可枚举的 `ref` 推广链接,并在复制成功或失败时得到明确反馈。
2. **首次访问者**:我首次打开推广链接后,30 天内注册都能保持同一推广归因;后来打开其他推广链接不会覆盖首次来源。
3. **新用户**:我注册成功后推广关系立即固定,不能因为后续访问或订单参数变化被换绑。
4. **管理员**:我可以启用或关闭返佣,并设置全站佣金比例、结算观察期、提现门槛、手续费和可用渠道。
5. **推广用户**:我的被推广用户购买会员后,可以看到一笔包含比例和可返佣基数快照的待结算佣金。
6. **推广用户**:我的被推广用户购买付费内容后,可以看到与会员订单一致的佣金体验;非会员/内容订单不应静默产生佣金。
7. **推广用户**:佣金比例变更后,已有订单金额不变化,新订单才使用新比例。
8. **推广用户**:支付后的 7 天观察期内,我能区分待结算与可用佣金;观察期结束后,系统自动将到期记录结算到现金钱包。
9. **推广用户**:订单全额退款时,待结算佣金被冲销;部分退款时,只冲销对应比例,未退款部分保留。
10. **推广用户**:已经提现的订单随后退款时,系统形成可追踪欠款;在欠款清偿前,我不能继续发起提现。
11. **推广用户**:收益中心能一次看到佣金比例、累计产生、待结算、可用、提现中、已提现、推广人数和有效付费人数。
12. **推广用户**:我只能看到自己的佣金、提现和推广汇总,不能通过接口参数读取其他用户的订单或余额。
13. **推广用户**:我可以维护支付宝或微信收款码,申请提现时保存当时的收款码快照。
14. **推广用户**:当可用佣金低于 50 元、存在欠款、缺少收款码或已有待审核提现时,系统阻止申请并说明原因。
15. **管理员**:我可以先审核提现,再在确认线下打款后标记已打款;驳回时冻结金额会恢复,申请保留驳回原因和操作历史。
16. **管理员**:我可以重新运行失败的结算任务或处理异常调整,但不能覆盖原始订单佣金记录。
17. **安全审计者**:所有用户接口、管理员接口和提现状态转换都具有正确的权限、nonce、输入验证、输出脱敏和幂等约束。
18. **运营人员**:关闭返佣后,新订单不再生成佣金;既有账本、已批准提现和退款冲正仍可完成,不产生半套功能。
## Implementation Decisions
### New Modules
#### Referral Attribution
负责推广码、首次触达和永久关系,不负责积分、余额或订单金额。
- `capture(ref, request_context): CaptureResult`
- `bind(user_id, capture_context): BindingResult`
- `resolve(user_id, occurred_at): ReferralRelation|null`
- `create_link(user_id): ReferralLink`
- `validate_relation(promoter_id, user_id): ValidationResult`
关系数据必须以推广码和用户唯一约束保证幂等;模块拒绝不存在的推广码、自邀和重复绑定。
#### Commission Ledger
负责订单佣金报价、不可变快照、待结算、调整、统计和欠款,不直接处理页面渲染。
- `quote(order_context): CommissionQuote`
- `record_paid_order(order_context, quote, idempotency_key): LedgerEntry`
- `settle_due(as_of, limit): SettlementReport`
- `reverse(order_context, refund_context, idempotency_key): AdjustmentResult`
- `get_overview(user_id): EarningsOverview`
- `list_entries(user_id, filters, page): PaginatedLedger`
金额使用货币精度计算和数据库十进制存储,不把元金额强转为积分整数;结算与现金钱包入账必须在同一事务边界内完成。
#### Order Commission Adapter
将会员和付费内容订单事件映射到佣金账本,隐藏各订单领域的字段差异。
- `on_membership_paid(order): CommissionEventResult`
- `on_content_paid(order): CommissionEventResult`
- `on_order_refund(order, refund): AdjustmentResult`
- `run_due_settlement_batch(batch_context): SettlementReport`
支付、重复 webhook、订单重试、退款重试必须使用稳定幂等键;其他订单类型明确返回“不适用”,不得落入默认返佣路径。
#### Cash Wallet and Withdrawal
统一返佣、创作收益和现金余额的入账、冻结、释放、扣款和流水;提现请求只由这一模块改变冻结资金。
- `credit(user_id, amount, source, idempotency_key): WalletEntry`
- `hold(user_id, amount, source_id): HoldResult`
- `release(user_id, hold_id, reason): ReleaseResult`
- `create_withdrawal(user_id, request): WithdrawalRequest`
- `transition_withdrawal(id, transition, operator): WithdrawalResult`
- `record_adjustment(user_id, amount, source, idempotency_key): WalletEntry`
提现状态机为 `pending → approved → paid` 或 `pending → rejected`;状态转换、余额变更、通知和审计记录必须原子且可重试。
#### Earnings Center Read Model
对用户和管理员提供统一的只读聚合,隐藏账本、钱包和提现表的组合查询。
- `get_user_overview(user_id): EarningsOverview`
- `get_user_commissions(user_id, filters, page): PaginatedCommissionItems`
- `get_user_withdrawals(user_id, page): PaginatedWithdrawalItems`
- `get_admin_overview(filters): AdminEarningsOverview`
用户端方法从认证上下文取得用户身份,不接受可覆盖身份的请求参数;管理员方法必须经过运营权限检查。
#### Configuration and Native Operations
配置模块提供唯一的返佣和提现设置契约;运营模块提供原生 WP 后台列表、筛选、补结算、冲正审核和提现状态操作。
- `get_affiliate_settings(): AffiliateSettings`
- `save_affiliate_settings(input): AffiliateSettings`
- `list_admin_ledger(filters, page): AdminLedgerPage`
- `list_admin_withdrawals(filters, page): AdminWithdrawalPage`
- `process_admin_action(id, action, note): OperationResult`
配置只在 SPA 配置面维护;佣金订单、提现审核和用户运营数据只在原生 WP 操作面维护,不在两个前端实现同一套业务工作台。
### Architectural Decisions
- **唯一归因契约**:全面使用 `ref` + 不可枚举推广码;删除当前邀请码/独立邀请码/邀请奖励链,不保留旧参数、旧 cookie、旧关系表的双读或兼容分支。
- **单级关系**:订单只奖励直接推广人;不支持二级、团队或推广人等级叠加比例。
- **订单范围**:只支持会员和付费内容;不为商城、充值、积分购买或未来订单类型添加隐式兜底。
- **计价口径**:以实际支付的可返佣金额为基数,比例为全站统一比例;下单时保存比例、基数、订单类型和佣金金额快照。
- **时间口径**:注册前首次触达保留 30 天;注册成功立即绑定;支付后待结算 7 天;比例修改只影响新订单。
- **现金会计**:返佣只能进入现金钱包,不能进入积分账户;佣金账本、现金钱包流水和提现请求以稳定来源标识互相追溯。
- **退款会计**:不修改原始佣金金额;全额/部分退款写入负向调整,已提现部分形成欠款,欠款清偿前禁止新的提现。
- **提现会计**:提现申请锁定毛额、费率、手续费、净额、渠道和收款码快照;默认最低 50 元、默认手续费 5%,两项均可由管理员调整。
- **人工支付**:只支持支付宝/微信收款码人工打款;不接入自动支付 API、银行转账或其他渠道。
- **权限边界**:登录用户只看自己;管理员看全站;所有 REST 路由都有明确权限回调,所有状态变更都有 nonce/能力校验、输入校验和审计记录。
- **定时结算**:使用 WordPress 定时任务批量结算到期佣金,使用行锁/幂等键/失败重试避免重复入账;用户访问收益中心不承担资金副作用。
- **配置与运营分层**:SPA 只管理设置;原生 WP 只管理佣金、结算和提现运营;删除不可达的重复运营 Vue 页面与重复邀请配置面。
- **国际化与前端**:所有用户可见文案使用 `aksrt` 文本域;收益概览、明细和提现表单复用用户中心壳与设计 token,不新增独立 UI 框架。
- **安全改进优先于字面复制**:不复制参考主题的用户 ID 枚举、任意用户明细查询、退款不冲正、状态筛选失效、提现创建失败后冻结不回滚等缺陷。
### Schema Changes
- 将现有邀请关系存储替换为 `referral_relation` 契约:唯一推广码、推广人、被推广用户、首次触达时间、绑定时间和关系状态;被推广用户唯一绑定。
- 将现有返佣记录替换为 `commission_ledger` 契约:受益推广人、来源用户、来源订单标识、订单类型、可返佣基数、比例快照、原始佣金、调整总额、状态、到期时间、结算时间、幂等键和审计说明。
- 返佣原始记录不可变;退款冲正、欠款回收和人工纠正使用带来源的调整记录,能够关联订单、退款和操作人。
- 现金钱包流水增加来源类型、来源标识、幂等键、正负方向、可用余额变化和冻结余额变化,保证佣金、创作收益、提现冻结和退款调整可追踪但不混入积分流水。
- 提现请求保存用户、毛额、手续费率、手续费、净额、渠道、收款码附件快照、状态、申请/审核/打款时间、操作人、备注和关联资金流水;账户信息只按最小必要范围存储并在列表中脱敏。
- 会员和付费内容订单必须能提供稳定订单标识、支付金额、可返佣金额、推广人快照和退款金额;佣金账本以订单标识 + 受益人 + 类型构成幂等约束。
- 前向 schema 安装替换旧返佣/邀请码/邀请奖励契约,提升 schema 版本并更新清理清单;不执行旧数据回填、旧字段双读、旧表兼容或静默迁移。
### API Contracts
所有接口使用 `aksrt/v1`,响应遵循统一错误结构和分页结构,金额以十进制金额字符串或明确的货币数值返回,不向前端暴露内部数据库结构。
#### 登录用户接口
- `GET /promotion/me`:返回当前用户的推广码、`ref` 链接、当前佣金比例、适用订单类型、推广人数和有效付费人数。
- `PUT /promotion/payout-accounts`:保存支付宝/微信收款码附件引用;只允许当前用户修改自己的资料,附件类型、归属和权限必须校验。
- `GET /earnings/overview`:返回当前佣金比例、累计产生、待结算、可用、提现中、已提现、有效付费人数、欠款、最低提现金额、手续费和启用渠道。
- `GET /earnings/commissions`:按状态、订单类型、日期分页查询当前用户的佣金流水;只返回本人的订单佣金及必要脱敏字段。
- `GET /earnings/withdrawals`:分页返回当前用户的提现申请、状态、毛额/手续费/净额、渠道、时间和处理备注。
- `POST /earnings/withdrawals`:提交提现金额和渠道;服务端重新检查可用余额、门槛、欠款、重复待处理申请、收款码和手续费边界,不信任前端汇总。
#### 管理员接口
- `GET /payment/affiliate/overview`:返回全站返佣、待结算、可用、冲正、欠款、提现和任务统计。
- `GET /payment/affiliate/ledger`:按推广人、来源用户、订单类型、状态、日期和订单标识分页查询佣金账本。
- `POST /payment/affiliate/ledger/{id}/settle` 与 `POST /payment/affiliate/ledger/{id}/cancel`:仅用于合法的补结算或取消待结算记录,受状态机和幂等约束限制。
- `GET /payment/withdrawals`:按状态、用户、渠道、日期和金额分页查询提现申请,返回脱敏收款码快照和关联流水。
- `POST /payment/withdrawals/{id}/transition`:执行批准、已打款或驳回;批准不扣除冻结余额,已打款完成资金结算,驳回释放冻结余额,所有转换必须记录操作人和理由。
- 配置 REST 只读写唯一的 affiliate、withdrawal 和 settlement 设置契约;不暴露旧 invite/rebate/balance 多套字段名。
所有用户接口的权限回调强制使用当前认证用户;所有管理员接口使用独立运营能力;不存在接受任意 `user_id` 后直接查询收益的接口。
### Navigation
- 用户中心保留两个独立标签:**推广中心**(推广码、链接、归因和推广统计)与 **收益中心**(佣金、现金钱包、提现)。不再注册旧邀请码、旧邀请奖励或创作收益与推广佣金混排的重复页面。
- 站点管理员在 SPA 中进入推广返佣/提现配置;在原生 WP 支付中心进入佣金运营和提现审核。配置页不承载订单工作台,运营页不重复编辑配置表单。
- 旧的独立收益页面、旧 invite 页面和不可达 SPA 运营页面不保留兼容跳转或双渲染路径;以当前用户中心标签和原生运营菜单为唯一入口。
## Testing Decisions
本次要求核心全链路自动化测试,并使用 WordPress/浏览器做关键 UI 冒烟。测试不依赖旧实现的错误行为,重点覆盖:
### 归因与注册
- 有效推广码首次访问、30 天内注册、过期后注册、后续链接覆盖尝试。
- 不存在的推广码、格式错误、自邀、循环关系、重复注册绑定、并发注册绑定。
- 注册成功后关系永久固定,禁止用户 ID 参数覆盖当前认证用户。
- 旧邀请码、旧 invite 参数和旧奖励设置不再产生任何返佣或注册奖励路径。
### 订单与账本
- 会员现金订单和付费内容现金订单各自产生一笔 pending 佣金。
- 免费、积分、充值、非目标订单、自购和无有效推广关系不产生佣金。
- 重复支付事件、重复 webhook、重复任务和并发处理不会重复写入佣金或现金。
- 优惠、抵扣、让利后的可返佣基数和 5% 比例快照正确;修改比例不重算历史订单。
- 7 天前后结算边界、定时任务批量锁定、失败重试、管理员补跑和通知。
- 返佣结算进入现金钱包而非积分;现金流水、账本状态和余额变化保持原子一致。
### 退款与欠款
- 观察期内全额退款直接冲销待结算佣金。
- 可用佣金全额/部分退款按比例生成调整,原始记录保持不变。
- 已提现佣金退款形成欠款;余额不足时禁止新提现,后续返佣可按规则抵扣欠款。
- 重复退款事件不重复冲正,异常退款能进入可审计的人工处理状态。
### 提现与权限
- 低于 50 元、无收款码、有未偿欠款、有待审核申请、余额不足和手续费超界均被拒绝。
- 支付宝/微信收款码校验、账户快照、脱敏展示和个人资料更新不影响已有申请。
- 待审核 → 已批准 → 已打款、待审核 → 已驳回的合法转换;非法转换、重复点击、并发审批被拒绝。
- 驳回释放冻结金额;批准/已打款只在正确阶段改变资金;原生后台与管理 REST 结果一致。
- 用户接口无法读取其他用户的 overview、佣金、提现或收款码;管理员接口需要正确能力。
### 前端与合约
- 收益中心概览、分页明细、提现记录、筛选、空状态、加载失败和成功/失败反馈。
- 桌面与移动端无横向溢出,复制推广链接、上传收款码、提现提交和错误提示可键盘操作。
- SPA 配置 schema、PHP schema、REST 契约和原生菜单通过 `php tools/audit-admin-contracts.php`。
- Admin SPA 运行构建通过;在外部 WordPress harness 中完成注册、支付、退款、结算、提现和权限冒烟。
## Out of Scope
- 多级、团队、间接推广、推广人等级差异化比例、商品/商城返佣。
- 充值、积分购买、纯积分订单、免费订单、银行转账、PayPal 或自动打款 API。
- 佣金趋势图、复杂数据分析、公开排行榜、公开推广用户详情和推广人查看被推广用户完整订单。
- 将现金佣金转换为积分、站内消费余额或其他第二种资金账户。
- 保留或新增 `invite`/`ref` 双链接、旧字段 fallback、旧新接口并行、旧表双读、数据回填、兼容跳转或迁移脚本。
- 复制参考主题的用户 ID 暴露、任意用户查询、提现失败冻结不回滚、退款不冲正、状态筛选失效、金额整数截断和 AJAX 拼接 HTML 等缺陷。
- 自动化社交平台分享、第三方推广统计、站外归因和多站点推广网络。