"""initial models Revision ID: 001_initial Revises: Create Date: 2026-03-17 """ from collections.abc import Sequence import sqlalchemy as sa from alembic import op revision: str = "001_initial" down_revision: str | None = None branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: # --- users --- op.create_table( "users", sa.Column("id", sa.Uuid(), nullable=False), sa.Column("email", sa.String(255), nullable=False), sa.Column("hashed_password", sa.String(255), nullable=False), sa.Column("full_name", sa.String(100), nullable=False), sa.Column("is_active", sa.Boolean(), nullable=False, server_default="true"), sa.Column( "created_at", sa.DateTime(timezone=False), nullable=False, server_default=sa.text("now()"), ), sa.Column( "updated_at", sa.DateTime(timezone=False), nullable=False, server_default=sa.text("now()"), ), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("email"), ) op.create_index("ix_users_email", "users", ["email"]) # --- categories --- op.create_table( "categories", sa.Column("id", sa.Uuid(), nullable=False), sa.Column("user_id", sa.Uuid(), nullable=False), sa.Column("name", sa.String(50), nullable=False), sa.Column("type", sa.String(10), nullable=False), sa.Column("color", sa.String(7), nullable=True), sa.Column("icon", sa.String(50), nullable=True), sa.Column("is_default", sa.Boolean(), nullable=False, server_default="false"), sa.Column("deleted_at", sa.DateTime(timezone=False), nullable=True), sa.Column( "created_at", sa.DateTime(timezone=False), nullable=False, server_default=sa.text("now()"), ), sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), ) op.create_index("ix_categories_user_id", "categories", ["user_id"]) # --- transactions --- op.create_table( "transactions", sa.Column("id", sa.Uuid(), nullable=False), sa.Column("user_id", sa.Uuid(), nullable=False), sa.Column("category_id", sa.Uuid(), nullable=False), sa.Column("amount_cents", sa.Integer(), nullable=False), sa.Column("type", sa.String(10), nullable=False), sa.Column("description", sa.String(255), nullable=True), sa.Column("transaction_date", sa.Date(), nullable=False), sa.Column("deleted_at", sa.DateTime(timezone=False), nullable=True), sa.Column( "created_at", sa.DateTime(timezone=False), nullable=False, server_default=sa.text("now()"), ), sa.Column( "updated_at", sa.DateTime(timezone=False), nullable=False, server_default=sa.text("now()"), ), sa.CheckConstraint("amount_cents > 0", name="ck_transactions_amount_positive"), sa.ForeignKeyConstraint(["category_id"], ["categories.id"]), sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), ) op.create_index( "ix_transactions_user_date", "transactions", ["user_id", "transaction_date", "deleted_at"], ) op.create_index( "ix_transactions_user_category", "transactions", ["user_id", "category_id", "deleted_at"], ) # --- budgets --- op.create_table( "budgets", sa.Column("id", sa.Uuid(), nullable=False), sa.Column("user_id", sa.Uuid(), nullable=False), sa.Column("category_id", sa.Uuid(), nullable=False), sa.Column("month", sa.String(7), nullable=False), sa.Column("limit_cents", sa.Integer(), nullable=False), sa.Column( "created_at", sa.DateTime(timezone=False), nullable=False, server_default=sa.text("now()"), ), sa.Column( "updated_at", sa.DateTime(timezone=False), nullable=False, server_default=sa.text("now()"), ), sa.CheckConstraint("limit_cents > 0", name="ck_budgets_limit_positive"), sa.ForeignKeyConstraint(["category_id"], ["categories.id"]), sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint( "user_id", "category_id", "month", name="uq_budgets_user_category_month" ), ) op.create_index("ix_budgets_user_id", "budgets", ["user_id"]) # --- refresh_tokens --- op.create_table( "refresh_tokens", sa.Column("id", sa.Uuid(), nullable=False), sa.Column("user_id", sa.Uuid(), nullable=False), sa.Column("token_hash", sa.String(64), nullable=False), sa.Column("expires_at", sa.DateTime(timezone=False), nullable=False), sa.Column("revoked_at", sa.DateTime(timezone=False), nullable=True), sa.Column( "created_at", sa.DateTime(timezone=False), nullable=False, server_default=sa.text("now()"), ), sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("token_hash"), ) op.create_index("ix_refresh_tokens_user_id", "refresh_tokens", ["user_id"]) def downgrade() -> None: op.drop_table("refresh_tokens") op.drop_table("budgets") op.drop_table("transactions") op.drop_table("categories") op.drop_table("users")