Fix notification logs migration

This commit is contained in:
gpt-engineer-app[bot]
2025-11-03 00:24:38 +00:00
parent 71bb364bce
commit a3b52b777c
2 changed files with 142 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
-- Migration: Add notification idempotency and duplicate prevention
-- Add idempotency columns to notification_logs
ALTER TABLE public.notification_logs
ADD COLUMN IF NOT EXISTS idempotency_key TEXT,
ADD COLUMN IF NOT EXISTS is_duplicate BOOLEAN NOT NULL DEFAULT false;
-- Create immutable function for date extraction (required for index)
CREATE OR REPLACE FUNCTION public.immutable_date(ts TIMESTAMPTZ)
RETURNS DATE AS $$
BEGIN
RETURN ts::DATE;
END;
$$ LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER SET search_path = public;
-- Create unique index to prevent duplicates (same key per user per day)
DROP INDEX IF EXISTS idx_notification_logs_idempotency_unique;
CREATE UNIQUE INDEX idx_notification_logs_idempotency_unique
ON public.notification_logs (user_id, idempotency_key, immutable_date(created_at))
WHERE idempotency_key IS NOT NULL;
-- Index for monitoring duplicates
CREATE INDEX IF NOT EXISTS idx_notification_logs_duplicates
ON public.notification_logs(is_duplicate, created_at)
WHERE is_duplicate = true;
-- Create duplicate tracking stats table
CREATE TABLE IF NOT EXISTS public.notification_duplicate_stats (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
date DATE NOT NULL DEFAULT CURRENT_DATE,
total_attempts INTEGER DEFAULT 0,
duplicates_prevented INTEGER DEFAULT 0,
prevention_rate DECIMAL(5,2) GENERATED ALWAYS AS (
CASE
WHEN total_attempts > 0 THEN (duplicates_prevented::DECIMAL / total_attempts * 100)
ELSE 0
END
) STORED,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(date)
);
-- Enable RLS on duplicate stats
ALTER TABLE public.notification_duplicate_stats ENABLE ROW LEVEL SECURITY;
-- Drop and recreate policy
DROP POLICY IF EXISTS "Admins can view duplicate stats" ON public.notification_duplicate_stats;
CREATE POLICY "Admins can view duplicate stats"
ON public.notification_duplicate_stats FOR SELECT
USING (is_moderator(auth.uid()));
-- Function to generate idempotency key
CREATE OR REPLACE FUNCTION public.generate_notification_idempotency_key(
p_notification_type TEXT,
p_entity_id UUID,
p_recipient_id UUID,
p_event_data JSONB DEFAULT NULL
)
RETURNS TEXT AS $$
BEGIN
RETURN encode(
digest(
p_notification_type ||
COALESCE(p_entity_id::TEXT, '') ||
p_recipient_id::TEXT ||
CURRENT_DATE::TEXT ||
COALESCE(p_event_data::TEXT, ''),
'sha256'
),
'hex'
);
END;
$$ LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER SET search_path = public;
-- Create monitoring view for notification health
CREATE OR REPLACE VIEW public.notification_health_dashboard AS
SELECT
date,
total_attempts,
duplicates_prevented,
prevention_rate,
CASE
WHEN prevention_rate > 10 THEN 'critical'
WHEN prevention_rate > 5 THEN 'warning'
ELSE 'healthy'
END as health_status
FROM public.notification_duplicate_stats
ORDER BY date DESC
LIMIT 30;