package models import ( "time" "github.com/uptrace/bun" ) // ─── Roles ────────────────────────────────────────────────── type Role string const ( RoleAdmin Role = "admin" RoleModerator Role = "moderator" RoleUser Role = "user" ) // ─── User ─────────────────────────────────────────────────── type User struct { bun.BaseModel `bun:"table:users,alias:u"` ID int64 `bun:"id,pk,autoincrement" json:"id"` Email string `bun:"email,notnull,unique" json:"email"` Username string `bun:"username,notnull,unique" json:"username"` Password string `bun:"password,notnull" json:"-"` Role Role `bun:"role,notnull,default:'user'" json:"role"` IsActive bool `bun:"is_active,notnull,default:true" json:"is_active"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` UserGames []*UserGame `bun:"rel:has-many,join:id=user_id" json:"user_games,omitempty"` } // ─── Game ─────────────────────────────────────────────────── type Game struct { bun.BaseModel `bun:"table:games,alias:g"` ID int64 `bun:"id,pk,autoincrement" json:"id"` Name string `bun:"name,notnull,unique" json:"name"` Slug string `bun:"slug,notnull,unique" json:"slug"` Description string `bun:"description" json:"description"` ImageURL string `bun:"image_url" json:"image_url"` IsActive bool `bun:"is_active,notnull,default:true" json:"is_active"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` Variables []*GameVariable `bun:"rel:has-many,join:id=game_id" json:"variables,omitempty"` Notifications []Notification `bun:"rel:has-many,join:id=game_id" json:"notifications,omitempty"` Leaderboards []Leaderboard `bun:"rel:has-many,join:id=game_id" json:"leaderboards,omitempty"` Modules []Module `bun:"-" json:"modules,omitempty"` } type GameVariableType string const ( GameVariableTypeNumber GameVariableType = "number" GameVariableTypeString GameVariableType = "string" GameVariableTypeTable GameVariableType = "table" GameVariableTypeVector GameVariableType = "vector" ) type GameVariableTableValueType string const ( GameVariableTableValueTypeNumber GameVariableTableValueType = "number" GameVariableTableValueTypeString GameVariableTableValueType = "string" ) type GameVariable struct { bun.BaseModel `bun:"table:game_variables,alias:gv"` ID int64 `bun:"id,pk,autoincrement" json:"id"` GameID int64 `bun:"game_id,notnull" json:"game_id"` Key string `bun:"key,notnull" json:"key"` Type GameVariableType `bun:"type,notnull" json:"type"` NumberValue *float64 `bun:"number_value" json:"number_value,omitempty"` StringValue *string `bun:"string_value" json:"string_value,omitempty"` TableValueType *GameVariableTableValueType `bun:"table_value_type" json:"table_value_type,omitempty"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` Game *Game `bun:"rel:belongs-to,join:game_id=id" json:"game,omitempty"` Items []*GameVariableItem `bun:"rel:has-many,join:id=game_variable_id" json:"items,omitempty"` } type GameVariableItem struct { bun.BaseModel `bun:"table:game_variable_items,alias:gvi"` ID int64 `bun:"id,pk,autoincrement" json:"id"` GameVariableID int64 `bun:"game_variable_id,notnull" json:"game_variable_id"` Key string `bun:"item_key,notnull" json:"key,omitempty"` Index *int64 `bun:"-" json:"index,omitempty"` NumberValue *float64 `bun:"number_value" json:"number_value,omitempty"` StringValue *string `bun:"string_value" json:"string_value,omitempty"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` Variable *GameVariable `bun:"rel:belongs-to,join:game_variable_id=id" json:"-"` } type Module struct { bun.BaseModel `bun:"table:modules,alias:m"` ID int64 `bun:"id,pk,autoincrement" json:"id"` Key string `bun:"key,notnull,unique" json:"key"` Name string `bun:"name,notnull" json:"name"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` } type Language struct { bun.BaseModel `bun:"table:languages,alias:l"` ID int64 `bun:"id,pk,autoincrement" json:"id"` Code string `bun:"code,notnull,unique" json:"code"` Name string `bun:"name,notnull" json:"name"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` } type GameModule struct { bun.BaseModel `bun:"table:game_modules,alias:gm"` ID int64 `bun:"id,pk,autoincrement" json:"id"` GameID int64 `bun:"game_id,notnull" json:"game_id"` ModuleID int64 `bun:"module_id,notnull" json:"module_id"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` Game *Game `bun:"rel:belongs-to,join:game_id=id" json:"-"` Module *Module `bun:"rel:belongs-to,join:module_id=id" json:"module,omitempty"` } type Notification struct { bun.BaseModel `bun:"table:notifications,alias:n"` ID int64 `bun:"id,pk,autoincrement" json:"id"` GameID int64 `bun:"game_id,notnull" json:"game_id"` Name string `bun:"name,notnull" json:"name"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` Game *Game `bun:"rel:belongs-to,join:game_id=id" json:"game,omitempty"` Descriptions []NotificationDescription `bun:"rel:has-many,join:id=notification_id" json:"descriptions,omitempty"` Variables []NotificationVariableDef `bun:"rel:has-many,join:id=notification_id" json:"variables,omitempty"` Entries []NotificationEntry `bun:"rel:has-many,join:id=notification_id" json:"entries,omitempty"` Macros []string `bun:"-" json:"macros,omitempty"` } type NotificationDescription struct { bun.BaseModel `bun:"table:notification_descriptions,alias:nd"` ID int64 `bun:"id,pk,autoincrement" json:"id"` NotificationID int64 `bun:"notification_id,notnull" json:"notification_id"` LanguageID int64 `bun:"language_id,notnull" json:"language_id"` Description string `bun:"description,notnull" json:"description"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` Language *Language `bun:"rel:belongs-to,join:language_id=id" json:"language,omitempty"` Notification *Notification `bun:"rel:belongs-to,join:notification_id=id" json:"-"` } type NotificationVariableDef struct { bun.BaseModel `bun:"table:notification_variable_defs,alias:nvd"` ID int64 `bun:"id,pk,autoincrement" json:"id"` NotificationID int64 `bun:"notification_id,notnull" json:"notification_id"` Key string `bun:"key,notnull" json:"key"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` Notification *Notification `bun:"rel:belongs-to,join:notification_id=id" json:"-"` } type NotificationEntry struct { bun.BaseModel `bun:"table:notification_entries,alias:ne"` ID int64 `bun:"id,pk,autoincrement" json:"id"` NotificationID int64 `bun:"notification_id,notnull" json:"notification_id"` TimeSecond int64 `bun:"time_second,notnull" json:"time_second"` Image string `bun:"image,notnull" json:"image"` Login string `bun:"login,notnull" json:"login"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` Notification *Notification `bun:"rel:belongs-to,join:notification_id=id" json:"-"` Variables []NotificationEntryVariable `bun:"rel:has-many,join:id=notification_entry_id" json:"variables,omitempty"` } type NotificationEntryVariable struct { bun.BaseModel `bun:"table:notification_entry_variables,alias:nev"` ID int64 `bun:"id,pk,autoincrement" json:"id"` NotificationEntryID int64 `bun:"notification_entry_id,notnull" json:"notification_entry_id"` NotificationVariableID int64 `bun:"notification_variable_id,notnull" json:"notification_variable_id"` Value string `bun:"value,notnull" json:"value"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` Key string `bun:"-" json:"key,omitempty"` Entry *NotificationEntry `bun:"rel:belongs-to,join:notification_entry_id=id" json:"-"` Variable *NotificationVariableDef `bun:"rel:belongs-to,join:notification_variable_id=id" json:"-"` } type LeaderboardSortOrder string const ( LeaderboardSortOrderDesc LeaderboardSortOrder = "desc" LeaderboardSortOrderAsc LeaderboardSortOrder = "asc" ) type LeaderboardPeriodType string const ( LeaderboardPeriodAllTime LeaderboardPeriodType = "all_time" LeaderboardPeriodDaily LeaderboardPeriodType = "daily" LeaderboardPeriodWeekly LeaderboardPeriodType = "weekly" LeaderboardPeriodMonthly LeaderboardPeriodType = "monthly" ) type Leaderboard struct { bun.BaseModel `bun:"table:leaderboards,alias:lb"` ID int64 `bun:"id,pk,autoincrement" json:"id"` GameID int64 `bun:"game_id,notnull" json:"game_id"` Key string `bun:"key,notnull" json:"key"` Name string `bun:"name,notnull" json:"name"` SortOrder LeaderboardSortOrder `bun:"sort_order,notnull" json:"sort_order"` PeriodType LeaderboardPeriodType `bun:"period_type,notnull" json:"period_type"` IsActive bool `bun:"is_active,notnull,default:true" json:"is_active"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` Game *Game `bun:"rel:belongs-to,join:game_id=id" json:"game,omitempty"` Groups []LeaderboardGroup `bun:"rel:has-many,join:id=leaderboard_id" json:"groups,omitempty"` } type LeaderboardGroup struct { bun.BaseModel `bun:"table:leaderboard_groups,alias:lbg"` ID int64 `bun:"id,pk,autoincrement" json:"id"` LeaderboardID int64 `bun:"leaderboard_id,notnull" json:"leaderboard_id"` Key string `bun:"key,notnull" json:"key"` Name string `bun:"name,notnull" json:"name"` IsDefault bool `bun:"is_default,notnull,default:false" json:"is_default"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` Leaderboard *Leaderboard `bun:"rel:belongs-to,join:leaderboard_id=id" json:"leaderboard,omitempty"` Members []LeaderboardGroupMember `bun:"rel:has-many,join:id=group_id" json:"members,omitempty"` } type LeaderboardGroupMember struct { bun.BaseModel `bun:"table:leaderboard_group_members,alias:lbgm"` ID int64 `bun:"id,pk,autoincrement" json:"id"` GroupID int64 `bun:"group_id,notnull" json:"group_id"` UserID int64 `bun:"user_id,notnull" json:"user_id"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` Group *LeaderboardGroup `bun:"rel:belongs-to,join:group_id=id" json:"-"` User *User `bun:"rel:belongs-to,join:user_id=id" json:"user,omitempty"` } type LeaderboardScore struct { bun.BaseModel `bun:"table:leaderboard_scores,alias:lbs"` ID int64 `bun:"id,pk,autoincrement" json:"id"` LeaderboardID int64 `bun:"leaderboard_id,notnull" json:"leaderboard_id"` UserGameID int64 `bun:"user_game_id,notnull" json:"user_game_id"` Score float64 `bun:"score,notnull" json:"score"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` Leaderboard *Leaderboard `bun:"rel:belongs-to,join:leaderboard_id=id" json:"leaderboard,omitempty"` UserGame *UserGame `bun:"rel:belongs-to,join:user_game_id=id" json:"user_game,omitempty"` } type LeaderboardRankItem struct { Rank int64 `json:"rank"` UserID int64 `json:"user_id"` UserGameID int64 `json:"user_game_id"` Username string `json:"username"` Score float64 `json:"score"` } // ─── UserGame (pivot — user's connected games + balance) ──── type UserGame struct { bun.BaseModel `bun:"table:user_games,alias:ug"` ID int64 `bun:"id,pk,autoincrement" json:"id"` UserID int64 `bun:"user_id,notnull" json:"user_id"` GameID int64 `bun:"game_id,notnull" json:"game_id"` Balance float64 `bun:"balance,notnull,default:0" json:"balance"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"` User *User `bun:"rel:belongs-to,join:user_id=id" json:"user,omitempty"` Game *Game `bun:"rel:belongs-to,join:game_id=id" json:"game,omitempty"` } // ─── Invite Link ──────────────────────────────────────────── type InviteLink struct { bun.BaseModel `bun:"table:invite_links,alias:il"` ID int64 `bun:"id,pk,autoincrement" json:"id"` Code string `bun:"code,notnull,unique" json:"code"` Role Role `bun:"role,notnull,default:'user'" json:"role"` MaxUses int `bun:"max_uses,notnull,default:1" json:"max_uses"` UsedCount int `bun:"used_count,notnull,default:0" json:"used_count"` CreatedByID int64 `bun:"created_by_id,notnull" json:"created_by_id"` ExpiresAt *time.Time `bun:"expires_at" json:"expires_at"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` CreatedBy *User `bun:"rel:belongs-to,join:created_by_id=id" json:"created_by,omitempty"` } // ─── Balance Transaction Log ──────────────────────────────── type BalanceTransaction struct { bun.BaseModel `bun:"table:balance_transactions,alias:bt"` ID int64 `bun:"id,pk,autoincrement" json:"id"` UserGameID int64 `bun:"user_game_id,notnull" json:"user_game_id"` Amount float64 `bun:"amount,notnull" json:"amount"` Type string `bun:"type,notnull" json:"type"` // "topup" | "withdraw" Comment string `bun:"comment" json:"comment"` AdminID int64 `bun:"admin_id,notnull" json:"admin_id"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"` } // ─── Request / Response DTOs ──────────────────────────────── type LoginRequest struct { Email string `json:"email" binding:"required,email"` Password string `json:"password" binding:"required,min=6"` } type RegisterRequest struct { Email string `json:"email" binding:"required,email"` Username string `json:"username" binding:"required,min=3"` Password string `json:"password" binding:"required,min=6"` InviteCode string `json:"invite_code"` } type TopUpRequest struct { Amount float64 `json:"amount" binding:"required,gt=0"` Comment string `json:"comment"` } type CreateInviteRequest struct { Role Role `json:"role" binding:"required"` MaxUses int `json:"max_uses" binding:"required,gt=0"` } type CreateGameRequest struct { Name string `json:"name" binding:"required"` Slug string `json:"slug" binding:"required"` Description string `json:"description"` ImageURL string `json:"image_url"` } type GameVariableItemRequest struct { Key string `json:"key"` Index *int64 `json:"index"` NumberValue *float64 `json:"number_value"` StringValue *string `json:"string_value"` } type UpsertGameVariableRequest struct { Key string `json:"key" binding:"required"` Type GameVariableType `json:"type" binding:"required"` NumberValue *float64 `json:"number_value"` StringValue *string `json:"string_value"` TableValueType *GameVariableTableValueType `json:"table_value_type"` Items []GameVariableItemRequest `json:"items"` } type ConnectGameModuleRequest struct { ModuleKey string `json:"module_key" binding:"required"` } type UpsertLanguageRequest struct { Code string `json:"code" binding:"required"` Name string `json:"name" binding:"required"` } type NotificationDescriptionRequest struct { LanguageID int64 `json:"language_id" binding:"required"` Description string `json:"description" binding:"required"` } type NotificationVariableRequest struct { Key string `json:"key" binding:"required"` } type NotificationEntryVariableRequest struct { Key string `json:"key" binding:"required"` Value string `json:"value"` } type NotificationEntryRequest struct { TimeSecond int64 `json:"time_second"` Image string `json:"image" binding:"required"` Login string `json:"login" binding:"required"` Variables []NotificationEntryVariableRequest `json:"variables"` } type UpsertNotificationRequest struct { Name string `json:"name" binding:"required"` Descriptions []NotificationDescriptionRequest `json:"descriptions" binding:"required"` Variables []NotificationVariableRequest `json:"variables"` Entries []NotificationEntryRequest `json:"entries" binding:"required"` } type UpsertLeaderboardRequest struct { Key string `json:"key" binding:"required"` Name string `json:"name" binding:"required"` SortOrder LeaderboardSortOrder `json:"sort_order" binding:"required"` PeriodType LeaderboardPeriodType `json:"period_type" binding:"required"` IsActive *bool `json:"is_active"` } type UpsertLeaderboardGroupRequest struct { Key string `json:"key" binding:"required"` Name string `json:"name" binding:"required"` IsDefault *bool `json:"is_default"` } type AddLeaderboardGroupMemberRequest struct { UserID int64 `json:"user_id" binding:"required"` } type UpsertLeaderboardScoreRequest struct { UserGameID int64 `json:"user_game_id" binding:"required"` Score float64 `json:"score" binding:"required"` } type ConnectGameRequest struct { GameID int64 `json:"game_id" binding:"required"` } type UpdateUserRoleRequest struct { Role Role `json:"role" binding:"required"` }