Initial skills documentation — 25 categories, all SKILL.md + references + scripts
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# Fantasy Game Core Patterns — Backend (FastAPI + SQLite)
|
||||
|
||||
## Database schema
|
||||
|
||||
### users
|
||||
- id (int PK), email (unique), phone, display_name, password_hash, created_at
|
||||
|
||||
### leagues
|
||||
- id (int PK), name, invite_code (unique 8-char), status (draft/active/closed), season_start (date), season_end (date/null), created_by (FK users), created_at
|
||||
|
||||
### league_members
|
||||
- id (int PK), league_id (FK), user_id (FK), draft_order (int), is_commissioner (bool)
|
||||
- Unique: (league_id, user_id)
|
||||
|
||||
### regions
|
||||
- id (int PK), name, emoji, description, prev_year_sightings (int), prev_year_bites (int), prev_year_fatalities (int)
|
||||
|
||||
### draft_picks
|
||||
- id (int PK), league_id (FK), user_id (FK), region_id (FK), round (int), pick_number (int), created_at
|
||||
- Unique: (league_id, region_id) — no duplicates
|
||||
|
||||
### scores
|
||||
- id (int PK), region_id (FK), event_type (sighting/bite/fatality), description, source_url, points (int: 2/5/10), event_date (date), verified (bool default false), created_at
|
||||
|
||||
### user_scores (materialized)
|
||||
- user_id (FK), league_id (FK), total_points (int)
|
||||
|
||||
### league_excluded_regions
|
||||
- id (int PK), league_id (FK), region_id (FK)
|
||||
- Unique: (league_id, region_id) — a region can only be excluded once per league
|
||||
- Used when 32 % member_count > 0 at draft start: lowest-performing regions are removed so remaining pool is evenly divisible
|
||||
|
||||
## Points mapping
|
||||
sighting=2, bite=5, fatality=10
|
||||
|
||||
## Snake draft implementation
|
||||
```python
|
||||
members = sorted(league_members, key=lambda m: m['draft_order'])
|
||||
for round_num in range(1, total_rounds + 1):
|
||||
if round_num % 2 == 0:
|
||||
order = reversed(members) # Reverse order on even rounds
|
||||
else:
|
||||
order = members
|
||||
for member in order:
|
||||
# member picks
|
||||
```
|
||||
|
||||
## Turn enforcement
|
||||
```python
|
||||
current_pick_count = len(draft_picks)
|
||||
current_turn_order = (current_pick_count % member_count) + 1
|
||||
current_picker = member with draft_order == current_turn_order
|
||||
```
|
||||
|
||||
## Score recalculation (on event)
|
||||
```python
|
||||
INSERT OR REPLACE INTO user_scores (user_id, league_id, total_points)
|
||||
SELECT dp.user_id, dp.league_id, COALESCE(SUM(s.points), 0)
|
||||
FROM draft_picks dp
|
||||
LEFT JOIN scores s ON s.region_id = dp.region_id AND s.verified = 1
|
||||
WHERE dp.league_id = ?
|
||||
GROUP BY dp.user_id
|
||||
```
|
||||
|
||||
## Excluded region filtering
|
||||
When querying available regions for the draft board, filter against BOTH draft_picks AND league_excluded_regions:
|
||||
```python
|
||||
excluded_rows = conn.execute(
|
||||
"SELECT region_id FROM league_excluded_regions WHERE league_id = ?", (league_id,)
|
||||
).fetchall()
|
||||
excluded_ids = {r["region_id"] for r in excluded_rows}
|
||||
forbidden = drafted_ids | excluded_ids
|
||||
```
|
||||
|
||||
## Exclusion pick rejection
|
||||
```python
|
||||
excluded = conn.execute(
|
||||
"SELECT id FROM league_excluded_regions WHERE league_id = ? AND region_id = ?",
|
||||
(league_id, req.region_id),
|
||||
).fetchone()
|
||||
if excluded:
|
||||
raise HTTPException(status_code=400, detail="This region has been removed from the draft pool")
|
||||
```
|
||||
|
||||
## Performance score for exclusion ordering
|
||||
```sql
|
||||
ORDER BY (prev_year_sightings + prev_year_bites * 5 + prev_year_fatalities * 10) ASC, id ASC
|
||||
```
|
||||
Lower scores = worse performing regions = first to be removed.
|
||||
|
||||
## League invite code generation
|
||||
```python
|
||||
def generate_invite_code():
|
||||
return secrets.token_hex(4).upper()[:8]
|
||||
```
|
||||
|
||||
## Region seeding
|
||||
Use `INSERT OR IGNORE` so repeated runs don't error. Seed at least 20+ regions for meaningful draft depth.
|
||||
Reference in New Issue
Block a user