260 lines
6.3 KiB
Markdown
260 lines
6.3 KiB
Markdown
# 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/)
|