Alembic Migrations — Agent Rules
Parent rules:
/workspace/backend/agents.md
Generating Migrations
- Generate via
make migrate-new(oralembic revision --autogenerate -m "description"). - Never hand-edit DDL or write raw SQL in migration files unless autogenerate cannot handle the change.
Migration Requirements
- Every migration must include both
upgrade()anddowngrade()functions. - Use descriptive revision messages:
"add widget config_overrides column", not"update". - Test both upgrade and downgrade paths.
Scope
- Migrations apply to PostgreSQL only — application metadata tables.
- Never write migrations for ClickHouse, Materialize, or Redis.
Adding New Models
When adding a new SQLAlchemy model:
- Create the model in
app/models/. - Import the model in
alembic/env.pyso autogenerate detects it. - Run
make migrate-newto generate the migration. - Review the generated migration for correctness.
- Apply with
make migrate-up.
Multi-Tenancy Migration Rules
- All tenant-scoped tables (
users,workflows,dashboards,api_keys) MUST have atenant_id UUID NOT NULLcolumn. - Every
tenant_idcolumn MUST have an index (for query performance on filtered reads). - Consider composite indexes on
(tenant_id, id)or(tenant_id, created_at)for common query patterns. - When adding
tenant_idto existing tables, the migration must provide a default value for existing rows or use a data migration to backfill. - Child tables that inherit tenant scope from a parent (
widgetsviadashboards,dashboard_filtersviadashboards) do NOT get their owntenant_idcolumn. - PostgreSQL Row-Level Security (RLS) policies should be added as a defense-in-depth backstop:
CREATE POLICY tenant_isolation ON <table> USING (tenant_id = current_setting('app.current_tenant')::uuid). These are safety nets — the application layer is the primary enforcement mechanism.