# FastAPI Migration Management Guide

This guide explains how to handle database migrations in your FastAPI application, equivalent to Django's `manage.py migrate` functionality.

## Overview

Your FastAPI project now includes a complete migration management system using **Alembic** (the standard migration tool for SQLAlchemy/SQLModel). This provides Django-like migration functionality with the syntax:

```bash
uv run python oppman.py migrate [command]
```

## Quick Start

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

```bash
uv run 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 New Models to `models.py`

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

```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
uv run python oppman.py migrate create "Add Order model"
```

### 4. Apply the Migration

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

## Available Commands

### Basic Commands

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

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

# Apply all pending migrations
uv run python oppman.py migrate upgrade

# Check current status
uv run python oppman.py migrate current

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

### Advanced Commands

```bash
# Downgrade to previous revision
uv run python oppman.py migrate downgrade <revision>

# Show details of a migration
uv run python oppman.py migrate show <revision>

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

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

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

## Workflow Examples

### Adding a New Table

1. **Add model to `models.py`**:
```python
class Category(SQLModel, table=True):
    __tablename__ = "categories"
    
    id: Optional[uuid.UUID] = Field(default_factory=uuid.uuid4, primary_key=True)
    name: str = Field(max_length=100, nullable=False)
    description: Optional[str] = Field(default=None)
```

2. **Create migration**:
```bash
uv run python oppman.py migrate create "Add categories table"
```

3. **Apply migration**:
```bash
uv run python oppman.py migrate upgrade
```

4. **Verify**:
```bash
uv run python oppman.py migrate current
```

### Modifying Existing Table

1. **Modify model in `models.py`**:
```python
class User(SQLModel, table=True):
    __tablename__ = "users"
    
    id: Optional[uuid.UUID] = Field(default_factory=uuid.uuid4, primary_key=True)
    email: str = Field(unique=True, index=True, nullable=False)
    hashed_password: str = Field(nullable=False)
    is_active: bool = Field(default=True)
    is_superuser: bool = Field(default=False)
    # Add new field
    phone_number: Optional[str] = Field(default=None, max_length=20)
```

2. **Create migration**:
```bash
uv run python oppman.py migrate create "Add phone number to users"
```

3. **Apply migration**:
```bash
uv run python oppman.py migrate upgrade
```

## File Structure

```
fastapi_d/
├── models.py                    # Your SQLModel models
├── alembic/                     # Generated by migrate init
│   ├── versions/               # Migration files
│   ├── env.py                 # Alembic environment
│   └── script.py.mako         # Migration template
├── alembic.ini                # Alembic configuration
├── scripts/migrate/           # Migration management
│   ├── core.py               # Core functionality
│   ├── cli.py                # Command interface
│   └── README.md             # Detailed documentation
└── oppman.py                 # Main management script
```

## Comparison with Django

| Django Command | FastAPI Equivalent |
|----------------|-------------------|
| `python manage.py migrate` | `python oppman.py migrate upgrade` |
| `python manage.py makemigrations` | `python oppman.py migrate create "Description"` |
| `python manage.py showmigrations` | `python oppman.py migrate history` |
| `python manage.py migrate --plan` | `python oppman.py migrate check` |

## Troubleshooting

### Common Issues

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

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

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

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

### Database Issues

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

## Resetting the database and migrations

Sometimes you want to wipe the database and start over with a clean set of migration files. The `delete` command now backs up and removes both the SQLite database and all Alembic migration files under `alembic/versions/`.

### Delete database and migration files

```bash
uv run python oppman.py delete
```

This will:

- Back up the current database to `test.db.YYYYMMDD_HHMMSS`.
- Back up all migration files to `alembic/versions_backup_YYYYMMDD_HHMMSS/`.
- Delete all `alembic/versions/*.py` files and clean `__pycache__`.

### Recreate migrations

Use this when you have deleted the previous migration history and want to generate a fresh migration that reflects the current state of `models.py` and then apply it.

```bash
# Optional: ensure Alembic config is aligned (DB URL, imports)
uv run python oppman.py migrate setup

# Create a fresh initial migration from current models
uv run python oppman.py migrate create "Initial"

# Apply the migration to the (empty) database
uv run python oppman.py migrate upgrade
```

### How "Recreate migrations" differs from `uv run python oppman.py db`

- **Recreate migrations (create + upgrade)**: Uses Alembic to generate a migration file and apply it. This creates a proper migration history you can commit to version control, review, and use for upgrades/downgrades in all environments.
- **`uv run python oppman.py db`**: Directly creates tables via `SQLModel.metadata.create_all` without generating or applying Alembic migrations. This is convenient for quick local setups but does not produce migration files or history.

Recommended:

- Use the migration workflow for team/production workflows.
- Use `db` for quick local prototyping when migration history is not required.

## 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**

## Integration with Existing Commands

The migration system integrates seamlessly with your existing `oppman.py` commands:

```bash
# Database management
uv run python oppman.py db              # Initialize database
uv run python oppman.py backup          # Backup database
uv run python oppman.py delete          # Delete database

# Migration management
uv run python oppman.py migrate init    # Initialize migrations
uv run python oppman.py migrate create  # Create migration
uv run python oppman.py migrate upgrade # Apply migrations

# Server management
uv run python oppman.py runserver       # Start development server
uv run python oppman.py production      # Start production server
```

## 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: 8e825dae1884
Revises: 
Create Date: 2024-01-01 12:00:00.000000

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

# revision identifiers
revision = '8e825dae1884'
down_revision = None
branch_labels = None
depends_on = None

def upgrade() -> None:
    # Upgrade operations
    op.create_table('users',
        sa.Column('id', sa.UUID(), nullable=False),
        sa.Column('email', sa.String(), nullable=False),
        sa.Column('hashed_password', sa.String(), nullable=False),
        sa.Column('is_active', sa.Boolean(), nullable=True),
        sa.Column('is_superuser', sa.Boolean(), nullable=True),
        sa.PrimaryKeyConstraint('id')
    )
    op.create_table('products',
        sa.Column('id', sa.UUID(), nullable=False),
        sa.Column('name', sa.String(length=100), nullable=False),
        sa.Column('description', sa.String(), nullable=True),
        sa.Column('price', sa.Float(), nullable=False),
        sa.Column('category', sa.String(length=50), nullable=True),
        sa.Column('in_stock', sa.Boolean(), nullable=True),
        sa.Column('created_at', sa.DateTime(), nullable=True),
        sa.Column('updated_at', sa.DateTime(), nullable=True),
        sa.PrimaryKeyConstraint('id')
    )

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

## Next Steps

1. **Initialize migrations**: `uv run python oppman.py migrate init`
2. **Add your models** to `models.py`
3. **Create migrations** as you develop: `uv run python oppman.py migrate create "Description"`
4. **Apply migrations** to update your database: `uv run python oppman.py migrate upgrade`
5. **Use in production** by running migrations before starting your server

This migration system provides the same functionality as Django's `manage.py migrate` but is tailored for your FastAPI + SQLModel setup.

## Registering a model in the SQLAdmin panel

Follow these steps to make a new model appear in the SQLAdmin UI. The examples use the `Partner` model, but the flow is the same for any model. All migration commands are run via your custom `oppman.py` tool.

1. Define the model in `models.py`.

   ```python
   # models.py
   class Partner(SQLModel, table=True):
       __tablename__ = "partners"
       id: Optional[uuid.UUID] = Field(default_factory=uuid.uuid4, primary_key=True)
       name: str = Field(max_length=100, nullable=False)
       email: str = Field(unique=True, index=True, nullable=False)
   ```

2. Create a ModelView in `admin/views.py`.

   ```python
   # admin/views.py
   from sqladmin import ModelView
   from models import Partner

   class PartnerAdmin(ModelView, model=Partner):
       column_list = ["name", "email"]
   ```

3. Register the view in `admin/setup.py`.

   ```python
   # admin/setup.py
   from .views import UserAdmin, ProductAdmin, WebinarRegistrantsAdmin, AuditLogAdmin, PartnerAdmin

   def setup_admin(app: FastAPI, secret_key: str):
       admin = Admin(app, async_engine, authentication_backend=AdminAuth(secret_key=secret_key))
       admin.add_view(UserAdmin)
       admin.add_view(ProductAdmin)
       admin.add_view(WebinarRegistrantsAdmin)
       admin.add_view(AuditLogAdmin)
       admin.add_view(PartnerAdmin)  # <- new
       return admin
   ```

4. Ensure Alembic "sees" the new model, then create and apply a migration using `oppman.py`.

   ```bash
   # Update Alembic environment/imports (handled by the migrate setup command)
   uv run python oppman.py migrate setup

   # Create a migration for the new table
   uv run python oppman.py migrate create "Add partners table"

   # Apply the migration
   uv run python oppman.py migrate upgrade
   ```

   Note: If you prefer to verify manually, ensure `alembic/env.py` imports your new model so that autogenerate includes it (e.g., `from models import Partner`). The `uv run python oppman.py migrate setup` command typically takes care of this.

5. Restart the server and sign in to `/admin`.

   - You must log in as a user with `is_staff` or `is_superuser` to see the admin panel.
   - The new model (e.g., "Partner") should now appear in the sidebar.
