# EL3AB Database Quick Reference

**Full audit:** [docs/supabase_master_audit.md](docs/supabase_master_audit.md) (992 lines, every table/column/FK/policy)

---

## Connection

| Key | Value |
|-----|-------|
| API Gateway | https://safe-supabase-kong.caprover.al-arcade.com |
| REST endpoint | /rest/v1/{table} |
| Auth endpoint | /auth/v1/ |
| Storage endpoint | /storage/v1/ |
| Realtime WS | wss://safe-supabase-kong.caprover.al-arcade.com/realtime/v1/websocket |
| Anon Key | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84 |
| Service Key | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UiLCJpYXQiOjE3MzU2ODk2MDAsImV4cCI6MTg5MzQ1NjAwMH0.wNfmuJNkX-bZwD7RbjxOChlRf_3Xm4I7bswEYTcDCg4 |

---

## Tables Used by Player App (23 core)

### Player Identity
| Table | Key Columns | PK |
|-------|-------------|-----|
| profiles | username, display_name, elo_*, coins, gems, xp, level, is_online, is_banned | id (uuid, = auth.users.id) |
| player_game_ratings | player_id, game_key, rating, games_played, wins, losses, draws | id (uuid) |
| user_profiles | full_name, fide_id, fide_rating_*, nationality | id (uuid) |

### Games
| Table | Key Columns | PK |
|-------|-------------|-----|
| matches | game_key, white/black_player_id, status, result, time_control, moves (jsonb), current_fen | id (uuid) |
| domino_matches | room_code, status, players (jsonb), board (jsonb), hands (jsonb), scores (jsonb) | id (uuid) |
| ludo_matches | room_code, status, players (jsonb), positions (jsonb), dice_value, winners (jsonb) | id (uuid) |
| matchmaking_queue | player_id, game_key, time_control, rating, status, matched_with, match_id | id (uuid) |
| domino_queue | user_id, mode, match_id | id (uuid) |
| ludo_queue | user_id, match_id | id (uuid) |
| game_plugins | game_key (PK), name, name_ar, is_enabled, supports_* | game_key (text) |
| puzzles | fen, moves, rating, themes | id (serial) |

### Competitive
| Table | Key Columns | PK |
|-------|-------------|-----|
| leaderboards | player_id, game_key, time_control_type, period, rank, rating | id (uuid) |
| rating_history | player_id, game_key, rating_before/after, match_id, opponent_id | id (uuid) |
| el3ab_tournaments | org_id, game_key, format, time_control, status, max_players, starts_at | id (uuid) |
| tournament_registrations | tournament_id, player_id, status | id (uuid) |

### Social
| Table | Key Columns | PK |
|-------|-------------|-----|
| friendships | requester_id, addressee_id, status (pending/accepted) | id (uuid) |
| notifications | user_id, type, title, title_ar, body, is_read | id (uuid) |
| chat_messages | channel_type, channel_id, sender_id, content | id (uuid) |
| activity_feed | actor_id, action, target_type, target_id | id (uuid) |

### Economy
| Table | Key Columns | PK |
|-------|-------------|-----|
| economy_transactions | player_id, type, currency (coins/gems), amount, balance_after | id (uuid) |
| cosmetics | name, type (enum), rarity (enum), price_coins, price_gems | id (text) |
| player_cosmetics | player_id, cosmetic_id, is_equipped | id (uuid) |
| achievements | name, category, condition (jsonb), xp_reward, coins_reward | id (text) |
| player_achievements | player_id, achievement_id, progress, is_completed | id (uuid) |
| xp_levels | level (PK), xp_required, reward_coins, reward_gems | level (int) |

---

## Key Enums

```
match_status: waiting, ready, in_progress, paused, completed, aborted, abandoned
match_result: white_wins, black_wins, draw, white_timeout, black_timeout, white_resign, black_resign, white_abandon, black_abandon, stalemate, insufficient_material, threefold_repetition, fifty_moves, mutual_draw, aborted
time_control: bullet_1_0, bullet_1_1, bullet_2_1, blitz_3_0, blitz_3_2, blitz_5_0, blitz_5_3, rapid_10_0, rapid_10_5, rapid_15_10, rapid_30_0, classical_60_0, classical_90_30, custom
cosmetic_type: avatar_frame, board_theme, piece_set, profile_banner, chat_emoji, victory_animation, title_badge, trail_effect, sound_pack
cosmetic_rarity: common, uncommon, rare, epic, legendary
```

---

## RLS Rules (Player App perspective)

### Can read without auth (anon key, no JWT)
profiles, matches, leaderboards, achievements, cosmetics, game_plugins, puzzles, feature_flags, el3ab_tournaments, xp_levels, clubs, platform_assets, platform_theme, rating_history

### Must be authenticated (anon key + JWT)
- **Own data:** notifications, economy_transactions, player_cosmetics, player_achievements, matchmaking_queue, friendships
- **Can INSERT:** matches (own player), friendships (own requester), matchmaking_queue (own), chat_messages (own sender)
- **Can UPDATE:** profiles (own), notifications (own, mark read), matches (own player), matchmaking_queue (own)
- **Can DELETE:** matchmaking_queue (own)

### Requires service key (PHP backend)
All org_* tables (28), bracket_matches, tournament_brackets, tournament_phases, player_frames, profile_frames

---

## Key Foreign Keys (Player App)

```
profiles.id ← auth.users.id (trigger creates on signup)
matches.white_player_id → profiles.id
matches.black_player_id → profiles.id
matches.rematch_of → matches.id
matchmaking_queue.player_id → profiles.id
matchmaking_queue.match_id → matches.id
friendships.requester_id → profiles.id
friendships.addressee_id → profiles.id
notifications.user_id → profiles.id
economy_transactions.player_id → profiles.id
player_cosmetics.player_id → profiles.id
player_cosmetics.cosmetic_id → cosmetics.id
player_achievements.player_id → profiles.id
player_achievements.achievement_id → achievements.id
leaderboards.player_id → profiles.id
rating_history.player_id → profiles.id
rating_history.match_id → matches.id
el3ab_tournaments.org_id → el3ab_organizations.id
tournament_registrations.tournament_id → el3ab_tournaments.id
```

---

## RPC Functions Available

| Function | Args | Returns | Purpose |
|----------|------|---------|---------|
| register_tournament_player | tournament_id, player_auth_id | json | Register for tournament (validates capacity/status) |
| cancel_tournament_registration | tournament_id | json | Cancel registration |
| get_all_tournaments | — | json | Get tournaments + players + brackets |
| get_tournament_by_id | id | json | Single tournament detail |
| get_tournament_room | tournament_id, bracket_id | json | Get lobby ID for match |
| check_opponent_timeout | bracket_id, user_numeric_id | json | Check if opponent timed out |
| check_app_version | client_version | json | Mobile app version check |
| get_friends_by_auth_ids | auth_ids[] | json | Get friend profiles (Unity) |

---

## Storage Buckets

| Bucket | Public | Use in Player App |
|--------|--------|-------------------|
| profile-images | YES | Avatar upload/display |
| avatars | YES | Legacy avatars |
| profile-frames | YES | Frame overlays |
| org-logos | YES | Org logos in listings |
| org-banners | YES | Org banners |

---

## Realtime Subscription Patterns

```javascript
// Match state (chess/domino/ludo)
supabase.channel('game')
  .on('postgres_changes', {
    event: 'UPDATE',
    schema: 'public',
    table: 'matches',
    filter: `id=eq.${matchId}`
  }, handleGameUpdate)

// Matchmaking
supabase.channel('queue')
  .on('postgres_changes', {
    event: 'UPDATE',
    schema: 'public',
    table: 'matchmaking_queue',
    filter: `player_id=eq.${userId}`
  }, handleMatchFound)

// Notifications
supabase.channel('notifs')
  .on('postgres_changes', {
    event: 'INSERT',
    schema: 'public',
    table: 'notifications',
    filter: `user_id=eq.${userId}`
  }, handleNewNotification)
```
