-- Migración 007: Tabla de eventos de notificación -- Fuente de verdad para el sistema de jobs. Garantiza idempotencia mediante UNIQUE constraint. -- -- Tipos de evento soportados: -- reservation.created — Teneriffa CRUD -- reservation.updated — Teneriffa CRUD -- reservation.cancelled — Teneriffa CRUD -- reservation.reminder_24h — 24h antes check-in (Teneriffa + Los Dragos) -- reservation.invoice_second_notice — 10 días antes check-in (Natur, ambas casas) -- reservation.pool_heating_notice — 48h antes check-in (si has_pool_heating = true) CREATE TABLE public.notification_events ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, reservation_id UUID REFERENCES public.reservations(id) ON DELETE CASCADE, event_type TEXT NOT NULL, scheduled_for TIMESTAMPTZ NOT NULL, sent_at TIMESTAMPTZ, status TEXT NOT NULL DEFAULT 'pending', -- 'pending': esperando ejecución -- 'processing': siendo procesado por el runner (previene duplicados) -- 'sent': enviado correctamente -- 'failed': fallido después de max_retries intentos attempts INTEGER DEFAULT 0 NOT NULL, last_error TEXT, metadata JSONB, created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL, -- CONSTRAINT DE IDEMPOTENCIA: -- Un mismo evento (mismo tipo + misma fecha programada) para una reserva -- solo puede existir una vez. ON CONFLICT DO NOTHING previene duplicados. CONSTRAINT uq_notification_event UNIQUE(reservation_id, event_type, scheduled_for) ); CREATE INDEX idx_notification_events_pending ON public.notification_events(scheduled_for) WHERE status = 'pending'; ALTER TABLE public.notification_events ENABLE ROW LEVEL SECURITY; -- Solo admin puede ver eventos de notificación (se refina en migración 009) CREATE POLICY "Temp: authenticated can read notifications" ON public.notification_events FOR SELECT TO authenticated USING (true); COMMENT ON TABLE public.notification_events IS 'Eventos de notificación programados. El runner en apps/api los procesa periódicamente.'; COMMENT ON COLUMN public.notification_events.status IS 'pending → processing → sent | failed. El estado "processing" previene que múltiples instancias procesen el mismo evento.';