diff --git a/CLAUDE.md b/CLAUDE.md index 7cd9a11..0d9082d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -258,6 +258,16 @@ Admin endpoints use `game_service.py` functions which handle both database updat 3. Return JSON responses with appropriate status codes 4. For admin actions affecting game state, use functions from `game_service.py` to ensure WebSocket broadcasts +## SQLite + Alembic Migrations + +This project uses **SQLite** as its database. SQLite has limited ALTER TABLE support, so Alembic uses **batch mode** (`render_as_batch=True` in `migrations/env.py`) to handle schema changes by recreating tables behind the scenes. + +**When writing or generating migrations, you MUST:** +- **Always test migrations can actually run** against SQLite — don't just generate and commit blindly. +- **Watch for circular dependency errors** in batch mode. If a table has foreign keys (especially self-referential or mutual FKs like `games` ↔ `teams`), splitting a single `batch_alter_table` into multiple calls (e.g., one for column adds, one for FK creation) avoids `CircularDependencyError`. +- **Make migrations idempotent when possible** — check if columns/tables already exist before adding them, especially if production DB state may have drifted from Alembic history. Use `PRAGMA table_info('table_name')` to inspect existing columns. +- **Never combine column adds/drops with FK changes** in a single `batch_alter_table` block on tables that have existing foreign keys. + ## Important Notes - **Port 5000 conflict**: macOS AirPlay Receiver uses port 5000 by default. Use `PORT=5001` when running the backend. diff --git a/migrations/env.py b/migrations/env.py index 4c97092..9ee8a6c 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -100,6 +100,7 @@ def run_migrations_online(): context.configure( connection=connection, target_metadata=get_metadata(), + render_as_batch=True, **conf_args )