Appearance
08 · 实时返水系统
0. 文档说明
| 项 | 内容 |
|---|---|
| 版本 | V1.0 |
投注即返。订阅 12 的
BetSettled实时累计;费率档位读 06 等级;领取入账走 02。一租户 = 一「本位币站」,站内单币种(→ 00 架构总纲)。返水池、有效投注、累计、领取到账口径恒为本位币
wallet.baseCurrency;返水池按 游戏类型 × 厂商 两维分桶,池值恒本位币。
一、定位与职责
- 定义返水的实时累计模型(注单结算 → 按费率入池,按 游戏类型 × 厂商 分桶,金额恒本位币);
- 定义费率矩阵(游戏类型 × VIP 等级,厂商可覆盖)与取值规则;
- 定义领取(阈值/粒度/幂等)与「即将派发」倒计时的准确语义;
- 定义返水面板、返水比例详情页、规则页的展示契约。
边界:有效投注(validTurnover)的产生与冲正归 12;等级归 06;打码权重是 10 的概念(返水用原始有效投注,不加权)。
二、核心概念与数据模型
2.1 返水池 RakebackPool(用户 × 游戏类型 × 厂商)
| 字段 | 说明 |
|---|---|
userId / tenantId | 归属 |
gameType / vendor | 分桶维度(游戏类型:原创/电子/真人/棋牌/捕鱼/体育…,目录归 12);无 currency 维度——站内单币种,池值恒本位币 |
accrued | 当前可领金额(本位币,实时累计,已结算即入) |
lastAccrualAt | 最近累计时间 |
场馆链路的 CNY 映射(→ 02 链路 route:仅 USDT 站高价值场馆可选)只影响向厂商申报的符号/数值口径,厂商回传注单由通道适配层 1:1 重标为本位币入库;本系统拿到的
validTurnover已是本位币真实值,返水计算零特判。
2.2 累计与领取流转
BetSettled(12) ──► accrual = validTurnover × rate(gameType, vipLevel, vendor?) ──► 池 accrued +=(本位币)
│
用户领取(≥ minClaim) ──► REWARD_CREDIT(claimId) ──► 池清零(领取范围内) ──► 界面出「即将派发」倒计时
= 下一结算批次(settleCycle)
注单取消(BetCancelled) ──► 对应累计冲正(池扣回;池不足时挂负债,后续累计抵扣)「即将派发」语义:倒计时仅在领取之后显示(settle.showCountdown=true),含义是「下一批结算入池的时间」(settle.nextSettleAt 绝对时间戳,→ §五 settle 字段);未领取时面板只显示当前可领金额与领取按钮,不显示倒计时,也不出现「每 2 小时到账」类固定文案;realtime 模式恒出静态文案「投注后实时到账」。
2.3 费率取值(优先级)
rate = vendorOverrides[vendor][gameType][level] // 厂商级覆盖(可选)
?? matrix[gameType][level] // 游戏类型 × 等级(主矩阵)
?? 0等级取注单结算时点的用户等级;费率用小数(0.006 = 0.6%,→ 00 §4.8);入池金额向下取整到本位币精度(→ 02 §3.7)。
三、业务规则
- 实时性:结算即入池(事件驱动,秒级);未结算注单不产生返水。
- 领取:粒度由
claimGranularity配置——all(一键领全部)/perType(按游戏类型分领);门槛minClaim(本位币);幂等键claimId;领取发RewardClaimed(source=RAKEBACK),默认直入可用(rewardTarget=available),入本位币钱包。 - 冲正:注单取消(
BetCancelled,幂等键betId+cancelSeq)→ 从对应池扣回,写一条rakeback_accrual_log(kind=REVERSE, amount<0)(与结算行 kind=ACCRUE 共享 bet_id、靠 kind+cancel_seq 区分,支持同注单多次/部分取消);池已被领走导致不足 → 记负余额(负债),后续累计先抵扣,不向用户追讨。注:返水冲正只作用于返水池;已解锁/已 FULFILLED 的彩金打码义务不因取消回退(资金已放,→ 10 §3.1),二者处置口径独立。 - 等级变化:
LevelChanged后,新结算的注单按新费率;已入池金额不重算。 - 过期:
expireDays可配(默认 null 不过期);过期清零走BONUS_EXPIRE语义的返水专用记录(留痕)。 - 风控:领取过 14 前置;对打套利(两边对冲刷流水)由 14 识别,处置=冻结领取/名单。
四、★ 租户可配置项(rakeback 命名空间)
jsonc
"rakeback": {
"enabled": true,
"rewardTarget": "available",
"claimGranularity": "all", // all | perType
"minClaim": "1", // 领取门槛(本位币;站内单币种,单值不分币种)
"settleCycle": "realtime", // realtime | 每 N 分钟批次(倒计时展示依据)
"expireDays": null,
"matrix": { // 游戏类型 × 等级段(段内同率,覆盖 1..maxLevel)
"slots": [ { "levels": "1-10", "rate": 0.003 }, { "levels": "11-30", "rate": 0.006 }, { "levels": "31-50", "rate": 0.009 } ],
"live": [ { "levels": "1-10", "rate": 0.002 }, { "levels": "11-30", "rate": 0.004 }, { "levels": "31-50", "rate": 0.006 } ],
"card": [ /* … */ ], "lottery": [ /* … */ ], "fish": [ /* … */ ], "sport": [ /* … */ ], "esport": [ /* … */ ], "original": [ /* … */ ]
},
"vendorOverrides": { } // 可选:{ "pg": { "slots": [ … ] } }
}Schema 校验:每 gameType 的段覆盖 1..level.maxLevel 且不重叠;rate ∈ [0, 上限(平台风控线)];gameType ⊆ 12 目录;minClaim 单值(本位币)。
五、与其他系统的关系 / 接口
| 接口 | 调用方 | 幂等键 | 说明 |
|---|---|---|---|
getRakebackPanel(userId) | 展示层 | — | 按游戏类型分组的厂商池列表 + 可领总额(本位币) + settle 倒计时字段(见下) |
getRateTable(gameType, vendor?) | 展示层 | — | 该维度 1..50 级费率表(比例详情页) |
claim(userId, scope) | 展示层 | claimId | 领取(scope=all/type),入本位币钱包 |
消费 BetSettled / BetCancelled | ← 12 | betId(+cancelSeq) | 累计/冲正 |
消费 LevelChanged | ← 06 | changeSeq | 刷新费率档位 |
产 RewardClaimed | → 02/13/14/16 | claimId | 入账留痕(本位币) |
settle 倒计时字段结构(getRakebackPanel 返回):
jsonc
"settle": {
"mode": "realtime", // realtime | batch(取自 rakeback.settleCycle)
"nextSettleAt": null, // batch 模式=下一结算批次的绝对时间戳(ISO,后端已对齐批次边界);realtime 模式=null
"showCountdown": false // 仅「本次领取之后」为 true(未领取不显示倒计时)
}- 来源:
mode直取rakeback.settleCycle;nextSettleAt由后端按批次边界对齐后下发绝对时间戳(前端只做nextSettleAt − now倒计时,不自行推批次);showCountdown由「是否刚领取过」决定。 - 批次边界对齐规则:
settleCycle=每N分钟时,nextSettleAt= 租户时区自然整点起算的下一个 N 分钟边界(如 N=120 → 对齐到偶数整点),与用户注册时刻无关,保证同租户所有用户对齐同一批次。 - 前端分支:
mode=realtime→ 出静态文案「投注后实时到账」(不倒计时);mode=batch && showCountdown→ 按nextSettleAt倒计时;showCountdown=false→ 只显示可领金额与领取按钮,无倒计时(→ §2.2)。
六、运营后台能力(→ 15)
| 侧 | 能力 |
|---|---|
| 平台控制台 | 费率上限风控线(防商户误配 10% 级费率) |
| 商户控制台 | 费率矩阵编辑(游戏类型×等级段,厂商覆盖)、领取门槛/粒度/过期、返水成本报表(→17)、用户返水流水查询 |
七、展示契约(→ 原型映射)
| UI 元素 | 数据 | 原型载体 | 系统契约 |
|---|---|---|---|
| 游戏类型侧边栏 | 池按 gameType 分组 | 返水 tab 左侧类型栏 | 类型目录来自 12;仅显示有池或有费率的类型 |
| 厂商行 | vendor 池金额(本位币) + logo | 品牌 logo 复用大厅 app/assets/img/brand/wd/pXX.webp;行可点 | 点击 → 比例详情页(带入该厂商);金额恒本位币符号 |
| 领取按钮 | 可领总额 ≥ minClaim | 完成态领取按钮(可领=绿/不足门槛=灰) | claim(all);领取后即时刷新池与红点 |
| 「即将派发」倒计时 | settle.{mode,nextSettleAt,showCountdown}(→ §五) | 仅领取后显示(showCountdown) | batch 按 nextSettleAt 绝对时间戳倒计时;realtime 出「投注后实时到账」静态文案 |
| 比例详情页 | 费率表 | #sub-rebate-detail:游戏类型/厂商双下拉 + 1..50 级费率表(当前级高亮) | getRateTable;下拉选项来自 12 目录 |
| 规则页 | 计算口径 | #sub-rebate-rules(独立页,由 ? 入口进入) | 文案与配置联动(门槛/粒度/口径:有效投注=已结算注单本金,取消冲正) |
八、数据库设计(全表含 tenant_id;金额 DECIMAL(32,8))
| 表 | 关键字段 | 约束/索引 |
|---|---|---|
rakeback_pools | tenant_id, user_id, game_type, vendor, accrued(本位币,可负=负债), last_accrual_at | UK(tenant_id,user_id,game_type,vendor) |
rakeback_accrual_log | id PK, tenant_id, user_id, bet_id, kind(ACCRUE/REVERSE:结算入池 / 取消冲正), cancel_seq(结算行=0,冲正行=取消序号), game_type, vendor, turnover, rate, amount(本位币,冲正为负), created_at | UK(tenant_id,bet_id,kind,cancel_seq)——结算与多次冲正各一行,靠 kind+cancel_seq 区分;IDX(tenant_id,user_id,created_at) |
rakeback_claims | claim_id PK, tenant_id, user_id, scope, amount(本位币), detail JSON(各池扣减明细), created_at | UK(tenant_id,claim_id) |
(池键为 (tenant_id, user_id, game_type, vendor)——站内单币种,金额恒本位币,键内无 currency 分量。)accrual_log 为审计与「返水明细」展示依据;高频场景可批次聚合写入(实现优化,语义一致)。
九、扩展点与开放问题
- 加权返水:返水基数用原始有效投注,权重仅存在于 10 的打码;若租户要求加权返水,复用 10 的权重表作可选项。
- 负债展示:冲正负债对用户可见(「待抵扣 -X」)还是静默抵扣,交互待定。
- 实时批次的成本:
realtime逐注入池在高频下的写放大,实现层可微批(N 秒聚合),语义不变。 - 返佣 basis=rakebackShare 的取数口径:本系统返水池是发给用户的(无「平台返水池」实体)。11 若配
basis=rakebackShare,其分成基数 = 下级实际领取的返水净额(RewardClaimed(source=RAKEBACK)的领取额,已含冲正抵扣后的真实到手值),数据源 =rakeback_claims(而非入池accrued或冲正前流水),避免与返水成本双计(→ 11 §2.3)。
十、验收要点
- [ ] 注单结算后池金额 = Σ(validTurnover × 结算时点费率),向下取整到本位币精度;未结算注单不入池;
- [ ] 池仅按 游戏类型 × 厂商 分桶,金额全程本位币,无 currency 分桶维度;
- [ ] 领取幂等,入本位币钱包;领取后池清零、红点清除、倒计时才出现(
settle.showCountdown=true,batch 按nextSettleAt绝对时间戳、realtime 出静态文案);未领取时无倒计时、无「每2小时」文案; - [ ] 注单取消(betId+cancelSeq)后池扣回,写
accrual_log(kind=REVERSE)与结算行 kind=ACCRUE 靠 kind+cancel_seq 共存不撞 UK;池不足挂负债并被后续累计抵扣; - [ ] 升级后新注单按新费率,旧池不重算;
- [ ] 比例详情页:切换游戏类型/厂商,费率表与当前级高亮正确;费率全配置驱动;
- [ ] 费率超平台上限的配置发布被拒。