diff --git a/.cursor/rules/backend-rules.mdc b/.cursor/rules/backend-rules.mdc index 3a6349297..5949f8131 100644 --- a/.cursor/rules/backend-rules.mdc +++ b/.cursor/rules/backend-rules.mdc @@ -47,7 +47,9 @@ If necessary (like editing ), refer [sync-architecture.mdc](mdc:.cursor/rules/sy - **Config** (`core/config.py`): Environment-based configuration - **Logging** (`core/logging.py`): Structured logging system - **Exceptions** (`core/exceptions.py`): Centralized error handling -- **Migrations** (`alembic/`): Database schema versioning +- **Migrations** (`alembic/`): Database schema versioning. `env.py` sets + a 10 s `lock_timeout` by default. Always use `CREATE INDEX CONCURRENTLY` + (via `autocommit_block`) and expand-contract for breaking schema changes. ## Data Flow diff --git a/backend/alembic/env.py b/backend/alembic/env.py index ed4f261db..ad8a556a8 100755 --- a/backend/alembic/env.py +++ b/backend/alembic/env.py @@ -8,7 +8,7 @@ from pathlib import Path from dotenv import load_dotenv -from sqlalchemy import engine_from_config, pool +from sqlalchemy import engine_from_config, pool, text from alembic import context @@ -93,6 +93,7 @@ def run_migrations_online() -> None: context.configure(connection=connection, target_metadata=target_metadata, compare_type=True) with context.begin_transaction(): + connection.execute(text("SET lock_timeout = '10s'")) context.run_migrations() diff --git a/backend/alembic/script.py.mako b/backend/alembic/script.py.mako index 2c0156303..8a2a4cd11 100755 --- a/backend/alembic/script.py.mako +++ b/backend/alembic/script.py.mako @@ -15,6 +15,25 @@ down_revision = ${repr(down_revision)} branch_labels = ${repr(branch_labels)} depends_on = ${repr(depends_on)} +# --- DDL safety checklist (remove before committing) --- +# +# [ ] lock_timeout: env.py sets a 10s default. Override per-statement +# with op.execute("SET lock_timeout = '30s'") if needed. +# +# [ ] CREATE INDEX CONCURRENTLY: requires autocommit (non-transactional) +# mode. Use: +# with op.get_context().autocommit_block(): +# op.create_index(..., postgresql_concurrently=True) +# +# [ ] ADD COLUMN with DEFAULT: PG 11+ handles non-volatile defaults +# (literals, immutable functions) as metadata-only. Volatile +# defaults (e.g. clock_timestamp()) still rewrite the table. +# +# [ ] Breaking schema changes: use expand-contract. Deploy the new +# schema (expand) first, migrate data/code, then drop the old +# schema (contract) in a later migration. +# --- + def upgrade(): ${upgrades if upgrades else "pass"} diff --git a/backend/entrypoint.dev.sh b/backend/entrypoint.dev.sh index 027e929b5..e07738193 100644 --- a/backend/entrypoint.dev.sh +++ b/backend/entrypoint.dev.sh @@ -21,10 +21,17 @@ def check_db(): check_db() " -# Run migrations using our existing Alembic setup -echo "Running database migrations..." -cd /app && poetry run alembic upgrade head -# cd /app #dev time to not rerun alembic on conflicting branches +# Run migrations unless explicitly disabled +_migrate_flag="$(echo "${RUN_ALEMBIC_MIGRATIONS:-true}" | tr '[:upper:]' '[:lower:]')" +case "$_migrate_flag" in + true|1|yes|on) + echo "Running database migrations..." + cd /app && poetry run alembic upgrade head + ;; + *) + echo "Skipping migrations (RUN_ALEMBIC_MIGRATIONS=$RUN_ALEMBIC_MIGRATIONS)" + ;; +esac # Start application with hot reloading enabled echo "Starting application with hot reloading..." diff --git a/backend/entrypoint.sh b/backend/entrypoint.sh index e31f23b0e..5312d1417 100644 --- a/backend/entrypoint.sh +++ b/backend/entrypoint.sh @@ -46,10 +46,17 @@ except Exception as e: sys.exit(1) " -# Run migrations using our existing Alembic setup -echo "Running database migrations..." -cd /app && poetry run alembic upgrade heads -# cd /app #dev time to not rerun alembic on conflicting branches +# Run migrations unless explicitly disabled +_migrate_flag="$(echo "${RUN_ALEMBIC_MIGRATIONS:-true}" | tr '[:upper:]' '[:lower:]')" +case "$_migrate_flag" in + true|1|yes|on) + echo "Running database migrations..." + cd /app && poetry run alembic upgrade heads + ;; + *) + echo "Skipping migrations (RUN_ALEMBIC_MIGRATIONS=$RUN_ALEMBIC_MIGRATIONS)" + ;; +esac # Start application echo "Starting application..."