Files
tasq/supabase/migrations/20260323000000_fix_enqueue_all_notifications.sql
T
2026-04-27 06:20:39 +08:00

77 lines
4.0 KiB
PL/PgSQL

-- Migration: Definitive enqueue_all_notifications() dispatcher + self-hosted fix
--
-- WHY THIS EXISTS:
-- 1. Sort-order bug: 20260322_finalize_notification_functions.sql has an
-- underscore at filename position 9, which sorts AFTER all 20260322NNNNNN_*
-- files (underscore ASCII 95 > digits 48-57). It therefore ran LAST and
-- overrode enqueue_all_notifications() with a version that omitted:
-- - enqueue_announcement_banner_notifications() (added in 20260322210000)
-- - enqueue_pass_slip_expired_notifications() (added in 20260322150000)
-- This migration (20260323000000) sorts after all 20260322* files and
-- restores the authoritative 10-type definition.
--
-- 2. Self-hosted Docker: process_notification_queue() fires the edge function
-- via pg_net (HTTP), but on self-hosted the vault secrets and GUC fallbacks
-- are often not configured, so the function returns early and the edge
-- function is never triggered. enqueue_all_notifications() therefore never
-- runs and scheduled_notifications is never populated.
-- Fix: a dedicated pg_cron job calls enqueue_all_notifications() directly
-- (pure SQL, no HTTP, no vault required). The edge function is still called
-- for FCM delivery — only the enqueue step is decoupled.
-- ============================================================================
-- 1. Authoritative master dispatcher (all 10 types)
-- ============================================================================
CREATE OR REPLACE FUNCTION public.enqueue_all_notifications()
RETURNS void LANGUAGE plpgsql AS $$
BEGIN
PERFORM public.enqueue_due_shift_notifications();
PERFORM public.enqueue_overtime_idle_notifications();
PERFORM public.enqueue_overtime_checkout_notifications();
PERFORM public.enqueue_isr_event_notifications();
PERFORM public.enqueue_isr_evidence_notifications();
PERFORM public.enqueue_paused_task_notifications();
PERFORM public.enqueue_backlog_notifications();
PERFORM public.enqueue_pass_slip_expiry_notifications();
PERFORM public.enqueue_pass_slip_expired_notifications();
PERFORM public.enqueue_announcement_banner_notifications();
END;
$$;
-- ============================================================================
-- 2. Dedicated enqueue cron job (self-hosted compatible)
-- ============================================================================
-- This job calls enqueue_all_notifications() directly inside PostgreSQL every
-- minute. It requires only pg_cron — no pg_net, no vault, no HTTP.
--
-- On Supabase cloud: both this job and the edge-function trigger run, which
-- is safe because every enqueue function is idempotent via
-- ON CONFLICT DO NOTHING.
-- On self-hosted Docker: this job ensures scheduled_notifications is populated
-- even when the pg_net → edge-function path is broken.
-- For FCM delivery you still need the edge function to
-- run; use the system crontab as shown below if pg_net
-- is not configured:
--
-- */1 * * * * curl -sS -X POST \
-- "http://localhost:8000/functions/v1/process_scheduled_notifications" \
-- -H "Authorization: Bearer <service-role-key>" \
-- -H "Content-Type: application/json" -d '{}'
--
-- Self-hosted vault / GUC setup (run once, required for pg_net path):
-- SELECT vault.create_secret('http://localhost:8000', 'supabase_url');
-- SELECT vault.create_secret('<service-role-key>', 'service_role_key');
-- -- or via GUC (no vault extension required):
-- ALTER DATABASE postgres SET "app.settings.supabase_url" = 'http://localhost:8000';
-- ALTER DATABASE postgres SET "app.settings.service_role_key" = '<service-role-key>';
DO $$
BEGIN
PERFORM cron.schedule(
'notification_enqueue_every_min',
'*/1 * * * *',
'SELECT public.enqueue_all_notifications();'
);
EXCEPTION WHEN others THEN
RAISE NOTICE 'pg_cron not available (%). Use the system crontab to call the edge function directly instead.', SQLERRM;
END $$;