# 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
