-
Notifications
You must be signed in to change notification settings - Fork 0
Database Schema
c0bra edited this page Jul 24, 2026
·
1 revision
erDiagram
users ||--o{ season_ratings : has
users ||--o{ lobbies : creates
users ||--o{ lobby_rosters : plays_in
lobbies ||--o{ lobby_rosters : has_roster
guild_config ||--o{ leaderboard_slots : caches
guild_config {
BIGINT guild_id PK
BIGINT leaderboard_channel_id "nullable"
INTEGER leaderboard_limit "1-50; nullable means 50"
TIMESTAMPTZ updated_at
BIGINT updated_by "nullable Discord user ID"
}
leaderboard_slots {
BIGINT guild_id PK,FK
INTEGER slot PK "0 is header"
BIGINT channel_id "active mapping on slot 0 only"
BIGINT message_id "active mapping on slot 0 only"
INTEGER season_year "nullable"
INTEGER season_number "nullable"
UUID user_id "nullable; no foreign key"
TEXT fingerprint
TIMESTAMPTZ updated_at
}
users {
UUID id PK
TEXT discord_username
BIGINT discord_id UK "nullable, resolved locally by the bot"
INTEGER member_number
INTEGER tournaments_joined
TEXT bio
TEXT favorite_champion
TEXT profile_title
TIMESTAMPTZ username_changed_at
}
season_ratings {
BIGINT id PK
UUID user_id FK
INTEGER season_year
INTEGER season_number
INTEGER mmr
INTEGER wins
INTEGER losses
INTEGER matches_played
TIMESTAMPTZ updated_at
}
lobbies {
INTEGER id PK
INTEGER lobby_number
TEXT title
TEXT lobby_type
TEXT region
INTEGER match_size
TEXT team_one_name
TEXT team_two_name
UUID creator_id FK
TEXT status
INTEGER draft_step
TIMESTAMPTZ draft_started_at
TEXT winner_slot
INTEGER season_year
INTEGER season_number
TEXT season_name
TIMESTAMPTZ created_at
TIMESTAMPTZ ended_at
TIMESTAMPTZ match_started_at
TEXT dispute_reason
BOOLEAN winner_confirmed_by_team_one
BOOLEAN winner_confirmed_by_team_two
TEXT result_team_one_vote
TEXT result_team_two_vote
TIMESTAMPTZ discord_match_ready_requested_at
TIMESTAMPTZ discord_match_ready_sent_at
TEXT discord_match_ready_status
TEXT discord_match_ready_error
BOOLEAN mmr_applied
INTEGER ban_count
BOOLEAN is_tournament
TEXT tournament_match_id
TEXT tournament_name
INTEGER url_year
TEXT url_series
INTEGER game_number
BOOLEAN has_password
TEXT_ARRAY map_pool
TEXT selected_map
}
lobby_rosters {
INTEGER lobby_id PK,FK
UUID user_id PK,FK
TEXT team "team_one or team_two"
}
-
users.id,lobbies.id, andseason_ratings.idare upstream Supabase primary keys, kept as-is. -
users.discord_idis bot-owned local state, not part of the upstream payload. Sync logic must never overwrite it. -
season_ratingsis a separate upstream endpoint (/season_ratings), one row per user per season –UNIQUE (user_id, season_year, season_number). -
team_one_roster/team_two_rosterfrom the upstreamLobbypayload are normalized intolobby_rostersrather than kept as array columns. - Write order matters:
usersmust be synced beforelobbiesandseason_ratings, since both foreign-key into it. -
guild_configstores one row per Discord server. A nullableleaderboard_channel_idmeans the leaderboard destination is unset.leaderboard_limitaccepts values from 1 through 50; null uses the maximum of 50 after Discord guild-member filtering. -
updated_bystores the Discord user ID that last changed the configuration and may be null for older/manual rows. -
leaderboard_slotsstores fingerprints and Discord message metadata only. Slot0is the header and holds the active Discord message mapping; player slots begin at1and keep their channel/message IDs null. Reconciliation replaces all rows for one guild in a single transaction. - Complete content-addressed PNGs are stored at
app/data/leaderboards/<guild_id>/<aggregate_fingerprint>.png. The aggregate fingerprint is derived from the ordered slot fingerprints. The persistentapp/data:/app/dataCompose mount retains these images across container replacement. - Leaderboard images are 1280 pixels wide, with a 184-pixel header and one 124-pixel row per player. The renderer can reuse a valid complete image and redraw only changed rectangles, while PNG encoding and Discord upload still use the whole image.
- The current leaderboard season is the season belonging to the
season_ratingsrow with the greatestupdated_at. Rows in that season are ordered bymmr DESCwith no additional tie-breaker. - Native PostgreSQL triggers publish
leaderboard_changednotifications for rating changes and changes to user Discord links or usernames. The bot also periodically reconciles as recovery for missed notifications.