# Migration Management System

This directory contains the migration management system for the FastAPI admin application, providing Django-like migration functionality using Alembic.

## Overview

The migration system allows you to:
- Initialize Alembic for database migrations
- Create migrations from model changes
- Apply migrations to update the database
- Rollback migrations if needed
- View migration history and status

## Quick Start

### 1. Initialize Migrations (First Time Only)

```bash
python oppman.py migrate init
```

This will:
- Initialize Alembic in your project
- Create `alembic/` directory and `alembic.ini`
- Configure the database URL for SQLite
- Set up model imports in `alembic/env.py`

### 2. Add a New Model

Edit `models.py` to add your new model:

```python
class Order(SQLModel, table=True):
    __tablename__ = "orders"
    
    id: Optional[uuid.UUID] = Field(default_factory=uuid.uuid4, primary_key=True)
    user_id: uuid.UUID = Field(foreign_key="users.id", nullable=False)
    total_amount: float = Field(nullable=False)
    status: str = Field(default="pending", max_length=20)
    created_at: datetime = Field(default_factory=datetime.utcnow)
```

### 3. Create a Migration

```bash
python oppman.py migrate create "Add Order model"
```

### 4. Apply the Migration

```bash
python oppman.py migrate upgrade
```

## Available Commands

### Basic Commands

```bash
# Initialize Alembic (first time only)
python oppman.py migrate init

# Create a new migration
python oppman.py migrate create "Description of changes"

# Apply all pending migrations
python oppman.py migrate upgrade

# Apply to specific revision
python oppman.py migrate upgrade abc123def

# Check current status
python oppman.py migrate current

# View migration history
python oppman.py migrate history
```

### Advanced Commands

```bash
# Downgrade to previous revision
python oppman.py migrate downgrade abc123def

# Show details of a migration
python oppman.py migrate show abc123def

# Mark database as up to date without running migrations
python oppman.py migrate stamp head

# Check if database is up to date
python oppman.py migrate check

# Update configuration files
python oppman.py migrate setup
```

## Workflow

### Development Workflow

1. **Add/Modify Models**: Edit `models.py` with your changes
2. **Create Migration**: `python oppman.py migrate create "Description"`
3. **Review Migration**: Check the generated file in `alembic/versions/`
4. **Apply Migration**: `python oppman.py migrate upgrade`
5. **Verify**: `python oppman.py migrate current`

### Production Workflow

1. **Deploy Code**: Deploy your updated code with new migrations
2. **Apply Migrations**: `python oppman.py migrate upgrade`
3. **Verify**: `python oppman.py migrate check`

## File Structure

```
scripts/migrate/
├── __init__.py          # Package initialization
├── core.py              # Core migration management
├── cli.py               # Command-line interface
├── example.py           # Example usage
└── README.md           # This file

alembic/                 # Generated by migrate init
├── versions/            # Migration files
├── env.py              # Alembic environment
└── script.py.mako      # Migration template

alembic.ini             # Alembic configuration
```

## Troubleshooting

### Common Issues

1. **"Alembic not found"**
   ```bash
   uv add alembic
   ```

2. **"Alembic not initialized"**
   ```bash
   python oppman.py migrate init
   ```

3. **Migration conflicts**
   ```bash
   # Check current status
   python oppman.py migrate current
   
   # View history
   python oppman.py migrate history
   
   # Downgrade if needed
   python oppman.py migrate downgrade <revision>
   ```

4. **Configuration issues**
   ```bash
   python oppman.py migrate setup
   ```

### Database Issues

- **SQLite**: Uses `test.db` in project root
- **Backup**: `python oppman.py backup` before major changes
- **Reset**: `python oppman.py delete` to start fresh

## Examples

### Adding a New Table

```bash
# 1. Add model to models.py
# 2. Create migration
python oppman.py migrate create "Add categories table"

# 3. Apply migration
python oppman.py migrate upgrade

# 4. Verify
python oppman.py migrate current
```

### Modifying Existing Table

```bash
# 1. Modify model in models.py
# 2. Create migration
python oppman.py migrate create "Add email field to users"

# 3. Apply migration
python oppman.py migrate upgrade
```

### Rolling Back Changes

```bash
# 1. Check current revision
python oppman.py migrate current

# 2. Downgrade to previous revision
python oppman.py migrate downgrade <previous_revision>

# 3. Verify
python oppman.py migrate current
```

## Integration with oppman.py

The migration system is fully integrated with `oppman.py`:

```bash
# All migration commands work through oppman.py
python oppman.py migrate init
python oppman.py migrate create "Add new feature"
python oppman.py migrate upgrade
python oppman.py migrate current
```

## Best Practices

1. **Always create migrations** for model changes
2. **Use descriptive messages** when creating migrations
3. **Test migrations** in development before production
4. **Backup database** before applying migrations in production
5. **Review generated migrations** before applying them
6. **Keep migrations in version control**

## Migration Files

Migration files are stored in `alembic/versions/` and contain:
- **Upgrade operations**: Changes to apply to database
- **Downgrade operations**: How to reverse the changes
- **Metadata**: Migration information and dependencies

Example migration file:
```python
"""Add Order model

Revision ID: abc123def456
Revises: def456abc789
Create Date: 2024-01-01 12:00:00.000000

"""
from alembic import op
import sqlalchemy as sa
import sqlmodel

# revision identifiers
revision = 'abc123def456'
down_revision = 'def456abc789'
branch_labels = None
depends_on = None

def upgrade() -> None:
    # Upgrade operations
    op.create_table('orders',
        sa.Column('id', sa.UUID(), nullable=False),
        sa.Column('user_id', sa.UUID(), nullable=False),
        sa.Column('total_amount', sa.Float(), nullable=False),
        sa.Column('status', sa.String(length=20), nullable=True),
        sa.Column('created_at', sa.DateTime(), nullable=True),
        sa.PrimaryKeyConstraint('id')
    )

def downgrade() -> None:
    # Downgrade operations
    op.drop_table('orders')
``` 