Files
Horchposten/models/models.go
2026-03-08 14:44:50 +00:00

120 lines
4.2 KiB
Go

package models
import (
"database/sql"
"time"
)
// Player represents an anonymous player identified by a client-generated UUID.
type Player struct {
ID int64 `json:"-"`
ClientID string `json:"client_id"`
FirstSeen time.Time `json:"first_seen"`
LastSeen time.Time `json:"last_seen"`
TotalSessions int `json:"total_sessions"`
}
// PlayerIP tracks distinct IP addresses a player has connected from.
type PlayerIP struct {
ID int64 `json:"-"`
PlayerID int64 `json:"-"`
IPAddress string `json:"ip_address"`
FirstSeen time.Time `json:"first_seen"`
LastSeen time.Time `json:"last_seen"`
}
// GameSession represents a single play session.
type GameSession struct {
ID string `json:"session_id"`
PlayerID int64 `json:"-"`
Score int `json:"score"`
LevelReached int `json:"level_reached"`
LivesUsed int `json:"lives_used"`
DurationSeconds int `json:"duration_seconds"`
EndReason string `json:"end_reason"`
StartedAt time.Time `json:"started_at"`
EndedAt time.Time `json:"ended_at"`
}
// DeviceInfo holds browser/device fingerprint data captured per session.
type DeviceInfo struct {
ID int64 `json:"-"`
SessionID string `json:"-"`
IPAddress string `json:"ip_address"`
UserAgent string `json:"user_agent"`
Platform string `json:"platform"`
Language string `json:"language"`
ScreenWidth sql.NullInt32 `json:"screen_width"`
ScreenHeight sql.NullInt32 `json:"screen_height"`
DevicePixelRatio sql.NullFloat64 `json:"device_pixel_ratio"`
Timezone string `json:"timezone"`
WebGLRenderer string `json:"webgl_renderer"`
TouchSupport bool `json:"touch_support"`
}
// HighScore is a denormalized personal-best record, one per player.
type HighScore struct {
ID int64 `json:"-"`
PlayerID int64 `json:"-"`
Score int `json:"score"`
SessionID sql.NullString `json:"-"`
AchievedAt time.Time `json:"achieved_at"`
}
// --- Request/Response types ---
// DeviceInfoRequest is the optional device payload in session start.
type DeviceInfoRequest struct {
Platform string `json:"platform"`
Language string `json:"language"`
ScreenWidth *int `json:"screen_width"`
ScreenHeight *int `json:"screen_height"`
DevicePixelRatio *float64 `json:"device_pixel_ratio"`
Timezone string `json:"timezone"`
WebGLRenderer string `json:"webgl_renderer"`
TouchSupport bool `json:"touch_support"`
}
// SessionStartRequest is the JSON body for POST /session/start/.
type SessionStartRequest struct {
ClientID string `json:"client_id"`
Device *DeviceInfoRequest `json:"device"`
}
// SessionEndRequest is the JSON body for POST /session/:id/end/.
type SessionEndRequest struct {
Score int `json:"score"`
LevelReached int `json:"level_reached"`
LivesUsed int `json:"lives_used"`
DurationSeconds int `json:"duration_seconds"`
EndReason string `json:"end_reason"`
}
// LeaderboardEntry is a single row in the leaderboard response.
type LeaderboardEntry struct {
ClientID string `json:"client_id"`
Score int `json:"score"`
AchievedAt time.Time `json:"achieved_at"`
}
// SessionSummary is a session entry in the player stats response.
type SessionSummary struct {
SessionID string `json:"session_id"`
Score int `json:"score"`
LevelReached int `json:"level_reached"`
LivesUsed int `json:"lives_used"`
DurationSeconds int `json:"duration_seconds"`
EndReason string `json:"end_reason"`
StartedAt time.Time `json:"started_at"`
EndedAt time.Time `json:"ended_at"`
}
// PlayerStatsResponse is the response for GET /player/:client_id/.
type PlayerStatsResponse struct {
ClientID string `json:"client_id"`
TotalSessions int `json:"total_sessions"`
FirstSeen time.Time `json:"first_seen"`
HighScore *int `json:"high_score"`
Sessions []SessionSummary `json:"sessions"`
}