571 lines
22 KiB
Go
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.

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 仅为协议/存储 sentinelnormal/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
DeviceID string
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
// HostPeriodDiamondAdded 是 wallet 按后台礼物比例配置实际入账的主播钻石,资金拆分必须以该 owner 事实为准。
HostPeriodDiamondAdded 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 statetransport 映射时必须丢弃。
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_msowner MQ 重投必须保持同一事实正文不漂移。
RewardGrantedAtMS int64
}