trying to rework database migrations

This commit is contained in:
2026-02-05 11:42:04 -06:00
parent 3b14c65998
commit 343488b3eb
83 changed files with 5793 additions and 876 deletions

View File

@@ -0,0 +1,249 @@
-- Migration: Consolidate Webhook Configuration
-- Date: 2026-01-27
-- Description: Consolidates multiple webhook_* columns into a single webhook_config JSONB column
-- for cleaner schema and better flexibility. Keeps webhook_enabled and webhook_key
-- as separate columns for indexing and quick filtering.
-- Step 1: Add new webhook_config column
ALTER TABLE trigger
ADD COLUMN IF NOT EXISTS webhook_config JSONB DEFAULT '{}'::jsonb;
COMMENT ON COLUMN trigger.webhook_config IS
'Webhook configuration as JSON. Contains settings like secret, HMAC config, rate limits, IP whitelist, etc.';
-- Step 2: Migrate existing data to webhook_config
-- Build JSON object from existing columns
UPDATE trigger
SET webhook_config = jsonb_build_object(
'secret', COALESCE(webhook_secret, NULL),
'hmac', jsonb_build_object(
'enabled', COALESCE(webhook_hmac_enabled, false),
'secret', COALESCE(webhook_hmac_secret, NULL),
'algorithm', COALESCE(webhook_hmac_algorithm, 'sha256')
),
'rate_limit', jsonb_build_object(
'enabled', COALESCE(webhook_rate_limit_enabled, false),
'requests', COALESCE(webhook_rate_limit_requests, NULL),
'window_seconds', COALESCE(webhook_rate_limit_window_seconds, NULL)
),
'ip_whitelist', jsonb_build_object(
'enabled', COALESCE(webhook_ip_whitelist_enabled, false),
'ips', COALESCE(
(SELECT jsonb_agg(ip) FROM unnest(webhook_ip_whitelist) AS ip),
'[]'::jsonb
)
),
'payload_size_limit_kb', COALESCE(webhook_payload_size_limit_kb, NULL)
)
WHERE webhook_enabled = true OR webhook_key IS NOT NULL;
-- Step 3: Drop dependent views that reference the columns we're about to drop
DROP VIEW IF EXISTS webhook_stats;
DROP VIEW IF EXISTS webhook_stats_detailed;
-- Step 4: Drop NOT NULL constraints on columns we're about to drop
ALTER TABLE trigger
DROP CONSTRAINT IF EXISTS trigger_webhook_hmac_enabled_not_null,
DROP CONSTRAINT IF EXISTS trigger_webhook_rate_limit_enabled_not_null,
DROP CONSTRAINT IF EXISTS trigger_webhook_ip_whitelist_enabled_not_null;
-- Step 5: Drop old webhook columns (keeping webhook_enabled and webhook_key)
ALTER TABLE trigger
DROP COLUMN IF EXISTS webhook_secret,
DROP COLUMN IF EXISTS webhook_hmac_enabled,
DROP COLUMN IF EXISTS webhook_hmac_secret,
DROP COLUMN IF EXISTS webhook_hmac_algorithm,
DROP COLUMN IF EXISTS webhook_rate_limit_enabled,
DROP COLUMN IF EXISTS webhook_rate_limit_requests,
DROP COLUMN IF EXISTS webhook_rate_limit_window_seconds,
DROP COLUMN IF EXISTS webhook_ip_whitelist_enabled,
DROP COLUMN IF EXISTS webhook_ip_whitelist,
DROP COLUMN IF EXISTS webhook_payload_size_limit_kb;
-- Step 6: Drop old indexes that referenced removed columns
DROP INDEX IF EXISTS idx_trigger_webhook_enabled;
-- Step 7: Recreate index for webhook_enabled with better name
CREATE INDEX IF NOT EXISTS idx_trigger_webhook_enabled
ON trigger(webhook_enabled)
WHERE webhook_enabled = TRUE;
-- Index on webhook_key already exists from previous migration
-- CREATE INDEX IF NOT EXISTS idx_trigger_webhook_key ON trigger(webhook_key) WHERE webhook_key IS NOT NULL;
-- Step 8: Add GIN index for webhook_config JSONB queries
CREATE INDEX IF NOT EXISTS idx_trigger_webhook_config
ON trigger USING gin(webhook_config)
WHERE webhook_config IS NOT NULL AND webhook_config != '{}'::jsonb;
-- Step 9: Recreate webhook stats view with new schema
CREATE OR REPLACE VIEW webhook_stats AS
SELECT
t.id as trigger_id,
t.ref as trigger_ref,
t.webhook_enabled,
t.webhook_key,
t.webhook_config,
t.created as webhook_created_at,
COUNT(e.id) as total_events,
MAX(e.created) as last_event_at,
MIN(e.created) as first_event_at
FROM trigger t
LEFT JOIN event e ON
e.trigger = t.id
AND (e.config->>'source') = 'webhook'
WHERE t.webhook_enabled = TRUE
GROUP BY t.id, t.ref, t.webhook_enabled, t.webhook_key, t.webhook_config, t.created;
COMMENT ON VIEW webhook_stats IS
'Statistics for webhook-enabled triggers including event counts and timestamps.';
-- Step 10: Update helper functions to work with webhook_config
-- Update enable_trigger_webhook to work with new schema
CREATE OR REPLACE FUNCTION enable_trigger_webhook(
p_trigger_id BIGINT,
p_config JSONB DEFAULT '{}'::jsonb
)
RETURNS TABLE(
webhook_enabled BOOLEAN,
webhook_key VARCHAR(64),
webhook_url TEXT,
webhook_config JSONB
) AS $$
DECLARE
v_new_key VARCHAR(64);
v_existing_key VARCHAR(64);
v_base_url TEXT;
v_config JSONB;
BEGIN
-- Check if trigger exists
IF NOT EXISTS (SELECT 1 FROM trigger WHERE id = p_trigger_id) THEN
RAISE EXCEPTION 'Trigger with id % does not exist', p_trigger_id;
END IF;
-- Get existing webhook key if any
SELECT t.webhook_key INTO v_existing_key
FROM trigger t
WHERE t.id = p_trigger_id;
-- Generate new key if one doesn't exist
IF v_existing_key IS NULL THEN
v_new_key := generate_webhook_key();
ELSE
v_new_key := v_existing_key;
END IF;
-- Merge provided config with defaults
v_config := p_config || jsonb_build_object(
'hmac', COALESCE(p_config->'hmac', jsonb_build_object('enabled', false, 'algorithm', 'sha256')),
'rate_limit', COALESCE(p_config->'rate_limit', jsonb_build_object('enabled', false)),
'ip_whitelist', COALESCE(p_config->'ip_whitelist', jsonb_build_object('enabled', false, 'ips', '[]'::jsonb))
);
-- Update trigger to enable webhooks
UPDATE trigger
SET
webhook_enabled = TRUE,
webhook_key = v_new_key,
webhook_config = v_config,
updated = NOW()
WHERE id = p_trigger_id;
-- Construct webhook URL
v_base_url := '/api/v1/webhooks/' || v_new_key;
-- Return result
RETURN QUERY
SELECT
TRUE::BOOLEAN as webhook_enabled,
v_new_key as webhook_key,
v_base_url as webhook_url,
v_config as webhook_config;
END;
$$ LANGUAGE plpgsql;
COMMENT ON FUNCTION enable_trigger_webhook(BIGINT, JSONB) IS
'Enables webhooks for a trigger with optional configuration. Generates a new webhook key if one does not exist. Returns webhook details.';
-- Update disable_trigger_webhook (no changes needed, but recreate for consistency)
CREATE OR REPLACE FUNCTION disable_trigger_webhook(
p_trigger_id BIGINT
)
RETURNS BOOLEAN AS $$
BEGIN
-- Check if trigger exists
IF NOT EXISTS (SELECT 1 FROM trigger WHERE id = p_trigger_id) THEN
RAISE EXCEPTION 'Trigger with id % does not exist', p_trigger_id;
END IF;
-- Update trigger to disable webhooks
-- Note: We keep the webhook_key and webhook_config for audit purposes
UPDATE trigger
SET
webhook_enabled = FALSE,
updated = NOW()
WHERE id = p_trigger_id;
RETURN TRUE;
END;
$$ LANGUAGE plpgsql;
COMMENT ON FUNCTION disable_trigger_webhook(BIGINT) IS
'Disables webhooks for a trigger. Webhook key and config are retained for audit purposes.';
-- Update regenerate_trigger_webhook_key (no changes to logic)
CREATE OR REPLACE FUNCTION regenerate_trigger_webhook_key(
p_trigger_id BIGINT
)
RETURNS TABLE(
webhook_key VARCHAR(64),
previous_key_revoked BOOLEAN
) AS $$
DECLARE
v_old_key VARCHAR(64);
v_new_key VARCHAR(64);
BEGIN
-- Check if trigger exists
IF NOT EXISTS (SELECT 1 FROM trigger WHERE id = p_trigger_id) THEN
RAISE EXCEPTION 'Trigger with id % does not exist', p_trigger_id;
END IF;
-- Get existing key
SELECT t.webhook_key INTO v_old_key
FROM trigger t
WHERE t.id = p_trigger_id;
-- Generate new key
v_new_key := generate_webhook_key();
-- Update trigger with new key
UPDATE trigger
SET
webhook_key = v_new_key,
updated = NOW()
WHERE id = p_trigger_id;
-- Return result
RETURN QUERY
SELECT
v_new_key as webhook_key,
(v_old_key IS NOT NULL)::BOOLEAN as previous_key_revoked;
END;
$$ LANGUAGE plpgsql;
COMMENT ON FUNCTION regenerate_trigger_webhook_key(BIGINT) IS
'Regenerates the webhook key for a trigger. The old key is immediately revoked.';
-- Drop old webhook-specific functions that are no longer needed
DROP FUNCTION IF EXISTS enable_trigger_webhook_hmac(BIGINT, VARCHAR);
DROP FUNCTION IF EXISTS disable_trigger_webhook_hmac(BIGINT);
-- Migration complete messages
DO $$
BEGIN
RAISE NOTICE 'Webhook configuration consolidation completed successfully';
RAISE NOTICE 'Webhook settings now stored in webhook_config JSONB column';
RAISE NOTICE 'Kept separate columns: webhook_enabled (indexed), webhook_key (indexed)';
END $$;