185 lines
8.1 KiB
Markdown
185 lines
8.1 KiB
Markdown
# 幸运礼物线上落地文档
|
||
|
||
本文档定义当前幸运礼物在 `activity-service` 的线上落地边界、后台参数、抽奖事务和验证方式。幸运礼物只拥有活动决策、RTP 窗口、奖池和抽奖事实;金币扣费和返奖入账仍归 `wallet-service`,房间状态和房间表现仍归 `room-service`。
|
||
|
||
## Current Scope
|
||
|
||
本次落地包含:
|
||
|
||
| Scope | Status | Notes |
|
||
| --- | --- | --- |
|
||
| `LuckyGiftService.CheckLuckyGift` | done | 房间送礼前检查礼物是否启用,并返回当前体验池 |
|
||
| `LuckyGiftService.ExecuteLuckyGiftDraw` | done | 扣费成功后执行抽奖决策,写抽奖事实和 outbox |
|
||
| `AdminLuckyGiftService.GetLuckyGiftConfig` | done | 后台按 `pool_id` 读取幸运礼物奖池规则;未配置时返回默认草稿 |
|
||
| `AdminLuckyGiftService.UpsertLuckyGiftConfig` | done | 后台按 `pool_id` 发布独立幸运礼物奖池规则版本 |
|
||
| `AdminLuckyGiftService.ListLuckyGiftDraws` | done | 后台审计抽奖记录 |
|
||
| 三层基础奖池 | done | platform / room / gift |
|
||
| RTP 双窗口 | done | global + gift |
|
||
| 风控计数 | done | user hour/day、device day、room hour、anchor day |
|
||
| 房间气氛池 | done | 独立预算,不污染基础 RTP |
|
||
| 活动预算池 | done | 独立补贴,不污染基础 RTP |
|
||
|
||
暂不在 `activity-service` 事务内调用钱包或房间 RPC。抽奖事务只写事实和 `activity_outbox`;后续由 outbox dispatcher 或房间链路消费结果。
|
||
|
||
## Call Flow
|
||
|
||
```text
|
||
room-service SendGift
|
||
1. CheckLuckyGift(meta, user_id, room_id, gift_id, pool_id)
|
||
2. wallet-service 扣费成功
|
||
3. ExecuteLuckyGiftDraw(command_id, user_id, device_id, room_id, anchor_id, gift_id, pool_id, coin_spent, paid_at_ms)
|
||
4. activity-service 本地事务写 draw fact + outbox
|
||
5. 事务后由钱包/房间表现链路处理 reward_status=pending 的结果
|
||
```
|
||
|
||
`command_id` 是抽奖幂等键。重复 `ExecuteLuckyGiftDraw` 会返回同一条 `lucky_draw_records`,不会重复消耗 RTP、奖池或预算。
|
||
|
||
后台按 `pool_id` 维护多份互相独立的幸运礼物奖池规则,实际抽奖仍记录用户发送的真实 `gift_id`。后台不暴露单抽消耗;服务端保存固定内部换算单位,不同幸运礼物实际消耗不同,抽奖事务按实际 `coin_spent` 等比缩放基础奖档,并按实际 `coin_spent` 累计 RTP 目标和奖池入账。同一个 `gift_id` 可以请求不同 `pool_id`,不同 `pool_id` 的 RTP 窗口、基础奖池、房间气氛池、活动预算、用户阶段和风控计数互不共享。
|
||
|
||
## Transaction Boundary
|
||
|
||
`ExecuteLuckyGiftDraw` 使用一个 MySQL 本地事务,事务内必须完成:
|
||
|
||
1. 按 `command_id` 锁定幂等记录。
|
||
2. 锁定 `lucky_gift_rules` 中 `pool_id` 对应规则。
|
||
3. 锁定或创建用户体验状态 `lucky_user_states`。
|
||
4. 锁定或创建全站 RTP 窗口、幸运礼物整体子窗口。
|
||
5. 锁定或创建平台、房间、幸运礼物整体三层基础奖池。
|
||
6. 锁定或创建房间气氛池。
|
||
7. 锁定或创建活动总预算桶和 UTC 日预算桶。
|
||
8. 锁定用户、设备、房间、主播风控计数。
|
||
9. 抽前过滤所有不可支付候选。
|
||
10. 执行一次服务端安全随机。
|
||
11. 更新 RTP 窗口、奖池、预算、风控计数、用户状态。
|
||
12. 插入 `lucky_draw_records`。
|
||
13. 必要时插入 `activity_outbox`。
|
||
|
||
事务内不得调用 `wallet-service`、`room-service` 或腾讯云 IM,避免外部 RPC 卡住奖池行锁。
|
||
|
||
## RTP Accounting
|
||
|
||
基础返奖只使用 `base_reward_coins`:
|
||
|
||
```text
|
||
base_rtp = sum(base_reward_coins) / sum(coin_spent)
|
||
```
|
||
|
||
用户可见返奖使用:
|
||
|
||
```text
|
||
effective_reward_coins = base_reward_coins
|
||
+ room_atmosphere_reward_coins
|
||
+ activity_subsidy_coins
|
||
```
|
||
|
||
房间气氛池和活动预算只能提高 `effective_rtp`,不能用于补平基础 RTP。
|
||
|
||
## Admin Parameters
|
||
|
||
后台参数分为 6 类。
|
||
|
||
后台 HTTP 入口:
|
||
|
||
| Method | Path | Permission | Meaning |
|
||
| --- | --- | --- | --- |
|
||
| `GET` | `/api/v1/admin/activity/lucky-gifts/config?pool_id=pool_95` | `lucky-gift:view` | 读取指定奖池规则;未配置返回默认草稿 |
|
||
| `PUT` | `/api/v1/admin/activity/lucky-gifts/config?pool_id=pool_95` | `lucky-gift:update` | 发布指定奖池的新规则版本 |
|
||
| `GET` | `/api/v1/admin/activity/lucky-gifts/draws` | `lucky-gift:view` | 查询抽奖审计记录 |
|
||
|
||
| Group | Fields | Meaning |
|
||
| --- | --- | --- |
|
||
| RTP 成本 | `target_rtp_ppm`, `pool_rate_ppm`, `global_window_draws`, `gift_window_draws` | 控制基础 RTP 和收敛窗口 |
|
||
| 三层池 | `platform_pool_weight_ppm`, `room_pool_weight_ppm`, `gift_pool_weight_ppm`, `initial_*_pool`, `*_reserve` | 控制平台、房间、礼物各自承担的基础返奖能力 |
|
||
| 倍率配置 | `multiplier_ppms`, generated `tiers` | 运营只配置用户可能命中的倍率;服务按 RTP 窗口、水位和风控自动生成实时概率 |
|
||
| 体验池 | `novice_draw_limit`, `intermediate_draw_limit` | 控制新手/中级/高级阶段,不直接决定成本 |
|
||
| 高倍 | `high_multiplier`, `high_water_pool_multiple`, `large_tier_enabled` | 控制 100x/500x 等高倍倍率是否可进入候选 |
|
||
| 风控 | `max_single_payout`, `user_hourly_payout_cap`, `user_daily_payout_cap`, `device_daily_payout_cap`, `room_hourly_payout_cap`, `anchor_daily_payout_cap` | 控制单用户、设备、房间、主播关联风险敞口 |
|
||
| 娱乐补贴 | `room_atmosphere_rate_ppm`, `room_atmosphere_initial`, `room_atmosphere_reserve`, `activity_budget`, `activity_daily_limit` | 控制房间爆点和活动补贴 |
|
||
|
||
调整方向:
|
||
|
||
| Goal | Primary Change |
|
||
| --- | --- |
|
||
| 降成本 | 降 `target_rtp_ppm`,降补贴预算,提高高水位倍数 |
|
||
| 增刺激 | 增加高倍倍率,增房间气氛和活动预算 |
|
||
| 新手更友好 | 增加 0.2x/0.5x/1x 等小倍率,延长 `novice_draw_limit` |
|
||
| 防套利 | 降低用户/设备/房间/主播上限,关闭高倍 |
|
||
| RTP 更稳 | 缩小 RTP 窗口 |
|
||
| 体验更自然 | 放大 RTP 窗口,但接受短周期波动 |
|
||
|
||
## Data Tables
|
||
|
||
| Table | Owner Data |
|
||
| --- | --- |
|
||
| `lucky_gift_rules` | 按 `pool_id` 保存幸运礼物奖池规则和后台可调参数 |
|
||
| `lucky_rtp_windows` | 按 `pool_id` 保存 RTP 控制窗口 |
|
||
| `lucky_pools` | 按 `pool_id` 保存 platform / room / gift 三层基础奖池 |
|
||
| `lucky_room_atmosphere_pools` | 按 `pool_id + room_id` 保存房间气氛预算 |
|
||
| `lucky_activity_budgets` | 按 `pool_id` 保存活动补贴预算;`budget_day=__total__` 控总额,UTC 日期行控日释放 |
|
||
| `lucky_user_states` | 用户在单个 `pool_id` 内的累计付费抽数 |
|
||
| `lucky_risk_counters` | 按 `pool_id` 保存风控窗口计数 |
|
||
| `lucky_draw_records` | 每次抽奖事实和审计快照 |
|
||
|
||
## Verification
|
||
|
||
Proto 变更后必须运行:
|
||
|
||
```bash
|
||
PATH=/tmp/codex-protoc/bin:$HOME/go/bin:$PATH make proto
|
||
```
|
||
|
||
服务编译验证:
|
||
|
||
```bash
|
||
go test ./services/activity-service/...
|
||
```
|
||
|
||
模型验证:
|
||
|
||
```bash
|
||
go run ./tools/lucky-gift-v2-demo \
|
||
-users 1000 \
|
||
-devices 900 \
|
||
-rooms 50 \
|
||
-draws-min 0 \
|
||
-draws-max 100000 \
|
||
-unique-draws \
|
||
-base-rtp 95 \
|
||
-initial 1000000000 \
|
||
-cost 500 \
|
||
-global-window 100000 \
|
||
-gift-window 100000
|
||
```
|
||
|
||
验收口径:
|
||
|
||
| Check | Requirement |
|
||
| --- | --- |
|
||
| `100000` paid draws | 基础 RTP 偏差 `< 1%` |
|
||
| `1000000` paid draws | 基础 RTP 偏差 `< 0.5%` |
|
||
| lucky gift RTP | 幸运礼物整体子窗口独立收敛 |
|
||
| pool safety | 三层池不低于 reserve |
|
||
| subsidy isolation | 房间气氛/活动补贴不进入基础 RTP |
|
||
| idempotency | 重复 command_id 返回同一 draw |
|
||
|
||
## Rollout
|
||
|
||
建议上线顺序:
|
||
|
||
1. 后台创建规则草稿,`enabled=false`。
|
||
2. 跑模型模拟并审核参数。
|
||
3. 发布 `enabled=true` 到全局幸运礼物配置。
|
||
4. 只开放内部房间或白名单房间。
|
||
5. 观察 `base_rtp`、`effective_rtp`、pool balance、risk reject、outbox pending。
|
||
6. 稳定后逐步开放更多房间和礼物。
|
||
|
||
必须保留的开关:
|
||
|
||
| Switch | Effect |
|
||
| --- | --- |
|
||
| `enabled=false` | 全站幸运礼物停止抽奖 |
|
||
| `large_tier_enabled=false` | 关闭高倍奖档 |
|
||
| `activity_budget=0` | 关闭活动补贴 |
|
||
| `room_atmosphere_rate_ppm=0` | 关闭房间气氛补贴 |
|
||
| 降低各风控 cap | 快速压缩风险敞口 |
|