"""E2 B21: аудит (audit_events + audit_changes, immutable, 90 дней). Revision ID: 008_e2_audit Revises: 007_e1_rbac """ from __future__ import annotations import sqlalchemy as sa from alembic import op from sqlalchemy.dialects import postgresql as pg revision = '008_e2_audit' down_revision = '007_e1_rbac' branch_labels = None depends_on = None def upgrade() -> None: op.create_table( 'audit_events', sa.Column('id', pg.UUID(as_uuid=True), primary_key=True, server_default=sa.text('gen_random_uuid()')), sa.Column('user_id', pg.UUID(as_uuid=True), sa.ForeignKey('users.id', ondelete='SET NULL')), sa.Column('username', sa.String(100)), sa.Column('event_type', sa.String(40), nullable=False), sa.Column('object_type', sa.String(40)), sa.Column('object_id', sa.String(64)), sa.Column('ip_address', sa.String(64)), sa.Column('user_agent', sa.String(255)), sa.Column('details', sa.JSON().with_variant(pg.JSONB(), 'postgresql')), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('NOW()')), ) op.create_index('idx_audit_events_created', 'audit_events', ['created_at']) op.create_table( 'audit_changes', sa.Column('id', pg.UUID(as_uuid=True), primary_key=True, server_default=sa.text('gen_random_uuid()')), sa.Column('event_id', pg.UUID(as_uuid=True), sa.ForeignKey('audit_events.id', ondelete='CASCADE'), nullable=False), sa.Column('field_name', sa.String(100), nullable=False), sa.Column('old_value', sa.Text()), sa.Column('new_value', sa.Text()), ) op.create_index('idx_audit_changes_event', 'audit_changes', ['event_id']) def downgrade() -> None: op.drop_index('idx_audit_changes_event', table_name='audit_changes') op.drop_table('audit_changes') op.drop_index('idx_audit_events_created', table_name='audit_events') op.drop_table('audit_events')