skills/awais68/db-migration/SKILL.md
Use when setting up Alembic migrations or making database schema changes. Triggers for: initializing Alembic, generating migrations, applying upgrades, rolling back changes, or creating data migrations. NOT for: raw SQL execution outside migration context or non-database schema updates.
npx skillsauth add aiskillstore/marketplace db-migrationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert Alembic migration management for SQLModel/FastAPI projects with safe schema evolution and rollback capabilities.
| Command | Purpose |
|---------|---------|
| alembic init alembic | Initialize Alembic in project |
| alembic revision --autogenerate -m "message" | Generate migration from model changes |
| alembic revision -m "message" | Create empty migration manually |
| alembic upgrade head | Apply all pending migrations |
| alembic upgrade +1 | Apply one migration at a time |
| alembic downgrade -1 | Rollback last migration |
| alembic downgrade base | Rollback all migrations |
| alembic current | Show current revision |
| alembic history | Show migration history |
alembic init alembic
# alembic.ini
sqlalchemy.url = driver://user:pass@localhost/dbname
file_template = %%(year)s_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d_%%(rev)s_%%(slug)s
timezone = UTC
# alembic/env.py
from logging.config import fileConfig
from sqlalchemy import pool
from sqlalchemy.engine import Connection
from alembic.runtime.migration import MigrationContext
from sqlmodel import SQLModel, create_engine
from myapp.models import * # Import all SQLModel classes
config = context.config
config.set_main_option("sqlalchemy.url", "postgresql://user:pass@localhost/dbname")
target_metadata = SQLModel.metadata
def run_migrations_offline() -> None:
"""Run migrations in 'offline' mode."""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online() -> None:
"""Run migrations in 'online' mode."""
connectable = create_engine(
config.get_main_option("sqlalchemy.url"),
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
# Generate migration automatically based on model diffs
alembic revision --autogenerate -m "add_fees_table"
# With specific revision range
alembic revision --autogenerate -m "add_user_email" --rev-id=abc123
# Create empty migration for manual changes
alembic revision -m "add_status_column"
# alembic/versions/2024_01_15_1200_add_fees_table.py
"""add_fees_table
Revision ID: abc123
Revises: def456
Create Date: 2024-01-15 12:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
from sqlmodel import SQLModel
# revision identifiers
revision = 'abc123'
down_revision = 'def456'
branch_labels = None
depends_on = None
def upgrade() -> None:
op.create_table(
'fees',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('student_id', sa.Integer(), nullable=False),
sa.Column('amount', sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False, default='pending'),
sa.Column('due_date', sa.DateTime(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.Column('updated_at', sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.PrimaryKeyConstraint('id'),
sa.ForeignKeyConstraint(['student_id'], ['students.id']),
)
op.create_index('ix_fees_student_id', 'fees', ['student_id'])
op.create_index('ix_fees_status', 'fees', ['status'])
def downgrade() -> None:
op.drop_index('ix_fees_status', table_name='fees')
op.drop_index('ix_fees_student_id', table_name='fees')
op.drop_table('fees')
# alembic/versions/2024_01_16_0900_add_fees_description.py
"""add_fees_description
Revision ID: ghi789
Revises: abc123
Create Date: 2024-01-16 09:00:00.000000
"""
from alembic import op
def upgrade() -> None:
op.add_column('fees', sa.Column('description', sa.Text(), nullable=True))
def downgrade() -> None:
op.drop_column('fees', 'description')
# Upgrade to latest revision
alembic upgrade head
# Upgrade one step at a time
alembic upgrade +1
# Upgrade to specific revision
alembic upgrade abc123
# Show pending migrations without applying
alembic show heads
alembic history --verbose
# Rollback one migration
alembic downgrade -1
# Rollback to specific revision
alembic downgrade abc123
# Rollback all migrations (empty database)
alembic downgrade base
def downgrade() -> None:
# Always drop indexes before table
op.drop_index('ix_fees_status', table_name='fees')
op.drop_index('ix_fees_student_id', table_name='fees')
# Drop foreign keys before table
op.drop_constraint('fees_student_id_fkey', 'fees', type_='foreignkey')
op.drop_table('fees')
# alembic/versions/2024_01_17_1400_update_fees_status.py
"""update_fees_status_values
Revision ID: jkl012
Revises: ghi789
Create Date: 2024-01-17 14:00:00.000000
"""
from alembic import op
from sqlalchemy import text
def upgrade() -> None:
# Update existing records
op.execute(
text("UPDATE fees SET status = 'pending' WHERE status = 'unpaid'")
)
def downgrade() -> None:
# Revert status values
op.execute(
text("UPDATE fees SET status = 'unpaid' WHERE status = 'pending'")
)
def upgrade() -> None:
# Add new enum type
op.execute("CREATE TYPE fee_status_new AS ENUM ('pending', 'paid', 'overdue', 'waived')")
# Copy data to new type
op.execute("ALTER TABLE fees ALTER COLUMN status TYPE fee_status_new USING status::text::fee_status_new")
# Drop old type
op.execute("DROP TYPE fee_status_old")
def downgrade() -> None:
# Reverse the process
op.execute("ALTER TABLE fees ALTER COLUMN status TYPE VARCHAR(20)")
op.execute("DROP TYPE fee_status_new")
alembic upgrade then alembic downgrade in testDROP TABLE IF EXISTS, DROP COLUMN IF EXISTS| Skill | Integration Point |
|-------|-------------------|
| @sqlmodel-crud | Model changes trigger migrations |
| @fastapi-app | Migrations run at startup or via CLI |
| @jwt-auth | May need to handle auth during migrations |
alembic revision --autogenerate -m "describe_change"
# Then review and edit the generated file
# Check that:
# - Column types match SQLModel definitions
# - Foreign key constraints are correct
# - Indexes are appropriate
# - Default values are set
# In test environment
alembic downgrade base
alembic upgrade head
# Verify all data is intact
# For large tables, use batch updates
def upgrade():
op.execute("""
UPDATE fees SET status = 'pending'
WHERE status IS NULL
LIMIT 10000
""")
project/
├── alembic/
│ ├── env.py # Migration configuration
│ ├── script.py.mako # Template for new migrations
│ ├── README # Alembic documentation
│ └── versions/
│ ├── 2024_01_15_1200_add_fees_table.py
│ └── 2024_01_16_0900_add_fees_description.py
├── myapp/
│ └── models.py # SQLModel definitions
└── alembic.ini # Alembic configuration
development
Apple Human Interface Guidelines for content display components. Use this skill when the user asks about charts component, collection view, image view, web view, color well, image well, activity view, lockup, data visualization, content display, displaying images, rendering web content, color pickers, or presenting collections of items in Apple apps. Also use when the user says how should I display charts, what's the best way to show images, should I use a web view, how do I build a grid of items, what component shows media, or how do I present a share sheet. Cross-references: hig-foundations for color/typography/accessibility, hig-patterns for data visualization patterns, hig-components-layout for structural containers, hig-platforms for platform-specific component behavior.
tools
Automate HelpDesk tasks via Rube MCP (Composio): list tickets, manage views, use canned responses, and configure custom fields. Always search tools first for current schemas.
testing
Expert Haskell engineer specializing in advanced type systems, pure functional design, and high-reliability software. Use PROACTIVELY for type-level programming, concurrency, and architecture guidance.
tools
GraphQL gives clients exactly the data they need - no more, no less. One endpoint, typed schema, introspection. But the flexibility that makes it powerful also makes it dangerous. Without proper controls, clients can craft queries that bring down your server. This skill covers schema design, resolvers, DataLoader for N+1 prevention, federation for microservices, and client integration with Apollo/urql. Key insight: GraphQL is a contract. The schema is the API documentation. Design it carefully.