2.5 KiB
2.5 KiB
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 1–12 (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 13–32 (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 (1–12) 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