# Alembic Database Migrations This directory contains **Alembic** database migrations for the LOAF membership platform. ## What is Alembic? Alembic is a lightweight database migration tool for SQLAlchemy. It allows you to: - Track database schema changes over time - Apply migrations incrementally - Roll back changes if needed - Auto-generate migration scripts from model changes ## Directory Structure ``` alembic/ ├── versions/ # Migration scripts (KEEP IN VERSION CONTROL) │ └── *.py # Individual migration files ├── env.py # Alembic environment configuration ├── script.py.mako # Template for new migration files └── README.md # This file ``` ## Quick Start ### 1. Create a New Migration After making changes to `models.py`, generate a migration: ```bash cd backend alembic revision --autogenerate -m "add_user_bio_field" ``` This will create a new file in `alembic/versions/` like: ``` 3e02c74581c9_add_user_bio_field.py ``` ### 2. Review the Generated Migration **IMPORTANT:** Always review auto-generated migrations before applying them! ```bash # Open the latest migration file cat alembic/versions/3e02c74581c9_add_user_bio_field.py ``` Check: - ✅ The `upgrade()` function contains the correct changes - ✅ The `downgrade()` function properly reverses those changes - ✅ No unintended table drops or data loss ### 3. Apply the Migration ```bash # Apply all pending migrations alembic upgrade head # Or apply migrations one at a time alembic upgrade +1 ``` ### 4. Rollback a Migration ```bash # Rollback the last migration alembic downgrade -1 # Rollback to a specific revision alembic downgrade 3e02c74581c9 ``` ## Common Commands | Command | Description | |---------|-------------| | `alembic current` | Show current migration revision | | `alembic history` | Show migration history | | `alembic heads` | Show head revisions | | `alembic upgrade head` | Apply all pending migrations | | `alembic downgrade -1` | Rollback last migration | | `alembic revision --autogenerate -m "message"` | Create new migration | | `alembic stamp head` | Mark database as up-to-date without running migrations | ## Migration Workflow ### For Development 1. **Make changes to `models.py`** ```python # In models.py class User(Base): # ...existing fields... bio = Column(Text, nullable=True) # New field ``` 2. **Generate migration** ```bash alembic revision --autogenerate -m "add_user_bio_field" ``` 3. **Review the generated file** ```python # In alembic/versions/xxxxx_add_user_bio_field.py def upgrade(): op.add_column('users', sa.Column('bio', sa.Text(), nullable=True)) def downgrade(): op.drop_column('users', 'bio') ``` 4. **Apply migration** ```bash alembic upgrade head ``` 5. **Commit migration file to Git** ```bash git add alembic/versions/xxxxx_add_user_bio_field.py git commit -m "Add user bio field" ``` ### For Production Deployment **Fresh Database (New Installation):** ```bash # 1. Create database createdb membership_db # 2. Run initial schema SQL (creates all 17 tables) psql -U username -d membership_db -f ../migrations/000_initial_schema.sql # 3. Mark database as up-to-date with Alembic alembic stamp head # 4. Verify alembic current # Should show: 001_initial_baseline (head) ``` **Existing Database (Apply New Migrations):** ```bash # 1. Pull latest code git pull origin main # 2. Apply migrations alembic upgrade head # 3. Verify alembic current # 4. Restart application systemctl restart membership-backend ``` ## Configuration ### Database Connection Alembic reads the `DATABASE_URL` from your `.env` file: ```env DATABASE_URL=postgresql://user:password@localhost:5432/membership_db ``` The connection is configured in `alembic/env.py` (lines 29-36). ### Target Metadata Alembic uses `Base.metadata` from `models.py` to detect changes: ```python # In alembic/env.py from models import Base target_metadata = Base.metadata ``` ## Important Notes ### ✅ DO: - Always review auto-generated migrations before applying - Test migrations in development before production - Commit migration files to version control - Write descriptive migration messages - Include both `upgrade()` and `downgrade()` functions ### ❌ DON'T: - Don't edit migration files after they've been applied in production - Don't delete migration files from `alembic/versions/` - Don't modify the `revision` or `down_revision` values - Don't commit `.pyc` files (already in .gitignore) ## Migration History | Revision | Description | Date | Type | |----------|-------------|------|------| | `001_initial_baseline` | Baseline marker (empty migration) | 2026-01-02 | Baseline | **Note:** The actual initial schema is created by running `backend/migrations/000_initial_schema.sql`. The baseline migration is an empty marker that indicates the starting point for Alembic tracking. ## Troubleshooting ### "Target database is not up to date" ```bash # Check current revision alembic current # Check pending migrations alembic history # Apply missing migrations alembic upgrade head ``` ### "FAILED: Can't locate revision identified by 'xxxxx'" The database thinks it's at a revision that doesn't exist in your `alembic/versions/`. **Solution:** ```bash # Mark database at a known good revision alembic stamp head ``` ### Migration conflicts If you get merge conflicts in migration files: 1. Resolve conflicts in the migration file 2. Ensure `revision` and `down_revision` chain is correct 3. Test the migration locally ### Fresh database setup For a completely new database: ```bash # Step 1: Run initial schema SQL psql -U username -d membership_db -f ../migrations/000_initial_schema.sql # Step 2: Mark as up-to-date alembic stamp head # Step 3: Verify alembic current # Should show: 001_initial_baseline (head) ``` ## Legacy Migrations Old numbered SQL migrations (`000_initial_schema.sql` through `011_wordpress_import_enhancements.sql`) are preserved in `backend/migrations/` for reference. These have been consolidated into the initial Alembic migration. **Going forward, all new migrations must use Alembic.** ## Additional Resources - [Alembic Documentation](https://alembic.sqlalchemy.org/) - [SQLAlchemy Documentation](https://docs.sqlalchemy.org/) - [PostgreSQL Documentation](https://www.postgresql.org/docs/)