feat: configuración de destinatarios de notificaciones desde la app

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>
This commit is contained in:
2026-06-17 11:12:58 +01:00
parent 5656ad13ad
commit ee03f0b36d
19 changed files with 991 additions and 103 deletions

View File

@@ -2,9 +2,10 @@
export type { Reservation, NewReservation, ReservationOrigin, Property, PricingSnapshot, WebhookPayload } from './types/reservation.js';
export type { UserRole, UserProfile } from './types/user.js';
export type { PricingInput, PricingResult } from './types/pricing.js';
export type { NotificationEventType, NotificationStatus, NotificationEvent } from './types/notification.js';
export type { NotificationEventType, NotificationStatus, NotificationEvent, NotificationLevel, NotificationGroup, NotificationConfig, NotificationScenarioMeta } from './types/notification.js';
// Constants
export { CONFIGURABLE_SCENARIOS } from './types/notification.js';
export { PROPERTY_CONFIG, PROPERTIES, DEFAULT_IGIC_RATE, getExtraPersonRate } from './constants/properties.js';
export { ORIGIN_CONFIG } from './constants/origins.js';

View File

@@ -3,12 +3,50 @@ export type NotificationEventType =
| 'reservation.created'
| 'reservation.updated'
| 'reservation.cancelled'
| 'reservation.reminder_24h'
| 'reservation.invoice_second_notice'
| 'reservation.pool_heating_notice';
export type NotificationStatus = 'pending' | 'sent' | 'failed';
// ── Configuración de destinatarios (gestionada desde la app) ──
// Nivel de información que un grupo puede recibir.
// 'reducida' nunca recibe datos completos del cliente (regla de privacidad).
export type NotificationLevel = 'reducida' | 'completa';
export interface NotificationGroup {
id: string;
name: string;
level: NotificationLevel;
emails: string[];
enabled: boolean;
created_at?: string;
updated_at?: string;
}
// Estado completo de la configuración: grupos + qué grupos recibe cada escenario.
// assignments: { [event_type]: groupId[] }
export interface NotificationConfig {
groups: NotificationGroup[];
assignments: Record<string, string[]>;
}
// Escenarios configurables desde la pantalla, con etiqueta y si tienen doble versión.
export interface NotificationScenarioMeta {
scenario: NotificationEventType;
label: string;
/** true = tiene versión reducida y completa (escenarios CRUD de reserva) */
dualVersion: boolean;
}
export const CONFIGURABLE_SCENARIOS: NotificationScenarioMeta[] = [
{ scenario: 'reservation.created', label: 'Nueva reserva', dualVersion: true },
{ scenario: 'reservation.updated', label: 'Reserva modificada (fechas)', dualVersion: true },
{ scenario: 'reservation.cancelled', label: 'Reserva cancelada', dualVersion: true },
{ scenario: 'reservation.invoice_second_notice', label: 'Segunda factura (10 días antes)', dualVersion: false },
{ scenario: 'reservation.pool_heating_notice', label: 'Calefacción de piscina (48h antes)', dualVersion: false },
];
export interface NotificationEvent {
id: string;
reservation_id: string;