Files

2.5 KiB
Raw Permalink Blame History

Shark Game Backend — FastAPI + SQLite + Auth + Draft + Scoring

Database tables

  • users (id, email, phone, display_name, password_hash, created_at)
  • leagues (id, name, invite_code, status [draft/active/closed], season_start/end, created_by)
  • league_members (id, league_id, user_id, draft_order, is_commissioner)
  • regions (id, name, emoji, description, prev_year stats)
  • draft_picks (id, league_id, user_id, region_id, round, pick_number) — unique on (league_id, region_id)
  • scores (id, region_id, event_type, description, source_url, points 2/5/10, event_date, verified)
  • user_scores (user_id, league_id, total_points) — materialized, recalculated on new score events

Seed data: 32 coastal regions

The game ships with 32 pre-seeded regions with real-world lat/lng and historical stats (prev_year_sightings, prev_year_bites, prev_year_fatalities):

  • IDs 112 (original): Florida East Coast, Florida Gulf Coast, Caribbean, California South, California North, Hawaii, Carolina Coast, Texas Gulf, Australia East/West, South Africa, Brazil Coast
  • IDs 1332 (expanded): New England Coast, New York Bight, Mid-Atlantic, Georgia Coast, Louisiana Gulf, Mexico Pacific, Mexico Gulf, Central America, South America Pacific, Mediterranean, West/East Africa, Middle East, India West/East, Southeast Asia, Japan, New Zealand, Pacific Islands, UK & Ireland

Seed strategy: INSERT OR IGNORE — the regions table is populated once on first startup via seed_regions(). The REGIONS_SEED list in server.py is the single source of truth. When adding new regions, append tuples to the list and increment the total. The seed guard (if existing == 0) ensures existing databases are not touched.

The frontend MAP_REGIONS array in draft-room.html mirrors the backend list with matching IDs, lat/lng for Leaflet markers, and a stats:{s,b,f} field on new regions (IDs 13+). Original regions (112) intentionally lack the stats field to avoid breaking the existing code path.

Key patterns

  • Snake draft: Round 1 order 1→N, Round 2 N→1, Round 3 1→N
  • Turn enforcement: Check draft_order matches next_pick_number
  • Commissioner-only: Draft start endpoint validates is_commissioner
  • Scoring: sighting=2, bite=5, fatality=10. Recalculate all user_scores on new event
  • Region assignment: Region IDs 1-32 are pre-seeded. Event endpoint expects region_id, validates it exists.
  • Frontend serving: FastAPI catch-all route at the end serves static files + falls back to index.html