"""Create webhooks table for outgoing webhook subscriptions. Revision ID: 0042_webhooks Revises: 0041_custom_field_definitions Create Date: 2026-07-26 Stores outgoing webhook subscriptions with target URL, event subscriptions, and delivery settings (retry count, timeout, HMAC secret). """ from __future__ import annotations from typing import Union import sqlalchemy as sa from alembic import op # revision identifiers revision: str = "0042_webhooks" down_revision: Union[str, None] = "0041_custom_field_definitions" branch_labels: Union[str, None] = None depends_on: Union[str, None] = None def upgrade() -> None: conn = op.get_bind() conn.execute( sa.text( """ CREATE TABLE IF NOT EXISTS webhooks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL, url VARCHAR(500) NOT NULL, events JSONB NOT NULL DEFAULT '[]', secret VARCHAR(255), is_active BOOLEAN NOT NULL DEFAULT TRUE, retry_count INTEGER NOT NULL DEFAULT 3, timeout_seconds INTEGER NOT NULL DEFAULT 30, created_by UUID, updated_by UUID, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), deleted_at TIMESTAMPTZ ) """ ) ) # Indexes conn.execute( sa.text( "CREATE INDEX IF NOT EXISTS ix_webhooks_tenant " "ON webhooks (tenant_id)" ) ) conn.execute( sa.text( "CREATE INDEX IF NOT EXISTS ix_webhooks_tenant_active " "ON webhooks (tenant_id, is_active)" ) ) def downgrade() -> None: conn = op.get_bind() conn.execute(sa.text("DROP INDEX IF EXISTS ix_webhooks_tenant_active")) conn.execute(sa.text("DROP INDEX IF EXISTS ix_webhooks_tenant")) conn.execute(sa.text("DROP TABLE IF EXISTS webhooks"))