"""Add password_reset_tokens table. Revision ID: 015 Revises: 014 Create Date: 2026-03-03 Stores one-time password reset tokens with expiry. Tokens are hashed with SHA-256 so a database leak doesn't expose reset links. """ revision = "015" down_revision = "014" branch_labels = None depends_on = None from alembic import op import sqlalchemy as sa from sqlalchemy.dialects.postgresql import UUID def upgrade() -> None: op.create_table( "password_reset_tokens", sa.Column( "id", UUID(as_uuid=True), server_default=sa.text("gen_random_uuid()"), primary_key=True, ), sa.Column( "user_id", UUID(as_uuid=True), sa.ForeignKey("users.id", ondelete="CASCADE"), nullable=False, ), sa.Column( "token_hash", sa.String(64), nullable=False, unique=True, index=True, ), sa.Column( "expires_at", sa.DateTime(timezone=True), nullable=False, ), sa.Column( "used_at", sa.DateTime(timezone=True), nullable=True, ), sa.Column( "created_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), ), ) def downgrade() -> None: op.drop_table("password_reset_tokens")