-- webhook_subscriptions: per-organization webhook delivery targets. -- Each subscription registers a URL to receive HTTP POST callbacks for specified event types. -- The HMAC signing secret is stored in Vault (vault_secret_path) when Vault is configured, -- or bcrypt-hashed into secret_hash in local mode. The raw secret is never stored in PostgreSQL. CREATE TABLE IF NOT EXISTS webhook_subscriptions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, url VARCHAR(2048) NOT NULL, -- HTTPS delivery target events JSONB NOT NULL DEFAULT '[]', -- array of WebhookEventType strings secret_hash VARCHAR(255) NOT NULL, -- bcrypt hash (local mode) or 'vault' sentinel vault_secret_path VARCHAR(512) NOT NULL, -- Vault KV path for HMAC signing secret, or 'local' active BOOLEAN NOT NULL DEFAULT true, failure_count INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_webhook_subscriptions_organization_id ON webhook_subscriptions(organization_id); CREATE INDEX IF NOT EXISTS idx_webhook_subscriptions_active ON webhook_subscriptions(active);