Files
avbeat-com/supabase/migrations/20260321200000_notifications.sql
2026-05-07 16:39:17 +00:00

145 lines
5.1 KiB
PL/PgSQL

-- Notifications Migration for BroadcastBeat
-- Tracks thread replies, mentions, upvotes, and follow activity
-- ============================================================
-- 1. NOTIFICATIONS TABLE
-- ============================================================
CREATE TABLE IF NOT EXISTS public.notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES public.user_profiles(id) ON DELETE CASCADE,
type TEXT NOT NULL CHECK (type IN ('thread_reply', 'mention', 'upvote', 'follow')),
title TEXT NOT NULL,
body TEXT,
link TEXT,
actor_id UUID REFERENCES public.user_profiles(id) ON DELETE SET NULL,
actor_name TEXT,
is_read BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON public.notifications(user_id);
CREATE INDEX IF NOT EXISTS idx_notifications_user_unread ON public.notifications(user_id, is_read) WHERE is_read = false;
CREATE INDEX IF NOT EXISTS idx_notifications_created_at ON public.notifications(created_at DESC);
-- ============================================================
-- 2. RLS POLICIES
-- ============================================================
ALTER TABLE public.notifications ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "Users can view own notifications" ON public.notifications;
CREATE POLICY "Users can view own notifications"
ON public.notifications FOR SELECT
USING (auth.uid() = user_id);
DROP POLICY IF EXISTS "Users can update own notifications" ON public.notifications;
CREATE POLICY "Users can update own notifications"
ON public.notifications FOR UPDATE
USING (auth.uid() = user_id);
DROP POLICY IF EXISTS "Users can delete own notifications" ON public.notifications;
CREATE POLICY "Users can delete own notifications"
ON public.notifications FOR DELETE
USING (auth.uid() = user_id);
DROP POLICY IF EXISTS "Service role can insert notifications" ON public.notifications;
CREATE POLICY "Service role can insert notifications"
ON public.notifications FOR INSERT
WITH CHECK (true);
-- ============================================================
-- 3. AUTO-NOTIFY ON FORUM REPLY
-- ============================================================
CREATE OR REPLACE FUNCTION public.notify_thread_reply()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
v_thread_author UUID;
v_thread_title TEXT;
v_thread_id UUID;
BEGIN
SELECT author_id, title, id INTO v_thread_author, v_thread_title, v_thread_id
FROM public.forum_threads
WHERE id = NEW.thread_id;
-- Notify thread author (if not replying to own thread and not AI)
IF v_thread_author IS NOT NULL
AND v_thread_author <> NEW.author_id
AND NEW.is_ai_response = false THEN
INSERT INTO public.notifications (user_id, type, title, body, link, actor_id, actor_name)
VALUES (
v_thread_author,
'thread_reply',
'New reply to your thread',
v_thread_title,
'/forum/thread/' || v_thread_id::TEXT,
NEW.author_id,
NEW.author_name
);
END IF;
RETURN NEW;
END;
$$;
DROP TRIGGER IF EXISTS trg_notify_thread_reply ON public.forum_replies;
CREATE TRIGGER trg_notify_thread_reply
AFTER INSERT ON public.forum_replies
FOR EACH ROW EXECUTE FUNCTION public.notify_thread_reply();
-- ============================================================
-- 4. AUTO-NOTIFY ON UPVOTE
-- ============================================================
CREATE OR REPLACE FUNCTION public.notify_upvote()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
v_target_author UUID;
v_target_title TEXT;
v_link TEXT;
v_voter_name TEXT;
BEGIN
-- Only notify on upvotes (vote_value = 1)
IF NEW.vote_value <> 1 THEN
RETURN NEW;
END IF;
SELECT username INTO v_voter_name FROM public.user_profiles WHERE id = NEW.user_id;
IF NEW.target_type = 'thread' THEN
SELECT author_id, title INTO v_target_author, v_target_title
FROM public.forum_threads WHERE id = NEW.target_id;
v_link := '/forum/thread/' || NEW.target_id::TEXT;
ELSE
SELECT fr.author_id, ft.title INTO v_target_author, v_target_title
FROM public.forum_replies fr
JOIN public.forum_threads ft ON ft.id = fr.thread_id
WHERE fr.id = NEW.target_id;
v_link := '/forum/thread/' || (
SELECT thread_id FROM public.forum_replies WHERE id = NEW.target_id
)::TEXT;
END IF;
IF v_target_author IS NOT NULL AND v_target_author <> NEW.user_id THEN
INSERT INTO public.notifications (user_id, type, title, body, link, actor_id, actor_name)
VALUES (
v_target_author,
'upvote',
'Someone upvoted your ' || NEW.target_type,
v_target_title,
v_link,
NEW.user_id,
COALESCE(v_voter_name, 'A member')
);
END IF;
RETURN NEW;
END;
$$;
DROP TRIGGER IF EXISTS trg_notify_upvote ON public.forum_votes;
CREATE TRIGGER trg_notify_upvote
AFTER INSERT ON public.forum_votes
FOR EACH ROW EXECUTE FUNCTION public.notify_upvote();