"""Add account_id to audit_logs and backfill via user_id. Revision ID: 2a9056eddd90 Revises: 70a5dd746e83 Create Date: 2026-04-11 00:00:00.000000 """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa revision: str = '2a9056eddd90' down_revision: Union[str, None] = '70a5dd746e83' branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: op.add_column('audit_logs', sa.Column('account_id', sa.UUID(), nullable=True)) op.create_foreign_key( 'fk_audit_logs_account_id', 'audit_logs', 'accounts', ['account_id'], ['id'], ondelete='CASCADE', ) # Backfill: derive from the acting user's account op.execute(""" UPDATE audit_logs al SET account_id = u.account_id FROM users u WHERE al.user_id = u.id AND u.account_id IS NOT NULL AND al.account_id IS NULL """) result = op.get_bind().execute( sa.text("SELECT COUNT(*) FROM audit_logs WHERE account_id IS NULL") ) count = result.scalar() if count > 0: raise RuntimeError( f"ROLLBACK: {count} audit_logs rows have NULL account_id after backfill. " "All audit log entries must have an associated user with an account." ) op.alter_column('audit_logs', 'account_id', nullable=False) op.create_index('ix_audit_logs_account_id', 'audit_logs', ['account_id']) def downgrade() -> None: op.drop_index('ix_audit_logs_account_id', table_name='audit_logs') op.drop_constraint('fk_audit_logs_account_id', 'audit_logs', type_='foreignkey') op.drop_column('audit_logs', 'account_id')