hyapp-server/api/proto/luckygift/v1/luckygift.proto

508 lines
16 KiB
Protocol Buffer
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

syntax = "proto3";
package hyapp.luckygift.v1;
option go_package = "hyapp.local/api/proto/luckygift/v1;luckygiftv1";
// RequestMeta 是 lucky-gift-service 的内部追踪元信息。
// request_id 只用于链路排查,不能被任何业务流程当成幂等键使用。
message RequestMeta {
string request_id = 1;
string caller = 2;
string gateway_node_id = 3;
int64 sent_at_ms = 4;
string app_code = 5;
}
// LuckyGiftMeta 是 HyApp 内部房间送礼扣费成功后的抽奖事实输入。
// 金额、目标用户和 command_id 必须来自 wallet-service 已落账的 receipt不能从客户端 payload 推导。
message LuckyGiftMeta {
RequestMeta meta = 1;
string command_id = 2;
int64 user_id = 3;
string device_id = 4;
string room_id = 5;
string anchor_id = 6;
string gift_id = 7;
int64 coin_spent = 8;
int64 paid_at_ms = 9;
string pool_id = 10;
int64 target_user_id = 11;
int32 gift_count = 12;
int64 visible_region_id = 13;
int64 country_id = 14;
// sender_* 是 room-service 在送礼入口已经确认的展示快照,只进入中奖事实和 IM不能参与抽奖或账务判断。
string sender_name = 15;
string sender_avatar = 16;
string sender_display_user_id = 17;
string sender_pretty_display_user_id = 18;
// 充值分层与充值后短时加权必须由调用方传入已确认的用户事实;幸运礼物服务不跨库回查用户或支付明细。
int64 recharge_7d_coins = 19;
int64 recharge_30d_coins = 20;
int64 last_recharged_at_ms = 21;
// gift_income_coins 是 wallet 已实际入账给收礼人的收益金币dynamic_v3 用它校验规则主播拆账,缺失或比例不一致均拒绝开奖。
int64 gift_income_coins = 22;
// user_registered_at_ms 是 user-service 在送礼入口返回的账号创建事实快照。
// dynamic_v3 只用它判断闭窗时账号是否已满 48 小时;缺失时普通开奖继续,但补偿大奖资格 fail-close。
int64 user_registered_at_ms = 23;
}
message LuckyGiftRuleTier {
string stage = 1;
string tier_id = 2;
int64 multiplier_ppm = 3;
int64 base_weight_ppm = 4;
bool high_water_only = 5;
bool enabled = 6;
}
message LuckyGiftRuleStage {
string stage = 1;
repeated LuckyGiftRuleTier tiers = 2;
// 两个充值门槛共同决定 dynamic_v3 分层novice 固定为 0/0后续阶段逐维单调递增。
int64 min_recharge_7d_coins = 3;
int64 min_recharge_30d_coins = 4;
}
message LuckyGiftRuleConfig {
string app_code = 1;
string pool_id = 2;
int64 rule_version = 3;
bool enabled = 4;
int64 target_rtp_ppm = 5;
int64 pool_rate_ppm = 6;
int64 settlement_window_wager = 7;
int64 control_band_ppm = 8;
int64 gift_price_reference = 9;
int64 novice_max_equivalent_draws = 10;
int64 normal_max_equivalent_draws = 11;
int64 effective_from_ms = 12;
int64 created_by_admin_id = 13;
int64 created_at_ms = 14;
repeated LuckyGiftRuleStage stages = 15;
// strategy_version 隔离历史 fixed_v2 与动态算法 dynamic_v3避免新增约束破坏已经发布的旧规则。
string strategy_version = 16;
int64 profit_rate_ppm = 17;
int64 anchor_rate_ppm = 18;
int64 initial_pool_coins = 19;
int64 loss_streak_guarantee = 20;
int64 low_watermark_coins = 21;
int64 low_water_nonzero_factor_ppm = 22;
int64 high_watermark_coins = 23;
int64 high_water_nonzero_factor_ppm = 24;
int64 recharge_boost_window_ms = 25;
int64 recharge_boost_factor_ppm = 26;
repeated int64 jackpot_multiplier_ppms = 27;
int64 jackpot_global_rtp_max_ppm = 28;
int64 jackpot_user_round_rtp_max_ppm = 29;
int64 jackpot_user_48h_rtp_max_ppm = 30;
// 用户在同一应用、奖池和 UTC 自然日每累计消费满该金币数,生成一次可跨日保留的消费大奖资格。
int64 jackpot_spend_threshold_coins = 31;
int64 max_jackpot_hits_per_user_day = 32;
int64 max_single_payout = 33;
int64 user_hourly_payout_cap = 34;
int64 user_daily_payout_cap = 35;
int64 device_daily_payout_cap = 36;
int64 room_hourly_payout_cap = 37;
int64 anchor_daily_payout_cap = 38;
// 用户严格滚动 24 小时 RTP 超过此值时普通非零奖档按下方因子降权0 表示关闭该策略。
int64 user_24h_rtp_threshold_ppm = 39;
// 触发用户 24 小时 RTP 降权后保留的普通中奖权重1000000 表示保持原概率。
int64 user_24h_ordinary_win_factor_ppm = 40;
}
message CheckLuckyGiftRequest {
RequestMeta meta = 1;
int64 user_id = 2;
string room_id = 3;
string gift_id = 4;
string pool_id = 5;
}
message CheckLuckyGiftResponse {
bool enabled = 1;
string reason = 2;
string gift_id = 3;
int64 gift_price = 4;
int64 rule_version = 5;
int64 target_rtp_ppm = 6;
string experience_pool = 7;
string pool_id = 8;
// strategy_version 由 lucky-gift owner 返回并由 room saga 固化,用于滚动发布时区分 fixed_v2 兼容与 dynamic_v3 强校验。
string strategy_version = 9;
}
message LuckyGiftDrawResult {
string draw_id = 1;
string command_id = 2;
string gift_id = 3;
int64 rule_version = 4;
string experience_pool = 5;
string selected_tier_id = 6;
int64 base_reward_coins = 7;
int64 effective_reward_coins = 8;
string reward_status = 9;
int64 rtp_window_index = 10;
int64 gift_rtp_window_index = 11;
int64 global_base_rtp_ppm = 12;
int64 gift_base_rtp_ppm = 13;
bool stage_feedback = 14;
bool high_multiplier = 15;
int64 created_at_ms = 16;
string pool_id = 17;
int64 multiplier_ppm = 18;
string wallet_transaction_id = 19;
int64 coin_balance_after = 20;
int64 user_id = 21;
string external_user_id = 22;
string app_code = 23;
repeated LuckyGiftHit hits = 24;
}
message ExecuteLuckyGiftDrawRequest {
LuckyGiftMeta lucky_gift = 1;
}
message ExecuteLuckyGiftDrawResponse {
LuckyGiftDrawResult result = 1;
}
message BatchExecuteLuckyGiftDrawRequest {
repeated LuckyGiftMeta lucky_gifts = 1;
}
message BatchExecuteLuckyGiftDrawResponse {
repeated LuckyGiftDrawResult results = 1;
}
// ExternalGiftDrawRequest 是外部 App 接入的抽奖输入。
// App 调用前必须已经完成自己的扣费lucky-gift-service 只校验金额事实并返回中奖结果。
message ExternalGiftDrawRequest {
RequestMeta meta = 1;
string app_code = 3;
string external_user_id = 4;
string request_id = 5;
int64 gift_count = 6;
int64 unit_amount = 7;
int64 total_amount = 8;
string currency = 9;
int64 paid_at_ms = 10;
string metadata_json = 11;
string pool_id = 12;
// dynamic_v3 必填的稳定设备作用域。luck-gateway 不独立证明其真实性,调用方必须在自己的认证/签名边界内绑定该值fixed_v2 允许缺失。
string device_id = 13;
// user_registered_at_ms 由外部 App 按自己的用户主数据提供dynamic_v3 缺失或晚于支付时间时补偿大奖资格 fail-close。
int64 user_registered_at_ms = 14;
}
message ExternalGiftDrawResponse {
string draw_id = 1;
string request_id = 2;
string app_code = 4;
string external_user_id = 5;
int64 gift_count = 6;
int64 unit_amount = 7;
int64 total_amount = 8;
int64 reward_amount = 9;
int64 multiplier_ppm = 10;
string reward_status = 11;
int64 rule_version = 12;
int64 created_at_ms = 13;
}
message GetLuckyGiftConfigRequest {
RequestMeta meta = 1;
string pool_id = 2;
}
message GetLuckyGiftConfigResponse {
LuckyGiftRuleConfig config = 1;
}
message UpsertLuckyGiftConfigRequest {
RequestMeta meta = 1;
LuckyGiftRuleConfig config = 2;
int64 operator_admin_id = 3;
}
message UpsertLuckyGiftConfigResponse {
LuckyGiftRuleConfig config = 1;
}
message ListLuckyGiftConfigsRequest {
RequestMeta meta = 1;
}
message ListLuckyGiftConfigsResponse {
repeated LuckyGiftRuleConfig configs = 1;
}
message ListLuckyGiftDrawsRequest {
RequestMeta meta = 1;
string gift_id = 2;
int64 user_id = 3;
string room_id = 4;
string status = 5;
int32 page = 6;
int32 page_size = 7;
string pool_id = 8;
string external_user_id = 10;
bool external_only = 11;
}
message ListLuckyGiftDrawsResponse {
repeated LuckyGiftDrawResult draws = 1;
int64 total = 2;
}
message LuckyGiftDrawSummary {
string pool_id = 1;
int64 total_draws = 2;
int64 unique_users = 3;
int64 unique_rooms = 4;
int64 total_spent_coins = 5;
int64 total_reward_coins = 6;
int64 base_reward_coins = 7;
int64 actual_rtp_ppm = 8;
int64 pending_draws = 9;
int64 granted_draws = 10;
int64 failed_draws = 11;
}
message LuckyGiftPoolBalance {
string app_code = 1;
string pool_id = 2;
int64 balance = 3;
int64 reserve_floor = 4;
int64 available_balance = 5;
int64 total_in = 6;
int64 total_out = 7;
bool materialized = 8;
int64 updated_at_ms = 9;
string strategy_version = 10;
int64 manual_credit_total = 11;
int64 manual_debit_total = 12;
}
message GetLuckyGiftDrawSummaryRequest {
RequestMeta meta = 1;
string gift_id = 2;
int64 user_id = 3;
string room_id = 4;
string status = 5;
string pool_id = 6;
string external_user_id = 8;
bool external_only = 9;
}
message GetLuckyGiftDrawSummaryResponse {
LuckyGiftDrawSummary summary = 1;
}
message ListLuckyGiftPoolBalancesRequest {
RequestMeta meta = 1;
string pool_id = 2;
string strategy_version = 3;
}
message ListLuckyGiftPoolBalancesResponse {
repeated LuckyGiftPoolBalance pools = 1;
}
service LuckyGiftService {
rpc CheckLuckyGift(CheckLuckyGiftRequest) returns (CheckLuckyGiftResponse);
rpc ExecuteLuckyGiftDraw(ExecuteLuckyGiftDrawRequest) returns (ExecuteLuckyGiftDrawResponse);
rpc BatchExecuteLuckyGiftDraw(BatchExecuteLuckyGiftDrawRequest) returns (BatchExecuteLuckyGiftDrawResponse);
rpc ExecuteExternalGiftDraw(ExternalGiftDrawRequest) returns (ExternalGiftDrawResponse);
}
service AdminLuckyGiftService {
rpc GetLuckyGiftConfig(GetLuckyGiftConfigRequest) returns (GetLuckyGiftConfigResponse);
rpc UpsertLuckyGiftConfig(UpsertLuckyGiftConfigRequest) returns (UpsertLuckyGiftConfigResponse);
rpc ListLuckyGiftConfigs(ListLuckyGiftConfigsRequest) returns (ListLuckyGiftConfigsResponse);
rpc ListLuckyGiftDraws(ListLuckyGiftDrawsRequest) returns (ListLuckyGiftDrawsResponse);
rpc GetLuckyGiftDrawSummary(GetLuckyGiftDrawSummaryRequest) returns (GetLuckyGiftDrawSummaryResponse);
rpc ListLuckyGiftPoolBalances(ListLuckyGiftPoolBalancesRequest) returns (ListLuckyGiftPoolBalancesResponse);
rpc AdjustLuckyGiftPoolBalance(AdjustLuckyGiftPoolBalanceRequest) returns (AdjustLuckyGiftPoolBalanceResponse);
rpc ListLuckyGiftUserProfiles(ListLuckyGiftUserProfilesRequest) returns (ListLuckyGiftUserProfilesResponse);
rpc GetLuckyGiftUserProfile(GetLuckyGiftUserProfileRequest) returns (GetLuckyGiftUserProfileResponse);
}
// LuckyGiftHit 只返回批量逐份开奖中实际中奖的精简位置,不复制全部审计明细。
// 声明追加在文件尾以保持既有 protobuf message index 稳定。
message LuckyGiftHit {
int32 gift_index = 1;
string draw_id = 2;
string selected_tier_id = 3;
int64 multiplier_ppm = 4;
int64 reward_coins = 5;
}
// 调账消息也只追加在文件尾,保持所有既有 protobuf message index 稳定。
// adjustment_id 是业务幂等键RequestMeta.request_id 只做链路追踪,不能替代资金幂等语义。
message AdjustLuckyGiftPoolBalanceRequest {
RequestMeta meta = 1;
string pool_id = 2;
string strategy_version = 3;
string adjustment_id = 4;
string direction = 5;
int64 amount_coins = 6;
string reason = 7;
int64 operator_admin_id = 8;
}
message LuckyGiftPoolAdjustment {
string adjustment_id = 1;
string app_code = 2;
string pool_id = 3;
string strategy_version = 4;
string direction = 5;
int64 amount_coins = 6;
string reason = 7;
int64 operator_admin_id = 8;
int64 balance_before = 9;
int64 balance_after = 10;
int64 created_at_ms = 11;
}
message AdjustLuckyGiftPoolBalanceResponse {
LuckyGiftPoolAdjustment adjustment = 1;
LuckyGiftPoolBalance pool = 2;
bool idempotent_replay = 3;
}
// 用户画像协议追加在文件尾,避免改变既有 message index。外部策略哈希只存在于 owner 数据库,
// 本协议永远只下发 external_user_id防止运营误把不可逆内部键当成外部用户身份。
message LuckyGiftUserProfileWindow {
int64 draws = 1;
int64 wager_coins = 2;
int64 payout_coins = 3;
int64 net_coins = 4;
int64 rtp_ppm = 5;
bool has_rtp = 6;
}
message LuckyGiftUserProfile {
string app_code = 1;
string pool_id = 2;
string identity_type = 3;
int64 internal_user_id = 4;
string external_user_id = 5;
int64 rule_version = 6;
string strategy_version = 7;
string stage = 8;
int64 paid_draws = 9;
int64 equivalent_draws = 10;
int64 loss_streak = 11;
int64 pending_spend_jackpot_tokens = 12;
int64 guarantee_draws_remaining = 13;
bool downweight_active = 14;
int64 downweight_factor_ppm = 15;
LuckyGiftUserProfileWindow one_hour = 16;
LuckyGiftUserProfileWindow twenty_four_hours = 17;
LuckyGiftUserProfileWindow forty_eight_hours = 18;
LuckyGiftUserProfileWindow lifetime = 19;
int64 base_reward_coins = 20;
int64 ordinary_win_count = 21;
int64 high_multiplier_ordinary_win_count = 22;
int64 rtp_compensation_jackpot_count = 23;
int64 cumulative_spend_jackpot_count = 24;
int64 guarantee_hit_count = 25;
int64 zero_draw_count = 26;
int64 granted_draw_count = 27;
int64 pending_draw_count = 28;
int64 failed_draw_count = 29;
int64 max_multiplier_ppm = 30;
int64 max_reward_coins = 31;
int64 first_draw_at_ms = 32;
int64 last_draw_at_ms = 33;
int64 aggregated_at_ms = 34;
int64 data_lag_ms = 35;
int64 user_24h_rtp_threshold_ppm = 36;
}
message ListLuckyGiftUserProfilesRequest {
RequestMeta meta = 1;
string pool_id = 2;
string identity_type = 3;
int64 internal_user_id = 4;
string external_user_id = 5;
string stage = 6;
string status = 7;
string sort_by = 8;
string sort_direction = 9;
int32 page = 10;
int32 page_size = 11;
// cursor 是 owner service 生成的不透明 keyset 游标page 仅保留旧客户端协议兼容,服务端不再执行 OFFSET。
string cursor = 12;
}
message ListLuckyGiftUserProfilesResponse {
repeated LuckyGiftUserProfile profiles = 1;
int64 total = 2;
int64 snapshot_at_ms = 3;
string next_cursor = 4;
bool has_more = 5;
}
message GetLuckyGiftUserProfileRequest {
RequestMeta meta = 1;
string pool_id = 2;
string identity_type = 3;
int64 internal_user_id = 4;
string external_user_id = 5;
int32 jackpot_page = 6;
int32 jackpot_page_size = 7;
// jackpot_cursor 由上一页 next_jackpot_cursor 原样返回jackpot_page 仅保留协议兼容。
string jackpot_cursor = 8;
}
message LuckyGiftUserMultiplierStat {
string hit_type = 1;
int64 multiplier_ppm = 2;
int64 draw_count = 3;
int64 wager_coins = 4;
int64 payout_coins = 5;
}
message LuckyGiftUserJackpotCondition {
string name = 1;
int64 numerator = 2;
int64 denominator = 3;
int64 ratio_ppm = 4;
int64 limit_ppm = 5;
int64 factor_ppm = 6;
bool passed = 7;
string reason = 8;
}
message LuckyGiftUserJackpotHit {
string draw_id = 1;
string request_id = 2;
int64 rule_version = 3;
string stage = 4;
string mechanism = 5;
string reason_code = 6;
string reason_summary = 7;
string tier_id = 8;
int64 multiplier_ppm = 9;
int64 wager_coins = 10;
int64 payout_coins = 11;
int64 occurred_at_ms = 12;
repeated LuckyGiftUserJackpotCondition conditions = 13;
// event_key 只标识这条画像大奖事实,供前端稳定追加去重;不包含用户策略键或用户哈希。
string event_key = 14;
}
message GetLuckyGiftUserProfileResponse {
LuckyGiftUserProfile profile = 1;
repeated LuckyGiftUserMultiplierStat multiplier_distribution = 2;
repeated LuckyGiftUserJackpotHit jackpot_hits = 3;
int64 jackpot_hit_total = 4;
int64 snapshot_at_ms = 5;
int32 jackpot_page = 6;
int32 jackpot_page_size = 7;
string next_jackpot_cursor = 8;
bool jackpot_has_more = 9;
}