Gestiona grupos de email y asignación por escenario en BD (natur_reservas.notification_groups / notification_scenario_recipients) en lugar de variables de entorno hardcodeadas. Incluye pantalla de ajustes, endpoint admin protegido, envío de prueba y niveles reducida/completa. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
88 lines
5.2 KiB
SQL
88 lines
5.2 KiB
SQL
-- Migración 012: Configuración de destinatarios de notificaciones
|
|
--
|
|
-- Mueve "quién recibe cada correo" desde variables de entorno (Dokploy) a la BD,
|
|
-- gestionable desde la app. Dos tablas:
|
|
-- notification_groups — grupos de destinatarios con un nivel de info fijo
|
|
-- notification_scenario_recipients — qué grupos recibe cada escenario (event_type)
|
|
--
|
|
-- IMPORTANTE: schema natur_reservas (la instancia Supabase es compartida; public es
|
|
-- otro proyecto). Ver CLAUDE.md §1.
|
|
|
|
-- ────────────────────────────────────────────────────────────
|
|
-- Grupos de destinatarios
|
|
-- ────────────────────────────────────────────────────────────
|
|
CREATE TABLE natur_reservas.notification_groups (
|
|
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
level TEXT NOT NULL DEFAULT 'completa'
|
|
CHECK (level IN ('reducida', 'completa')),
|
|
emails TEXT[] NOT NULL DEFAULT '{}',
|
|
enabled BOOLEAN NOT NULL DEFAULT true,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
COMMENT ON TABLE natur_reservas.notification_groups IS
|
|
'Grupos de destinatarios de notificaciones. level=reducida solo puede recibir la versión reducida de los correos (regla de privacidad).';
|
|
|
|
-- ────────────────────────────────────────────────────────────
|
|
-- Asignación escenario → grupos (N:M)
|
|
-- ────────────────────────────────────────────────────────────
|
|
CREATE TABLE natur_reservas.notification_scenario_recipients (
|
|
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
scenario TEXT NOT NULL, -- igual que notification_events.event_type
|
|
group_id UUID NOT NULL
|
|
REFERENCES natur_reservas.notification_groups(id) ON DELETE CASCADE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
CONSTRAINT uq_scenario_group UNIQUE (scenario, group_id)
|
|
);
|
|
|
|
CREATE INDEX idx_scenario_recipients_scenario
|
|
ON natur_reservas.notification_scenario_recipients(scenario);
|
|
|
|
COMMENT ON TABLE natur_reservas.notification_scenario_recipients IS
|
|
'Qué grupos reciben cada escenario (event_type). El motor de envío en apps/api lo consulta con service_role.';
|
|
|
|
-- ────────────────────────────────────────────────────────────
|
|
-- RLS: el acceso del frontend va por el API (service_role bypasea RLS).
|
|
-- Bloqueamos acceso directo de anon/authenticated; el API valida admin.
|
|
-- ────────────────────────────────────────────────────────────
|
|
ALTER TABLE natur_reservas.notification_groups ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE natur_reservas.notification_scenario_recipients ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- El API accede con service_role: bypasea RLS, pero necesita el GRANT de tabla
|
|
-- (en schemas custom no se concede automáticamente, a diferencia de public).
|
|
GRANT USAGE ON SCHEMA natur_reservas TO service_role;
|
|
GRANT ALL ON natur_reservas.notification_groups TO service_role;
|
|
GRANT ALL ON natur_reservas.notification_scenario_recipients TO service_role;
|
|
|
|
REVOKE ALL ON natur_reservas.notification_groups FROM anon;
|
|
REVOKE ALL ON natur_reservas.notification_scenario_recipients FROM anon;
|
|
|
|
-- ────────────────────────────────────────────────────────────
|
|
-- Semilla inicial (editable después desde la pantalla)
|
|
-- ────────────────────────────────────────────────────────────
|
|
WITH nuevos AS (
|
|
INSERT INTO natur_reservas.notification_groups (name, level, emails) VALUES
|
|
('Teneriffa', 'reducida',
|
|
ARRAY['uwe.dotschkis@teneriffa2000.de', 'j.reichstein@teneriffa2000.de']),
|
|
('Naturcalabacera (Admin)', 'completa',
|
|
ARRAY['administracion@naturcalabacera.com']),
|
|
('Limpieza', 'completa',
|
|
ARRAY['limpieza.naturcalabacera@gmail.com']) -- placeholder editable
|
|
RETURNING id, name
|
|
)
|
|
INSERT INTO natur_reservas.notification_scenario_recipients (scenario, group_id)
|
|
SELECT s.scenario, n.id
|
|
FROM nuevos n
|
|
JOIN (VALUES
|
|
('Teneriffa', 'reservation.created'),
|
|
('Teneriffa', 'reservation.updated'),
|
|
('Teneriffa', 'reservation.cancelled'),
|
|
('Naturcalabacera (Admin)', 'reservation.created'),
|
|
('Naturcalabacera (Admin)', 'reservation.updated'),
|
|
('Naturcalabacera (Admin)', 'reservation.cancelled'),
|
|
('Naturcalabacera (Admin)', 'reservation.invoice_second_notice'),
|
|
('Limpieza', 'reservation.pool_heating_notice')
|
|
) AS s(group_name, scenario) ON s.group_name = n.name;
|