6.5 KiB
6.5 KiB
幸运礼物重构第一步:配置契约与单位
本文档定义幸运礼物重构第一步。第一步只解决配置、单位、规则版本和后台发布校验,不实现新抽奖算法。当前处于开发阶段,不兼容旧代码,不保留旧的 target_rtp_ppm=95、旧 tiers.weight=0 自动权重模型,也不继续把 lucky_gift_rules.gift_id 当作奖池 ID 使用。
目标
| 目标 | 说明 |
|---|---|
| 消灭单位歧义 | 后台展示百分比和倍数,服务端持久化 ppm |
| 明确规则 owner | activity-service 拥有幸运礼物规则、奖档、RTP 参数和版本 |
| 按阶段配置体验 | novice/normal/advanced 各自拥有独立奖档概率 |
| 发布前校验 | 配置无法满足成本或体验边界时拒绝发布 |
| 为第二步抽奖引擎铺路 | 输出可直接被 v2 抽奖引擎读取的规则快照 |
删除旧模型
| 旧模型 | 新处理 |
|---|---|
后台直接提交 target_rtp_ppm=95 |
改为后台提交 target_rtp_percent=95,服务端转换为 950000 |
后台提交倍数 0.3 后直接存 0.3 |
服务端保存 multiplier_ppm=300000 |
lucky_gift_rules.gift_id 表示奖池 |
新表使用显式 pool_id |
单一 multiplier_ppms 生成三个阶段相同奖档 |
三个阶段分别配置奖档和权重 |
tiers.weight=0,运行时自动权重 |
后台必须配置基础概率,抽奖引擎只做控制调整 |
新配置字段
规则主表
建议新建 lucky_gift_rule_versions。
| 字段 | 类型 | 说明 |
|---|---|---|
app_code |
string | App 编码 |
pool_id |
string | 幸运礼物奖池 ID |
rule_version |
int64 | 规则版本,每次发布递增 |
enabled |
bool | 是否启用 |
target_rtp_ppm |
int64 | 基础返奖目标,95% = 950000 |
pool_rate_ppm |
int64 | 每笔扣费进入基础奖池比例 |
settlement_window_wager |
int64 | RTP 结算窗口流水,单位金币 |
control_band_ppm |
int64 | 正常波动带,10000 = ±1% |
gift_price_reference |
int64 | 配置参考礼物价格 |
effective_from_ms |
int64 | 生效时间,UTC epoch ms |
created_by_admin_id |
int64 | 发布人 |
created_at_ms |
int64 | 创建时间 |
阶段奖档表
建议新建 lucky_gift_stage_tiers。
| 字段 | 类型 | 说明 |
|---|---|---|
app_code |
string | App 编码 |
pool_id |
string | 奖池 ID |
rule_version |
int64 | 规则版本 |
stage |
string | novice/normal/advanced |
tier_id |
string | 奖档 ID |
multiplier_ppm |
int64 | 倍率,1x = 1000000 |
base_weight_ppm |
int64 | 正常模式基础概率 |
reward_source |
string | base_rtp/activity_subsidy/presentation_only |
high_water_only |
bool | 是否高水位才开放 |
broadcast_level |
string | none/room/region/global |
enabled |
bool | 是否启用 |
后台输入格式
后台对运营展示和提交应使用易懂单位:
{
"pool_id": "lucky_100",
"enabled": true,
"target_rtp_percent": 95,
"pool_rate_percent": 96,
"settlement_window_wager": 1000000,
"control_band_percent": 1,
"gift_price_reference": 100,
"stages": [
{
"stage": "novice",
"tiers": [
{"tier_id": "novice_none", "multiplier": 0, "probability_percent": 30},
{"tier_id": "novice_0_3x", "multiplier": 0.3, "probability_percent": 22},
{"tier_id": "novice_0_5x", "multiplier": 0.5, "probability_percent": 18}
]
}
]
}
服务端保存前转换:
target_rtp_percent=95 -> target_rtp_ppm=950000
pool_rate_percent=96 -> pool_rate_ppm=960000
control_band_percent=1 -> control_band_ppm=10000
multiplier=0.3 -> multiplier_ppm=300000
probability_percent=22 -> base_weight_ppm=220000
发布校验
| 校验项 | 规则 | 失败处理 |
|---|---|---|
| RTP 单位 | 100000 <= target_rtp_ppm <= 990000 |
拒绝发布 |
| 入池比例 | pool_rate_ppm >= target_rtp_ppm 且 pool_rate_ppm <= 1000000 |
拒绝发布 |
| 波动带 | 0 < control_band_ppm <= 50000 |
拒绝发布 |
| 参考价格 | gift_price_reference > 0 |
拒绝发布 |
| 阶段完整 | 必须有 novice/normal/advanced 三个阶段 |
拒绝发布 |
| 阶段概率 | 每个阶段 sum(base_weight_ppm) == 1000000 |
拒绝发布 |
| 倍率合法 | multiplier_ppm >= 0 |
拒绝发布 |
| 基础奖档 | 每个阶段至少有一个 base_rtp 奖档 |
拒绝发布 |
| 未中奖档 | 每个阶段必须显式配置 0x,除非标记为“每抽必返” |
拒绝发布或强确认 |
| 高倍档 | high_water_only=true 或有明确单次上限 |
拒绝发布 |
API 调整
后台接口只暴露业务单位:
| 接口 | 行为 |
|---|---|
GET /api/v1/admin/activity/lucky-gifts/config?pool_id=... |
返回百分比、倍数和阶段奖档 |
PUT /api/v1/admin/activity/lucky-gifts/config?pool_id=... |
发布新版本,服务端转换 ppm 并校验 |
GET /api/v1/admin/activity/lucky-gifts/configs |
列出所有奖池和当前版本 |
内部 gRPC 可以继续使用 ppm,但字段名必须明确:
| 字段 | 说明 |
|---|---|
target_rtp_ppm |
内部字段,后台 HTTP 不直接要求运营填写 |
pool_rate_ppm |
内部字段 |
multiplier_ppm |
内部字段 |
base_weight_ppm |
内部字段 |
实施任务
- 新增 v2 proto:规则、阶段、奖档、发布请求、读取响应。
- 新增 MySQL v2 表。
- 改后台 lucky gift handler,只接收百分比和倍数。
- 在
activity-service增加配置转换和发布校验。 - 删除或旁路旧
multiplier_ppms -> tiers(weight=0)归一化模型。 - 增加配置单元测试和 schema 初始化。
验收标准
| 验收项 | 标准 |
|---|---|
| 单位转换 | 后台提交 target_rtp_percent=95 后,DB 保存 target_rtp_ppm=950000 |
| 倍率转换 | 后台提交 multiplier=0.3 后,DB 保存 multiplier_ppm=300000 |
| 概率转换 | 后台提交 probability_percent=22 后,DB 保存 base_weight_ppm=220000 |
| 错误 RTP | 后台提交等价 target_rtp_ppm=95 的配置必须被拒绝 |
| 阶段概率 | 任一阶段概率和不是 100% 时必须被拒绝 |
| 旧字段隔离 | 新规则表不再使用 gift_id 表示 pool_id |
| 版本不可变 | 发布新配置只新增 rule_version,不覆盖历史版本 |
| 测试 | go test ./services/activity-service/internal/service/luckygift ./services/activity-service/internal/storage/mysql ./server/admin/internal/modules/luckygift 通过 |
第一步完成后,系统只具备“正确配置和发布规则”的能力,不要求新抽奖引擎上线。