"""initial schema

Revision ID: ca1f17d23b39
Revises: 
Create Date: 2026-10-27 09:14:29.201197
"""

from __future__ import annotations

from collections.abc import Sequence

from alembic import op
import sqlalchemy as sa

import app.database.base


revision: str = 'ca1f17d23b39'
down_revision: str | None = None
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('admins',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('telegram_id', sa.BigInteger(), nullable=False),
    sa.Column('title', sa.String(length=255), nullable=True),
    sa.Column('is_primary', sa.Boolean(), nullable=False),
    sa.Column('is_env_admin', sa.Boolean(), nullable=False),
    sa.Column('is_active', sa.Boolean(), nullable=False),
    sa.Column('added_by', sa.BigInteger(), nullable=True),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_admins'))
    )
    with op.batch_alter_table('admins', schema=None) as batch_op:
        batch_op.create_index(batch_op.f('ix_admins_telegram_id'), ['telegram_id'], unique=True)

    op.create_table('app_settings',
    sa.Column('key', sa.String(length=128), nullable=False),
    sa.Column('value', sa.Text(), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_by', sa.BigInteger(), nullable=True),
    sa.PrimaryKeyConstraint('key', name=op.f('pk_app_settings'))
    )
    op.create_table('audit_logs',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('actor_id', sa.BigInteger(), nullable=True),
    sa.Column('action', sa.String(length=128), nullable=False),
    sa.Column('entity_type', sa.String(length=64), nullable=True),
    sa.Column('entity_id', sa.String(length=64), nullable=True),
    sa.Column('details', sa.JSON(), nullable=False),
    sa.Column('correlation_id', sa.String(length=64), nullable=True),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_audit_logs'))
    )
    with op.batch_alter_table('audit_logs', schema=None) as batch_op:
        batch_op.create_index('ix_audit_created', ['created_at'], unique=False)
        batch_op.create_index(batch_op.f('ix_audit_logs_action'), ['action'], unique=False)
        batch_op.create_index(batch_op.f('ix_audit_logs_actor_id'), ['actor_id'], unique=False)
        batch_op.create_index(batch_op.f('ix_audit_logs_correlation_id'), ['correlation_id'], unique=False)

    op.create_table('operation_logs',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('correlation_id', sa.String(length=64), nullable=False),
    sa.Column('operation', sa.String(length=128), nullable=False),
    sa.Column('status', sa.Enum('STARTED', 'SUCCESS', 'FAILED', 'UNKNOWN', name='operation_status', native_enum=False, length=32), nullable=False),
    sa.Column('entity_type', sa.String(length=64), nullable=True),
    sa.Column('entity_id', sa.String(length=64), nullable=True),
    sa.Column('error_message', sa.String(length=2000), nullable=True),
    sa.Column('metadata', sa.JSON(), nullable=False),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('finished_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_operation_logs'))
    )
    with op.batch_alter_table('operation_logs', schema=None) as batch_op:
        batch_op.create_index('ix_operation_created', ['created_at'], unique=False)
        batch_op.create_index(batch_op.f('ix_operation_logs_correlation_id'), ['correlation_id'], unique=False)
        batch_op.create_index(batch_op.f('ix_operation_logs_operation'), ['operation'], unique=False)

    op.create_table('publish_channels',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('chat_id', sa.BigInteger(), nullable=False),
    sa.Column('title', sa.String(length=255), nullable=True),
    sa.Column('username', sa.String(length=64), nullable=True),
    sa.Column('chat_type', sa.String(length=32), nullable=False),
    sa.Column('is_active', sa.Boolean(), nullable=False),
    sa.Column('is_default', sa.Boolean(), nullable=False),
    sa.Column('can_post', sa.Boolean(), nullable=True),
    sa.Column('last_checked_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('last_error', sa.String(length=1000), nullable=True),
    sa.Column('added_by', sa.BigInteger(), nullable=True),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_publish_channels'))
    )
    with op.batch_alter_table('publish_channels', schema=None) as batch_op:
        batch_op.create_index(batch_op.f('ix_publish_channels_chat_id'), ['chat_id'], unique=True)

    op.create_table('rate_limit_events',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('telegram_id', sa.BigInteger(), nullable=False),
    sa.Column('action', sa.String(length=64), nullable=False),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_rate_limit_events'))
    )
    with op.batch_alter_table('rate_limit_events', schema=None) as batch_op:
        batch_op.create_index('ix_rate_limit_lookup', ['telegram_id', 'action', 'created_at'], unique=False)

    op.create_table('required_channels',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('chat_id', sa.BigInteger(), nullable=False),
    sa.Column('title', sa.String(length=255), nullable=False),
    sa.Column('invite_link', sa.String(length=512), nullable=False),
    sa.Column('chat_type', sa.String(length=32), nullable=False),
    sa.Column('is_active', sa.Boolean(), nullable=False),
    sa.Column('is_required_globally', sa.Boolean(), nullable=False),
    sa.Column('sort_order', sa.Integer(), nullable=False),
    sa.Column('bot_status', sa.String(length=32), nullable=True),
    sa.Column('last_checked_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('last_error', sa.String(length=1000), nullable=True),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_required_channels'))
    )
    with op.batch_alter_table('required_channels', schema=None) as batch_op:
        batch_op.create_index(batch_op.f('ix_required_channels_chat_id'), ['chat_id'], unique=True)

    op.create_table('source_chats',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('chat_id', sa.BigInteger(), nullable=False),
    sa.Column('title', sa.String(length=255), nullable=True),
    sa.Column('chat_type', sa.String(length=32), nullable=False),
    sa.Column('is_active', sa.Boolean(), nullable=False),
    sa.Column('auto_ingest', sa.Boolean(), nullable=False),
    sa.Column('added_by', sa.BigInteger(), nullable=True),
    sa.Column('last_message_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('last_error', sa.String(length=1000), nullable=True),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_source_chats'))
    )
    with op.batch_alter_table('source_chats', schema=None) as batch_op:
        batch_op.create_index(batch_op.f('ix_source_chats_chat_id'), ['chat_id'], unique=True)

    op.create_table('users',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('telegram_id', sa.BigInteger(), nullable=False),
    sa.Column('username', sa.String(length=64), nullable=True),
    sa.Column('display_name', sa.String(length=255), nullable=True),
    sa.Column('first_seen', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('last_active', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('request_count', sa.Integer(), nullable=False),
    sa.Column('last_request_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('is_blocked', sa.Boolean(), nullable=False),
    sa.Column('blocked_reason', sa.String(length=500), nullable=True),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_users'))
    )
    with op.batch_alter_table('users', schema=None) as batch_op:
        batch_op.create_index(batch_op.f('ix_users_telegram_id'), ['telegram_id'], unique=True)

    op.create_table('media_assets',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('source_chat_id', sa.Integer(), nullable=False),
    sa.Column('source_message_id', sa.BigInteger(), nullable=False),
    sa.Column('file_id', sa.String(length=512), nullable=False),
    sa.Column('file_unique_id', sa.String(length=255), nullable=False),
    sa.Column('media_type', sa.String(length=32), nullable=False),
    sa.Column('mime_type', sa.String(length=128), nullable=True),
    sa.Column('file_name', sa.String(length=255), nullable=True),
    sa.Column('file_size', sa.BigInteger(), nullable=True),
    sa.Column('duration_seconds', sa.Float(), nullable=True),
    sa.Column('width', sa.Integer(), nullable=True),
    sa.Column('height', sa.Integer(), nullable=True),
    sa.Column('thumbnail_file_id', sa.String(length=512), nullable=True),
    sa.Column('original_caption', sa.Text(), nullable=True),
    sa.Column('status', sa.Enum('RECEIVED', 'READY', 'IN_USE', 'INVALID', 'ERROR', 'IGNORED', name='media_status', native_enum=False, length=32), nullable=False),
    sa.Column('error_message', sa.String(length=1000), nullable=True),
    sa.Column('received_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.ForeignKeyConstraint(['source_chat_id'], ['source_chats.id'], name=op.f('fk_media_assets_source_chat_id_source_chats'), ondelete='CASCADE'),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_media_assets')),
    sa.UniqueConstraint('file_unique_id', name='uq_media_file_unique_id'),
    sa.UniqueConstraint('source_chat_id', 'source_message_id', name='uq_media_source_message')
    )
    with op.batch_alter_table('media_assets', schema=None) as batch_op:
        batch_op.create_index(batch_op.f('ix_media_assets_source_chat_id'), ['source_chat_id'], unique=False)
        batch_op.create_index('ix_media_status_received', ['status', 'received_at'], unique=False)

    op.create_table('posts',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('title', sa.String(length=255), nullable=True),
    sa.Column('description', sa.Text(), nullable=True),
    sa.Column('media_asset_id', sa.Integer(), nullable=False),
    sa.Column('cover_file_id', sa.String(length=512), nullable=True),
    sa.Column('caption_override', sa.Text(), nullable=True),
    sa.Column('caption_template_override', sa.Text(), nullable=True),
    sa.Column('buttons_override', sa.JSON(), nullable=True),
    sa.Column('video_link', sa.String(length=512), nullable=True),
    sa.Column('status', sa.Enum('DRAFT', 'READY', 'SCHEDULED', 'PUBLISHED', 'PAUSED', 'ARCHIVED', 'FAILED', name='post_status', native_enum=False, length=32), nullable=False),
    sa.Column('created_by', sa.BigInteger(), nullable=True),
    sa.Column('published_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('scheduled_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('auto_delete_enabled', sa.Boolean(), nullable=True),
    sa.Column('user_delete_after_seconds', sa.Integer(), nullable=True),
    sa.Column('channel_delete_after_seconds', sa.Integer(), nullable=True),
    sa.Column('membership_mode', sa.Enum('INHERIT', 'ENFORCE', 'DISABLE', name='membership_mode', native_enum=False, length=32), nullable=False),
    sa.Column('protect_content', sa.Boolean(), nullable=True),
    sa.Column('publish_count', sa.Integer(), nullable=False),
    sa.Column('last_error', sa.String(length=2000), nullable=True),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.ForeignKeyConstraint(['media_asset_id'], ['media_assets.id'], name=op.f('fk_posts_media_asset_id_media_assets'), ondelete='RESTRICT'),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_posts'))
    )
    with op.batch_alter_table('posts', schema=None) as batch_op:
        batch_op.create_index(batch_op.f('ix_posts_media_asset_id'), ['media_asset_id'], unique=False)
        batch_op.create_index(batch_op.f('ix_posts_status'), ['status'], unique=False)
        batch_op.create_index('ix_posts_status_created', ['status', 'created_at'], unique=False)

    op.create_table('access_tokens',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('post_id', sa.Integer(), nullable=False),
    sa.Column('token', sa.String(length=64), nullable=False),
    sa.Column('is_active', sa.Boolean(), nullable=False),
    sa.Column('expires_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('max_uses', sa.Integer(), nullable=True),
    sa.Column('use_count', sa.Integer(), nullable=False),
    sa.Column('last_used_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('rotated_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.ForeignKeyConstraint(['post_id'], ['posts.id'], name=op.f('fk_access_tokens_post_id_posts'), ondelete='CASCADE'),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_access_tokens'))
    )
    with op.batch_alter_table('access_tokens', schema=None) as batch_op:
        batch_op.create_index(batch_op.f('ix_access_tokens_post_id'), ['post_id'], unique=False)
        batch_op.create_index(batch_op.f('ix_access_tokens_token'), ['token'], unique=True)
        batch_op.create_index('ix_tokens_active_expiry', ['is_active', 'expires_at'], unique=False)

    op.create_table('membership_checks',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('telegram_id', sa.BigInteger(), nullable=False),
    sa.Column('post_id', sa.Integer(), nullable=True),
    sa.Column('all_joined', sa.Boolean(), nullable=False),
    sa.Column('error_count', sa.Integer(), nullable=False),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.ForeignKeyConstraint(['post_id'], ['posts.id'], name=op.f('fk_membership_checks_post_id_posts'), ondelete='SET NULL'),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_membership_checks'))
    )
    with op.batch_alter_table('membership_checks', schema=None) as batch_op:
        batch_op.create_index('ix_membership_check_created', ['created_at'], unique=False)
        batch_op.create_index(batch_op.f('ix_membership_checks_post_id'), ['post_id'], unique=False)
        batch_op.create_index(batch_op.f('ix_membership_checks_telegram_id'), ['telegram_id'], unique=False)

    op.create_table('post_destinations',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('post_id', sa.Integer(), nullable=False),
    sa.Column('channel_id', sa.Integer(), nullable=False),
    sa.Column('status', sa.Enum('PENDING', 'SENDING', 'PUBLISHED', 'FAILED', 'UNKNOWN', 'SKIPPED', name='destination_status', native_enum=False, length=32), nullable=False),
    sa.Column('telegram_message_id', sa.BigInteger(), nullable=True),
    sa.Column('error_message', sa.String(length=2000), nullable=True),
    sa.Column('attempted_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('published_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('delete_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('deleted_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('delete_error', sa.String(length=1000), nullable=True),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.ForeignKeyConstraint(['channel_id'], ['publish_channels.id'], name=op.f('fk_post_destinations_channel_id_publish_channels'), ondelete='CASCADE'),
    sa.ForeignKeyConstraint(['post_id'], ['posts.id'], name=op.f('fk_post_destinations_post_id_posts'), ondelete='CASCADE'),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_post_destinations')),
    sa.UniqueConstraint('post_id', 'channel_id', name='uq_post_destination')
    )
    with op.batch_alter_table('post_destinations', schema=None) as batch_op:
        batch_op.create_index('ix_destination_status', ['status'], unique=False)
        batch_op.create_index(batch_op.f('ix_post_destinations_channel_id'), ['channel_id'], unique=False)
        batch_op.create_index(batch_op.f('ix_post_destinations_post_id'), ['post_id'], unique=False)

    op.create_table('post_required_channels',
    sa.Column('post_id', sa.Integer(), nullable=False),
    sa.Column('channel_id', sa.Integer(), nullable=False),
    sa.Column('is_required', sa.Boolean(), nullable=False),
    sa.ForeignKeyConstraint(['channel_id'], ['required_channels.id'], name=op.f('fk_post_required_channels_channel_id_required_channels'), ondelete='CASCADE'),
    sa.ForeignKeyConstraint(['post_id'], ['posts.id'], name=op.f('fk_post_required_channels_post_id_posts'), ondelete='CASCADE'),
    sa.PrimaryKeyConstraint('post_id', 'channel_id', name=op.f('pk_post_required_channels'))
    )
    op.create_table('user_deliveries',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('user_id', sa.Integer(), nullable=False),
    sa.Column('post_id', sa.Integer(), nullable=False),
    sa.Column('access_token_id', sa.Integer(), nullable=False),
    sa.Column('telegram_message_id', sa.BigInteger(), nullable=False),
    sa.Column('sent_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('delete_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('deleted_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('delete_status', sa.Enum('PENDING', 'DELETED', 'FAILED', 'SKIPPED', name='delete_status', native_enum=False, length=32), nullable=False),
    sa.Column('delete_error', sa.String(length=1000), nullable=True),
    sa.Column('correlation_id', sa.String(length=64), nullable=True),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.ForeignKeyConstraint(['access_token_id'], ['access_tokens.id'], name=op.f('fk_user_deliveries_access_token_id_access_tokens'), ondelete='CASCADE'),
    sa.ForeignKeyConstraint(['post_id'], ['posts.id'], name=op.f('fk_user_deliveries_post_id_posts'), ondelete='CASCADE'),
    sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_user_deliveries_user_id_users'), ondelete='CASCADE'),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_user_deliveries'))
    )
    with op.batch_alter_table('user_deliveries', schema=None) as batch_op:
        batch_op.create_index('ix_delivery_delete', ['delete_at', 'deleted_at'], unique=False)
        batch_op.create_index(batch_op.f('ix_user_deliveries_correlation_id'), ['correlation_id'], unique=False)
        batch_op.create_index(batch_op.f('ix_user_deliveries_post_id'), ['post_id'], unique=False)
        batch_op.create_index(batch_op.f('ix_user_deliveries_user_id'), ['user_id'], unique=False)

    op.create_table('scheduled_jobs',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('job_type', sa.Enum('PUBLISH_POST', 'DELETE_USER_MESSAGE', 'DELETE_CHANNEL_MESSAGE', name='job_type', native_enum=False, length=32), nullable=False),
    sa.Column('status', sa.Enum('PENDING', 'RUNNING', 'DONE', 'FAILED', 'CANCELLED', name='job_status', native_enum=False, length=32), nullable=False),
    sa.Column('run_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('payload', sa.JSON(), nullable=False),
    sa.Column('attempts', sa.Integer(), nullable=False),
    sa.Column('max_attempts', sa.Integer(), nullable=False),
    sa.Column('last_error', sa.String(length=2000), nullable=True),
    sa.Column('correlation_id', sa.String(length=64), nullable=True),
    sa.Column('idempotency_key', sa.String(length=255), nullable=True),
    sa.Column('started_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('finished_at', app.database.base.UTCDateTime(timezone=True), nullable=True),
    sa.Column('post_id', sa.Integer(), nullable=True),
    sa.Column('delivery_id', sa.Integer(), nullable=True),
    sa.Column('created_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.Column('updated_at', app.database.base.UTCDateTime(timezone=True), nullable=False),
    sa.ForeignKeyConstraint(['delivery_id'], ['user_deliveries.id'], name=op.f('fk_scheduled_jobs_delivery_id_user_deliveries'), ondelete='SET NULL'),
    sa.ForeignKeyConstraint(['post_id'], ['posts.id'], name=op.f('fk_scheduled_jobs_post_id_posts'), ondelete='SET NULL'),
    sa.PrimaryKeyConstraint('id', name=op.f('pk_scheduled_jobs')),
    sa.UniqueConstraint('idempotency_key', name='uq_jobs_idempotency_key')
    )
    with op.batch_alter_table('scheduled_jobs', schema=None) as batch_op:
        batch_op.create_index('ix_jobs_due', ['status', 'run_at'], unique=False)
        batch_op.create_index(batch_op.f('ix_scheduled_jobs_correlation_id'), ['correlation_id'], unique=False)
        batch_op.create_index(batch_op.f('ix_scheduled_jobs_delivery_id'), ['delivery_id'], unique=False)
        batch_op.create_index(batch_op.f('ix_scheduled_jobs_job_type'), ['job_type'], unique=False)
        batch_op.create_index(batch_op.f('ix_scheduled_jobs_post_id'), ['post_id'], unique=False)

    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table('scheduled_jobs', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_scheduled_jobs_post_id'))
        batch_op.drop_index(batch_op.f('ix_scheduled_jobs_job_type'))
        batch_op.drop_index(batch_op.f('ix_scheduled_jobs_delivery_id'))
        batch_op.drop_index(batch_op.f('ix_scheduled_jobs_correlation_id'))
        batch_op.drop_index('ix_jobs_due')

    op.drop_table('scheduled_jobs')
    with op.batch_alter_table('user_deliveries', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_user_deliveries_user_id'))
        batch_op.drop_index(batch_op.f('ix_user_deliveries_post_id'))
        batch_op.drop_index(batch_op.f('ix_user_deliveries_correlation_id'))
        batch_op.drop_index('ix_delivery_delete')

    op.drop_table('user_deliveries')
    op.drop_table('post_required_channels')
    with op.batch_alter_table('post_destinations', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_post_destinations_post_id'))
        batch_op.drop_index(batch_op.f('ix_post_destinations_channel_id'))
        batch_op.drop_index('ix_destination_status')

    op.drop_table('post_destinations')
    with op.batch_alter_table('membership_checks', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_membership_checks_telegram_id'))
        batch_op.drop_index(batch_op.f('ix_membership_checks_post_id'))
        batch_op.drop_index('ix_membership_check_created')

    op.drop_table('membership_checks')
    with op.batch_alter_table('access_tokens', schema=None) as batch_op:
        batch_op.drop_index('ix_tokens_active_expiry')
        batch_op.drop_index(batch_op.f('ix_access_tokens_token'))
        batch_op.drop_index(batch_op.f('ix_access_tokens_post_id'))

    op.drop_table('access_tokens')
    with op.batch_alter_table('posts', schema=None) as batch_op:
        batch_op.drop_index('ix_posts_status_created')
        batch_op.drop_index(batch_op.f('ix_posts_status'))
        batch_op.drop_index(batch_op.f('ix_posts_media_asset_id'))

    op.drop_table('posts')
    with op.batch_alter_table('media_assets', schema=None) as batch_op:
        batch_op.drop_index('ix_media_status_received')
        batch_op.drop_index(batch_op.f('ix_media_assets_source_chat_id'))

    op.drop_table('media_assets')
    with op.batch_alter_table('users', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_users_telegram_id'))

    op.drop_table('users')
    with op.batch_alter_table('source_chats', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_source_chats_chat_id'))

    op.drop_table('source_chats')
    with op.batch_alter_table('required_channels', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_required_channels_chat_id'))

    op.drop_table('required_channels')
    with op.batch_alter_table('rate_limit_events', schema=None) as batch_op:
        batch_op.drop_index('ix_rate_limit_lookup')

    op.drop_table('rate_limit_events')
    with op.batch_alter_table('publish_channels', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_publish_channels_chat_id'))

    op.drop_table('publish_channels')
    with op.batch_alter_table('operation_logs', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_operation_logs_operation'))
        batch_op.drop_index(batch_op.f('ix_operation_logs_correlation_id'))
        batch_op.drop_index('ix_operation_created')

    op.drop_table('operation_logs')
    with op.batch_alter_table('audit_logs', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_audit_logs_correlation_id'))
        batch_op.drop_index(batch_op.f('ix_audit_logs_actor_id'))
        batch_op.drop_index(batch_op.f('ix_audit_logs_action'))
        batch_op.drop_index('ix_audit_created')

    op.drop_table('audit_logs')
    op.drop_table('app_settings')
    with op.batch_alter_table('admins', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('ix_admins_telegram_id'))

    op.drop_table('admins')
    # ### end Alembic commands ###
