Files
Sauci/apps/supabase/migrations/20260117000005_add_match_notification_digests.sql
T

93 lines
2.9 KiB
PL/PgSQL

-- Add match notification digest system
-- Coalesces multiple match events into a single push notification.
--
-- Design goals:
-- - Reduce push spam when many matches occur quickly
-- - Keep delivery latency bounded (<= ~2 minutes)
-- - Keep match creation real-time; only push notifications are delayed
-- Create pending match notifications table
CREATE TABLE pending_match_notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
couple_id UUID NOT NULL REFERENCES couples(id) ON DELETE CASCADE,
match_count INTEGER NOT NULL DEFAULT 1,
latest_match_id UUID REFERENCES matches(id) ON DELETE SET NULL,
notify_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(couple_id) -- One pending notification per couple (UPSERT timer reset)
);
-- Index for efficient cron queries
CREATE INDEX idx_pending_match_notifications_notify_at
ON pending_match_notifications(notify_at);
-- Enable RLS
ALTER TABLE pending_match_notifications ENABLE ROW LEVEL SECURITY;
-- RLS policies
CREATE POLICY "Users can view their couple's pending match notifications"
ON pending_match_notifications FOR SELECT
USING (couple_id = get_auth_user_couple_id());
CREATE POLICY "Super admins can view all pending match notifications"
ON pending_match_notifications FOR SELECT
USING (is_super_admin());
-- Updated_at trigger
CREATE TRIGGER update_pending_match_notifications_updated_at
BEFORE UPDATE ON pending_match_notifications
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
-- Function to queue match notifications
-- Runs whenever a new match row is inserted.
-- The notify_at value is aligned to minute boundaries so that a once-per-minute cron
-- can deliver notifications within ~1-2 minutes.
CREATE OR REPLACE FUNCTION queue_match_notification()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = 'public'
AS $$
BEGIN
INSERT INTO pending_match_notifications (
couple_id,
match_count,
latest_match_id,
notify_at
)
VALUES (
NEW.couple_id,
1,
NEW.id,
date_trunc('minute', now()) + interval '2 minutes'
)
ON CONFLICT (couple_id) DO UPDATE SET
match_count = pending_match_notifications.match_count + 1,
latest_match_id = NEW.id,
notify_at = date_trunc('minute', now()) + interval '2 minutes',
updated_at = now();
RETURN NEW;
END;
$$;
-- Trigger on matches table
CREATE TRIGGER on_match_created
AFTER INSERT ON matches
FOR EACH ROW
EXECUTE FUNCTION queue_match_notification();
-- Schedule cron job (runs every minute)
SELECT cron.schedule(
'send-match-notification-digests',
'* * * * *',
$$
SELECT net.http_post(
url := 'https://ckjcrkjpmhqhiucifukx.supabase.co/functions/v1/send-match-notification-digest',
headers := jsonb_build_object('Content-Type', 'application/json'),
body := '{}'::jsonb
)
$$
);