滞回标志按 app+pool 单行存储且由每个用户钉住的组内配置推进; 两组三元组不同(尤其 control 关/treatment 开的灰度形态)会互踩: control 逐抽清掉 treatment 的标志,阈值不同的组按对方状态加权付奖。 加权特性的灰度必须走常规发布,不能走实验。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
569 lines
21 KiB
Go
569 lines
21 KiB
Go
package luckygift
|
||
|
||
const (
|
||
DefaultPoolID = "default"
|
||
|
||
StatusDraft = "draft"
|
||
StatusActive = "active"
|
||
StatusPaused = "paused"
|
||
StatusClosed = "closed"
|
||
StatusPending = "pending"
|
||
StatusGranted = "granted"
|
||
StatusFailed = "failed"
|
||
|
||
PoolNovice = "novice"
|
||
PoolIntermediate = "intermediate"
|
||
PoolAdvanced = "advanced"
|
||
|
||
StageNovice = "novice"
|
||
StageNormal = "normal"
|
||
StageAdvanced = "advanced"
|
||
|
||
// StrategyFixedV2 保留现网不可变规则的原始语义;只有显式发布 StrategyDynamicV3 才启用动态水位、充值加权和多维风控。
|
||
StrategyFixedV2 = "fixed_v2"
|
||
StrategyDynamicV3 = "dynamic_v3"
|
||
|
||
PoolAdjustmentIn = "in"
|
||
PoolAdjustmentOut = "out"
|
||
|
||
EventTypeLuckyGiftDrawn = "LuckyGiftDrawn"
|
||
EventTypeLuckyGiftRewardSettlement = "LuckyGiftRewardSettlement"
|
||
EventTypeExternalLuckyGiftDrawn = "ExternalLuckyGiftDrawn"
|
||
)
|
||
|
||
// Tier 是单个体验池里的候选奖档;权重只塑造体验节奏,基础成本仍由 RTP 窗口兜住。
|
||
type Tier struct {
|
||
Pool string `json:"pool"`
|
||
TierID string `json:"tier_id"`
|
||
RewardCoins int64 `json:"reward_coins"`
|
||
MultiplierPPM int64 `json:"multiplier_ppm"`
|
||
Weight int64 `json:"weight"`
|
||
HighWaterOnly bool `json:"high_water_only"`
|
||
Enabled bool `json:"enabled"`
|
||
}
|
||
|
||
// Config 是幸运礼物线上规则快照。金额均为整数金币,比例均为 ppm。
|
||
type Config struct {
|
||
AppCode string `json:"app_code"`
|
||
GiftID string `json:"gift_id"`
|
||
PoolID string `json:"pool_id"`
|
||
Enabled bool `json:"enabled"`
|
||
RuleVersion int64 `json:"rule_version"`
|
||
StrategyVersion string `json:"strategy_version"`
|
||
GiftPrice int64 `json:"gift_price"`
|
||
TargetRTPPPM int64 `json:"target_rtp_ppm"`
|
||
PoolRatePPM int64 `json:"pool_rate_ppm"`
|
||
ProfitRatePPM int64 `json:"profit_rate_ppm"`
|
||
AnchorRatePPM int64 `json:"anchor_rate_ppm"`
|
||
ControlBandPPM int64 `json:"control_band_ppm"`
|
||
// SettlementWindowWager 是 dynamic_v3 结算窗口的真实金币流水阈值;不能按参考礼物价格换算成抽数。
|
||
SettlementWindowWager int64 `json:"settlement_window_wager"`
|
||
GlobalWindowDraws int64 `json:"global_window_draws"`
|
||
GiftWindowDraws int64 `json:"gift_window_draws"`
|
||
NoviceMaxEquivalentDraws int64 `json:"novice_max_equivalent_draws"`
|
||
NormalMaxEquivalentDraws int64 `json:"normal_max_equivalent_draws"`
|
||
HighMultiplier int64 `json:"high_multiplier"`
|
||
HighWaterPoolMultiple int64 `json:"high_water_pool_multiple"`
|
||
InitialBasePool int64 `json:"initial_base_pool"`
|
||
BasePoolReserve int64 `json:"base_pool_reserve"`
|
||
InitialPoolCoins int64 `json:"initial_pool_coins"`
|
||
LossStreakGuarantee int64 `json:"loss_streak_guarantee"`
|
||
LowWatermarkCoins int64 `json:"low_watermark_coins"`
|
||
LowWaterNonzeroFactorPPM int64 `json:"low_water_nonzero_factor_ppm"`
|
||
HighWatermarkCoins int64 `json:"high_watermark_coins"`
|
||
HighWaterNonzeroFactorPPM int64 `json:"high_water_nonzero_factor_ppm"`
|
||
// V2HighWaterBoost* 只由 fixed_v2 解释:奖池水位越过阈值后,中奖返奖金额按系数加权(RTP 等比放大),
|
||
// 滞回保持到水位跌破恢复线才退出;阈值为 0 表示关闭。dynamic_v3 有独立水位因子,不读这三个字段。
|
||
V2HighWaterBoostThresholdCoins int64 `json:"v2_high_water_boost_threshold_coins"`
|
||
V2HighWaterBoostFactorPPM int64 `json:"v2_high_water_boost_factor_ppm"`
|
||
V2HighWaterBoostRecoverCoins int64 `json:"v2_high_water_boost_recover_coins"`
|
||
RechargeBoostWindowMS int64 `json:"recharge_boost_window_ms"`
|
||
RechargeBoostFactorPPM int64 `json:"recharge_boost_factor_ppm"`
|
||
// User24HourRTPThresholdPPM/Factor 只调整普通非零奖档;大奖资格和保底仍由各自策略独立决定。
|
||
User24HourRTPThresholdPPM int64 `json:"user_24h_rtp_threshold_ppm"`
|
||
User24HourOrdinaryWinFactorPPM int64 `json:"user_24h_ordinary_win_factor_ppm"`
|
||
JackpotMultiplierPPMs []int64 `json:"jackpot_multiplier_ppms"`
|
||
JackpotGlobalRTPMaxPPM int64 `json:"jackpot_global_rtp_max_ppm"`
|
||
JackpotUserRoundRTPMaxPPM int64 `json:"jackpot_user_round_rtp_max_ppm"`
|
||
JackpotUser48hRTPMaxPPM int64 `json:"jackpot_user_48h_rtp_max_ppm"`
|
||
// Deprecated aliases only keep in-process callers built against the previous draft source-compatible.
|
||
// Persistence, protobuf and runtime decisions use the round/48h fields above; these aliases never create a second rule meaning.
|
||
JackpotUserDayRTPMaxPPM int64 `json:"-"`
|
||
JackpotUser72hRTPMaxPPM int64 `json:"-"`
|
||
// SettledRoundRTPEligibility marks configs received through the round/48h contract.
|
||
// It is transport metadata only: persistence stores the two canonical limits and reconstructs this marker on read.
|
||
SettledRoundRTPEligibility bool `json:"-"`
|
||
JackpotSpendThresholdCoins int64 `json:"jackpot_spend_threshold_coins"`
|
||
MaxJackpotHitsPerUserDay int64 `json:"max_jackpot_hits_per_user_day"`
|
||
MaxSinglePayout int64 `json:"max_single_payout"`
|
||
UserHourlyPayoutCap int64 `json:"user_hourly_payout_cap"`
|
||
UserDailyPayoutCap int64 `json:"user_daily_payout_cap"`
|
||
DeviceDailyPayoutCap int64 `json:"device_daily_payout_cap"`
|
||
RoomHourlyPayoutCap int64 `json:"room_hourly_payout_cap"`
|
||
AnchorDailyPayoutCap int64 `json:"anchor_daily_payout_cap"`
|
||
MultiplierPPMs []int64 `json:"multiplier_ppms"`
|
||
// Stages 保留 dynamic_v3 的充值门槛;Tiers 仍是 fixed_v2 候选选择使用的扁平运行结构。
|
||
Stages []RuleStage `json:"stages"`
|
||
Tiers []Tier `json:"tiers"`
|
||
UpdatedByAdminID int64 `json:"updated_by_admin_id"`
|
||
CreatedAtMS int64 `json:"created_at_ms"`
|
||
UpdatedAtMS int64 `json:"updated_at_ms"`
|
||
}
|
||
|
||
// RuleTier 是 v2 配置契约里的阶段奖档。倍率和概率在服务端内部统一用 ppm 保存。
|
||
type RuleTier struct {
|
||
Stage string `json:"stage"`
|
||
TierID string `json:"tier_id"`
|
||
MultiplierPPM int64 `json:"multiplier_ppm"`
|
||
BaseWeightPPM int64 `json:"base_weight_ppm"`
|
||
HighWaterOnly bool `json:"high_water_only"`
|
||
Enabled bool `json:"enabled"`
|
||
}
|
||
|
||
// RuleStage 保存某个用户阶段的完整奖档概率。每个阶段的基础概率必须合计 1000000。
|
||
type RuleStage struct {
|
||
Stage string `json:"stage"`
|
||
// novice 的两个 0 仅为协议/存储 sentinel;normal/advanced 才用这两个下限提档。
|
||
MinRecharge7DCoins int64 `json:"min_recharge_7d_coins"`
|
||
MinRecharge30DCoins int64 `json:"min_recharge_30d_coins"`
|
||
Tiers []RuleTier `json:"tiers"`
|
||
}
|
||
|
||
// RuleConfig 是幸运礼物不可变配置版本快照。fixed_v2 与 dynamic_v3 共用基础 RTP 契约,动态字段只由后者解释;
|
||
// 比例和倍率统一使用 ppm,后台百分比/倍率业务单位只在发布入口转换。
|
||
type RuleConfig struct {
|
||
AppCode string `json:"app_code"`
|
||
PoolID string `json:"pool_id"`
|
||
RuleVersion int64 `json:"rule_version"`
|
||
StrategyVersion string `json:"strategy_version"`
|
||
Enabled bool `json:"enabled"`
|
||
TargetRTPPPM int64 `json:"target_rtp_ppm"`
|
||
PoolRatePPM int64 `json:"pool_rate_ppm"`
|
||
ProfitRatePPM int64 `json:"profit_rate_ppm"`
|
||
AnchorRatePPM int64 `json:"anchor_rate_ppm"`
|
||
SettlementWindowWager int64 `json:"settlement_window_wager"`
|
||
ControlBandPPM int64 `json:"control_band_ppm"`
|
||
GiftPriceReference int64 `json:"gift_price_reference"`
|
||
NoviceMaxEquivalentDraws int64 `json:"novice_max_equivalent_draws"`
|
||
NormalMaxEquivalentDraws int64 `json:"normal_max_equivalent_draws"`
|
||
EffectiveFromMS int64 `json:"effective_from_ms"`
|
||
CreatedByAdminID int64 `json:"created_by_admin_id"`
|
||
CreatedAtMS int64 `json:"created_at_ms"`
|
||
InitialPoolCoins int64 `json:"initial_pool_coins"`
|
||
LossStreakGuarantee int64 `json:"loss_streak_guarantee"`
|
||
LowWatermarkCoins int64 `json:"low_watermark_coins"`
|
||
LowWaterNonzeroFactorPPM int64 `json:"low_water_nonzero_factor_ppm"`
|
||
HighWatermarkCoins int64 `json:"high_watermark_coins"`
|
||
HighWaterNonzeroFactorPPM int64 `json:"high_water_nonzero_factor_ppm"`
|
||
// V2HighWaterBoost* 是 fixed_v2 专属的高水位返奖加权三元组;0/0/0 表示关闭(历史版本反序列化默认值)。
|
||
V2HighWaterBoostThresholdCoins int64 `json:"v2_high_water_boost_threshold_coins"`
|
||
V2HighWaterBoostFactorPPM int64 `json:"v2_high_water_boost_factor_ppm"`
|
||
V2HighWaterBoostRecoverCoins int64 `json:"v2_high_water_boost_recover_coins"`
|
||
RechargeBoostWindowMS int64 `json:"recharge_boost_window_ms"`
|
||
RechargeBoostFactorPPM int64 `json:"recharge_boost_factor_ppm"`
|
||
// 0/100% 是历史兼容 sentinel;阈值大于 0 时,factor 表示触发后保留的普通中奖权重。
|
||
User24HourRTPThresholdPPM int64 `json:"user_24h_rtp_threshold_ppm"`
|
||
User24HourOrdinaryWinFactorPPM int64 `json:"user_24h_ordinary_win_factor_ppm"`
|
||
JackpotMultiplierPPMs []int64 `json:"jackpot_multiplier_ppms"`
|
||
JackpotGlobalRTPMaxPPM int64 `json:"jackpot_global_rtp_max_ppm"`
|
||
JackpotUserRoundRTPMaxPPM int64 `json:"jackpot_user_round_rtp_max_ppm"`
|
||
JackpotUser48hRTPMaxPPM int64 `json:"jackpot_user_48h_rtp_max_ppm"`
|
||
// Deprecated aliases are normalized at service/repository boundaries and are never persisted as separate values.
|
||
JackpotUserDayRTPMaxPPM int64 `json:"-"`
|
||
JackpotUser72hRTPMaxPPM int64 `json:"-"`
|
||
SettledRoundRTPEligibility bool `json:"-"`
|
||
JackpotSpendThresholdCoins int64 `json:"jackpot_spend_threshold_coins"`
|
||
MaxJackpotHitsPerUserDay int64 `json:"max_jackpot_hits_per_user_day"`
|
||
MaxSinglePayout int64 `json:"max_single_payout"`
|
||
UserHourlyPayoutCap int64 `json:"user_hourly_payout_cap"`
|
||
UserDailyPayoutCap int64 `json:"user_daily_payout_cap"`
|
||
DeviceDailyPayoutCap int64 `json:"device_daily_payout_cap"`
|
||
RoomHourlyPayoutCap int64 `json:"room_hourly_payout_cap"`
|
||
AnchorDailyPayoutCap int64 `json:"anchor_daily_payout_cap"`
|
||
Stages []RuleStage `json:"stages"`
|
||
}
|
||
|
||
type CheckCommand struct {
|
||
PoolID string
|
||
GiftID string
|
||
UserID int64
|
||
RoomID string
|
||
}
|
||
|
||
type DrawCommand struct {
|
||
CommandID string
|
||
PoolID string
|
||
UserID int64
|
||
TargetUserID int64
|
||
DeviceID string
|
||
RoomID string
|
||
AnchorID string
|
||
GiftID string
|
||
GiftCount int32
|
||
CoinSpent int64
|
||
PaidAtMS int64
|
||
// UserRegisteredAtMS is the user owner snapshot captured by gateway at the original gift request.
|
||
// Zero is tolerated for an old recovered command but makes the 48-hour jackpot maturity gate fail closed.
|
||
UserRegisteredAtMS int64
|
||
VisibleRegionID int64
|
||
CountryID int64
|
||
Recharge7DCoins int64
|
||
Recharge30DCoins int64
|
||
LastRechargedAtMS int64
|
||
GiftIncomeCoins int64
|
||
// Sender* 是扣费时刻的公开展示快照;owner outbox 必须携带快照,避免下游为一条飘屏同步反查 user-service。
|
||
SenderName string
|
||
SenderAvatar string
|
||
SenderDisplayUserID string
|
||
SenderPrettyDisplayUserID string
|
||
}
|
||
|
||
type CheckResult struct {
|
||
Enabled bool
|
||
Reason string
|
||
PoolID string
|
||
GiftID string
|
||
GiftPrice int64
|
||
RuleVersion int64
|
||
StrategyVersion string
|
||
TargetRTPPPM int64
|
||
ExperiencePool string
|
||
}
|
||
|
||
type DrawResult struct {
|
||
DrawID string
|
||
DrawIDs []string
|
||
CommandID string
|
||
AppCode string
|
||
UserID int64
|
||
ExternalUserID string
|
||
PoolID string
|
||
GiftID string
|
||
RuleVersion int64
|
||
ExperiencePool string
|
||
SelectedTierID string
|
||
MultiplierPPM int64
|
||
BaseRewardCoins int64
|
||
EffectiveRewardCoins int64
|
||
RewardStatus string
|
||
RTPWindowIndex int64
|
||
GiftRTPWindowIndex int64
|
||
GlobalBaseRTPPPM int64
|
||
GiftBaseRTPPPM int64
|
||
StageFeedback bool
|
||
HighMultiplier bool
|
||
CreatedAtMS int64
|
||
WalletTransactionID string
|
||
CoinBalanceAfter int64
|
||
// Hits 只保留 gift_count 批量中的中奖子抽,避免为了连击表现把所有 999 条审计记录塞进同步响应。
|
||
Hits []DrawHit
|
||
}
|
||
|
||
type DrawHit struct {
|
||
GiftIndex int32
|
||
DrawID string
|
||
SelectedTierID string
|
||
MultiplierPPM int64
|
||
RewardCoins int64
|
||
}
|
||
|
||
type DrawSummary struct {
|
||
PoolID string
|
||
TotalDraws int64
|
||
UniqueUsers int64
|
||
UniqueRooms int64
|
||
TotalSpentCoins int64
|
||
TotalRewardCoins int64
|
||
BaseRewardCoins int64
|
||
ActualRTPPPM int64
|
||
PendingDraws int64
|
||
GrantedDraws int64
|
||
FailedDraws int64
|
||
}
|
||
|
||
// DailyStatsQuery 是 Databi 按日聚合的查询输入;只读 lucky_draw_pool_day_stats 读模型,
|
||
// [StartMS, EndMS) 由存储层按北京日(+08:00)换算成 stat_day 闭区间。
|
||
type DailyStatsQuery struct {
|
||
AppCode string
|
||
// PoolID 为空表示全部奖池。
|
||
PoolID string
|
||
// StrategyVersion 为空表示不按策略过滤;否则必须是 fixed_v2 / dynamic_v3。
|
||
StrategyVersion string
|
||
StartMS int64
|
||
EndMS int64
|
||
// RegionIDs 为空表示全部区域(含 GLOBAL=0 房间);非空时按房间可见区域过滤。
|
||
RegionIDs []int64
|
||
}
|
||
|
||
// DailyStat 是单个北京日的抽奖汇总;口径与 DrawSummary 一致:
|
||
// payout 用用户可见返奖(effective),不按 reward_status 过滤。
|
||
type DailyStat struct {
|
||
StatDay string
|
||
DrawCount int64
|
||
TurnoverCoin int64
|
||
PayoutCoin int64
|
||
BaseRewardCoin int64
|
||
}
|
||
|
||
// PoolBalance 是后台看到的 app+pool_id 单池账本快照。
|
||
// materialized=false 表示该池还没有真实 lucky_pools 行,展示的是规则默认初始水位,不能当成已经入库的资金流水。
|
||
type PoolBalance struct {
|
||
AppCode string
|
||
PoolID string
|
||
StrategyVersion string
|
||
Balance int64
|
||
ReserveFloor int64
|
||
AvailableBalance int64
|
||
TotalIn int64
|
||
TotalOut int64
|
||
ManualCreditTotal int64
|
||
ManualDebitTotal int64
|
||
Materialized bool
|
||
UpdatedAtMS int64
|
||
}
|
||
|
||
type PoolBalanceQuery struct {
|
||
AppCode string
|
||
PoolID string
|
||
StrategyVersion string
|
||
}
|
||
|
||
// PoolAdjustmentCommand 是人工注资/扣资的 owner 命令。AdjustmentID 由调用方生成并在 App 内唯一,
|
||
// 同一个 ID 的重试只能复用完全相同的资金参数,避免网络重试演变成重复记账。
|
||
type PoolAdjustmentCommand struct {
|
||
AppCode string
|
||
PoolID string
|
||
StrategyVersion string
|
||
AdjustmentID string
|
||
Direction string
|
||
AmountCoins int64
|
||
Reason string
|
||
OperatorAdminID int64
|
||
RequestID string
|
||
}
|
||
|
||
type PoolAdjustment struct {
|
||
AdjustmentID string
|
||
AppCode string
|
||
PoolID string
|
||
StrategyVersion string
|
||
Direction string
|
||
AmountCoins int64
|
||
Reason string
|
||
OperatorAdminID int64
|
||
BalanceBefore int64
|
||
BalanceAfter int64
|
||
CreatedAtMS int64
|
||
}
|
||
|
||
type PoolAdjustmentResult struct {
|
||
Adjustment PoolAdjustment
|
||
Pool PoolBalance
|
||
IdempotentReplay bool
|
||
}
|
||
|
||
type AdminConfigQuery struct {
|
||
PoolID string
|
||
}
|
||
|
||
type DrawQuery struct {
|
||
AppCode string
|
||
PoolID string
|
||
GiftID string
|
||
UserID int64
|
||
RoomID string
|
||
Status string
|
||
Page int32
|
||
PageSize int32
|
||
// ExternalUserID 只用于外部 App 接入流水查询;内部房间抽奖不会填这个字段。
|
||
ExternalUserID string
|
||
ExternalOnly bool
|
||
}
|
||
|
||
const (
|
||
UserProfileIdentityInternal = "internal"
|
||
UserProfileIdentityExternal = "external"
|
||
|
||
UserProfileHitZero = "zero"
|
||
UserProfileHitOrdinary = "ordinary"
|
||
UserProfileHitRTPCompensation = "rtp_compensation"
|
||
UserProfileHitSpendMilestone = "spend_milestone"
|
||
)
|
||
|
||
// UserProfileQuery 只允许按已经物化的身份键分页。内部短号、长号和靓号由 admin-server
|
||
// 通过 user-service 解析成 InternalUserID;外部用户只用原始 ExternalUserID 搜索,稳定哈希绝不跨服务暴露。
|
||
type UserProfileQuery struct {
|
||
AppCode string
|
||
PoolID string
|
||
IdentityType string
|
||
InternalUserID int64
|
||
ExternalUserID string
|
||
Stage string
|
||
Status string
|
||
SortBy string
|
||
SortDirection string
|
||
Cursor string
|
||
Page int32
|
||
PageSize int32
|
||
JackpotPage int32
|
||
JackpotPageSize int32
|
||
JackpotCursor string
|
||
}
|
||
|
||
// UserProfileWindow 是严格时间窗内的用户资金结果。NetCoins 从用户视角计算为返奖减消耗;
|
||
// RTP 分母为 0 时保持 0,并由 HasRTP 区分“真实 0%”和“没有样本”。
|
||
type UserProfileWindow struct {
|
||
Draws int64
|
||
WagerCoins int64
|
||
PayoutCoins int64
|
||
NetCoins int64
|
||
RTPPPM int64
|
||
HasRTP bool
|
||
}
|
||
|
||
// UserProfile 是 app+pool+用户的运营画像,不携带外部 strategy_user_id。
|
||
// StrategyUserID 只在 lucky-gift-service 仓储层关联 current state,transport 映射时必须丢弃。
|
||
type UserProfile struct {
|
||
AppCode string
|
||
PoolID string
|
||
IdentityType string
|
||
IdentityKey string
|
||
StrategyUserID int64
|
||
InternalUserID int64
|
||
ExternalUserID string
|
||
RuleVersion int64
|
||
StrategyVersion string
|
||
Stage string
|
||
PaidDraws int64
|
||
EquivalentDraws int64
|
||
LossStreak int64
|
||
PendingSpendJackpotTokens int64
|
||
GuaranteeDrawsRemaining int64
|
||
DownweightActive bool
|
||
DownweightFactorPPM int64
|
||
User24HourRTPThresholdPPM int64
|
||
OneHour UserProfileWindow
|
||
TwentyFourHour UserProfileWindow
|
||
FortyEightHour UserProfileWindow
|
||
Lifetime UserProfileWindow
|
||
BaseRewardCoins int64
|
||
OrdinaryWinCount int64
|
||
HighMultiplierOrdinaryWinCount int64
|
||
RTPCompensationJackpotCount int64
|
||
CumulativeSpendJackpotCount int64
|
||
GuaranteeHitCount int64
|
||
ZeroDrawCount int64
|
||
GrantedDrawCount int64
|
||
PendingDrawCount int64
|
||
FailedDrawCount int64
|
||
MaxMultiplierPPM int64
|
||
MaxRewardCoins int64
|
||
FirstDrawAtMS int64
|
||
LastDrawAtMS int64
|
||
AggregatedAtMS int64
|
||
DataLagMS int64
|
||
}
|
||
|
||
type UserProfileMultiplierStat struct {
|
||
HitType string
|
||
MultiplierPPM int64
|
||
DrawCount int64
|
||
WagerCoins int64
|
||
PayoutCoins int64
|
||
}
|
||
|
||
type UserProfileJackpotCondition struct {
|
||
Name string
|
||
Numerator int64
|
||
Denominator int64
|
||
RatioPPM int64
|
||
LimitPPM int64
|
||
FactorPPM int64
|
||
Passed bool
|
||
Reason string
|
||
}
|
||
|
||
type UserProfileJackpotHit struct {
|
||
// SourceType 只参与 owner service 的稳定 keyset 游标,不通过 protobuf/HTTP 对外展示。
|
||
SourceType string
|
||
DrawID string
|
||
RequestID string
|
||
RuleVersion int64
|
||
Stage string
|
||
Mechanism string
|
||
ReasonCode string
|
||
ReasonSummary string
|
||
TierID string
|
||
MultiplierPPM int64
|
||
WagerCoins int64
|
||
PayoutCoins int64
|
||
OccurredAtMS int64
|
||
Conditions []UserProfileJackpotCondition
|
||
}
|
||
|
||
type UserProfileDetail struct {
|
||
Profile UserProfile
|
||
MultiplierDistribution []UserProfileMultiplierStat
|
||
JackpotHits []UserProfileJackpotHit
|
||
JackpotHitTotal int64
|
||
JackpotPage int32
|
||
JackpotPageSize int32
|
||
NextJackpotCursor string
|
||
JackpotHasMore bool
|
||
}
|
||
|
||
// ExternalDrawCommand 是外部 App “已扣费后请求抽奖”的业务事实。
|
||
// HyApp 不接管外部 App 余额,因此这里没有 target_user_id、room_id 或 wallet command_id;幂等边界固定为
|
||
// app_code + request_id,任何重试都必须返回同一条抽奖结果。
|
||
type ExternalDrawCommand struct {
|
||
AppCode string
|
||
ExternalUserID string
|
||
// DeviceID 是外部调用方在自己认证/签名边界内绑定的稳定设备标识;dynamic_v3 必填。
|
||
DeviceID string
|
||
RequestID string
|
||
GiftCount int64
|
||
UnitAmount int64
|
||
TotalAmount int64
|
||
Currency string
|
||
PaidAtMS int64
|
||
// UserRegisteredAtMS is supplied by the external App's authenticated user-data boundary.
|
||
// Missing or inconsistent facts do not block an ordinary draw, but can never mature a compensation jackpot.
|
||
UserRegisteredAtMS int64
|
||
MetadataJSON string
|
||
PoolID string
|
||
}
|
||
|
||
// ExternalDrawResult 是返回给外部 App 的最终抽奖结果。
|
||
// reward_status=granted 表示 HyApp 已完成抽奖审计并把 reward_amount 交给调用方处理;它不代表 HyApp wallet 入账。
|
||
type ExternalDrawResult struct {
|
||
DrawID string
|
||
RequestID string
|
||
AppCode string
|
||
ExternalUserID string
|
||
GiftCount int64
|
||
UnitAmount int64
|
||
TotalAmount int64
|
||
RewardAmount int64
|
||
MultiplierPPM int64
|
||
RewardStatus string
|
||
RuleVersion int64
|
||
CreatedAtMS int64
|
||
}
|
||
|
||
// DrawOutbox 是幸运礼物抽奖事务写出的异步副作用载体,worker 只消费这个持久事实。
|
||
type DrawOutbox struct {
|
||
AppCode string
|
||
OutboxID string
|
||
EventType string
|
||
PayloadJSON string
|
||
RetryCount int
|
||
CreatedAtMS int64
|
||
}
|
||
|
||
type DrawRewardState struct {
|
||
AllGranted bool
|
||
WalletTransactionID string
|
||
// RewardGrantedAtMS 取 granted draw 的稳定 updated_at_ms;owner MQ 重投必须保持同一事实正文不漂移。
|
||
RewardGrantedAtMS int64
|
||
}
|