Files
myeasycms-v2/apps/web/supabase/migrations/20260418000006_notification_rules.sql
T. Zehetbauer 9d5fe58ee3
Some checks failed
Workflow / ʦ TypeScript (push) Failing after 5m42s
Workflow / ⚫️ Test (push) Has been skipped
feat: add shared notification, communication, and export services for bookings, courses, and events; introduce btree_gist extension and new booking atomic function
2026-04-03 17:03:34 +02:00

94 lines
4.2 KiB
PL/PgSQL

-- =====================================================
-- Module Notification Rules & Queue
-- Shared notification infrastructure for courses, events, bookings.
-- =====================================================
-- Notification rules: define what triggers notifications
CREATE TABLE IF NOT EXISTS public.module_notification_rules (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
account_id uuid NOT NULL REFERENCES public.accounts(id) ON DELETE CASCADE,
module text NOT NULL CHECK (module IN ('courses', 'events', 'bookings')),
trigger_event text NOT NULL CHECK (trigger_event IN (
'course.participant_enrolled', 'course.participant_waitlisted', 'course.participant_promoted',
'course.participant_cancelled', 'course.status_changed', 'course.session_reminder',
'event.registration_confirmed', 'event.registration_waitlisted', 'event.registration_promoted',
'event.registration_cancelled', 'event.status_changed', 'event.reminder',
'booking.confirmed', 'booking.check_in_reminder', 'booking.checked_in',
'booking.checked_out', 'booking.cancelled'
)),
channel text NOT NULL DEFAULT 'in_app' CHECK (channel IN ('in_app', 'email', 'both')),
recipient_type text NOT NULL DEFAULT 'admin' CHECK (recipient_type IN ('admin', 'participant', 'guest', 'instructor', 'specific_user')),
recipient_config jsonb NOT NULL DEFAULT '{}',
subject_template text,
message_template text NOT NULL,
is_active boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_module_notification_rules_lookup
ON public.module_notification_rules(account_id, module, trigger_event)
WHERE is_active = true;
ALTER TABLE public.module_notification_rules ENABLE ROW LEVEL SECURITY;
REVOKE ALL ON public.module_notification_rules FROM authenticated, service_role;
GRANT SELECT, INSERT, UPDATE, DELETE ON public.module_notification_rules TO authenticated;
GRANT ALL ON public.module_notification_rules TO service_role;
CREATE POLICY module_notification_rules_select ON public.module_notification_rules
FOR SELECT TO authenticated USING (public.has_role_on_account(account_id));
CREATE POLICY module_notification_rules_mutate ON public.module_notification_rules
FOR ALL TO authenticated USING (
public.has_permission(auth.uid(), account_id, 'settings.manage'::public.app_permissions)
) WITH CHECK (
public.has_permission(auth.uid(), account_id, 'settings.manage'::public.app_permissions)
);
-- Pending notifications queue
CREATE TABLE IF NOT EXISTS public.pending_module_notifications (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
account_id uuid NOT NULL REFERENCES public.accounts(id) ON DELETE CASCADE,
module text NOT NULL CHECK (module IN ('courses', 'events', 'bookings')),
trigger_event text NOT NULL,
entity_id uuid NOT NULL,
context jsonb NOT NULL DEFAULT '{}',
processed_at timestamptz,
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS ix_pending_module_notifications_unprocessed
ON public.pending_module_notifications(created_at)
WHERE processed_at IS NULL;
ALTER TABLE public.pending_module_notifications ENABLE ROW LEVEL SECURITY;
REVOKE ALL ON public.pending_module_notifications FROM authenticated, service_role;
GRANT SELECT ON public.pending_module_notifications TO authenticated;
GRANT ALL ON public.pending_module_notifications TO service_role;
CREATE POLICY pending_module_notifications_select ON public.pending_module_notifications
FOR SELECT TO authenticated USING (public.has_role_on_account(account_id));
-- Enqueue helper
CREATE OR REPLACE FUNCTION public.enqueue_module_notification(
p_account_id uuid,
p_module text,
p_trigger_event text,
p_entity_id uuid,
p_context jsonb DEFAULT '{}'
)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = ''
AS $$
BEGIN
INSERT INTO public.pending_module_notifications
(account_id, module, trigger_event, entity_id, context)
VALUES
(p_account_id, p_module, p_trigger_event, p_entity_id, p_context);
END;
$$;
GRANT EXECUTE ON FUNCTION public.enqueue_module_notification(uuid, text, text, uuid, jsonb) TO authenticated;
GRANT EXECUTE ON FUNCTION public.enqueue_module_notification(uuid, text, text, uuid, jsonb) TO service_role;