michangarrito-database-v2/schemas/notifications.sql
rckrdmrd c730a9672d feat(notifications): Add notifications schema DDL (MCH-017)
- Create notifications schema
- Add tables: notifications, notification_templates, notification_preferences, device_tokens
- Add indexes for performance
- Add default notification templates for orders, payments, alerts
- Add updated_at triggers

Sprint 3: MCH-017 Notificaciones

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 03:32:35 -06:00

157 lines
6.9 KiB
PL/PgSQL

-- ============================================
-- Schema: notifications
-- Épica: MCH-017 - Notificaciones
-- Version: 1.0.0
-- ============================================
-- Create schema
CREATE SCHEMA IF NOT EXISTS notifications;
-- ============================================
-- Table: notifications
-- Stores all notification records
-- ============================================
CREATE TABLE notifications.notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
user_id UUID,
customer_id UUID,
type VARCHAR(50) NOT NULL,
channel VARCHAR(20) NOT NULL,
title VARCHAR(255) NOT NULL,
body TEXT NOT NULL,
data JSONB,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
error_message TEXT,
retry_count INTEGER DEFAULT 0,
scheduled_at TIMESTAMPTZ,
sent_at TIMESTAMPTZ,
delivered_at TIMESTAMPTZ,
read_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Indexes
CREATE INDEX idx_notifications_tenant_user_status
ON notifications.notifications(tenant_id, user_id, status);
CREATE INDEX idx_notifications_tenant_created
ON notifications.notifications(tenant_id, created_at);
CREATE INDEX idx_notifications_scheduled
ON notifications.notifications(scheduled_at)
WHERE scheduled_at IS NOT NULL AND status = 'pending';
-- ============================================
-- Table: notification_templates
-- Notification templates per type and channel
-- ============================================
CREATE TABLE notifications.notification_templates (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID, -- NULL = default template
type VARCHAR(50) NOT NULL,
channel VARCHAR(20) NOT NULL,
title VARCHAR(255) NOT NULL,
body TEXT NOT NULL,
variables JSONB, -- List of required variables
active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(tenant_id, type, channel)
);
-- ============================================
-- Table: notification_preferences
-- User preferences per channel
-- ============================================
CREATE TABLE notifications.notification_preferences (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
channel VARCHAR(20) NOT NULL,
enabled BOOLEAN DEFAULT true,
quiet_hours_enabled BOOLEAN DEFAULT false,
quiet_hours_start TIME,
quiet_hours_end TIME,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(user_id, channel)
);
-- ============================================
-- Table: device_tokens
-- FCM/APNs tokens for push notifications
-- ============================================
CREATE TABLE notifications.device_tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
platform VARCHAR(20) NOT NULL,
token TEXT NOT NULL UNIQUE,
device_name VARCHAR(100),
active BOOLEAN DEFAULT true,
last_used_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Indexes
CREATE INDEX idx_device_tokens_user ON notifications.device_tokens(user_id);
-- ============================================
-- Default Templates (seed data)
-- ============================================
INSERT INTO notifications.notification_templates (tenant_id, type, channel, title, body, variables) VALUES
-- Order notifications
(NULL, 'new_order', 'push', '🛒 Nuevo Pedido #{{order_id}}', 'Pedido de {{customer_name}} por ${{total}}', '["order_id", "customer_name", "total"]'),
(NULL, 'new_order', 'whatsapp', '🛒 *Nuevo Pedido*', 'Pedido #{{order_id}}\nCliente: {{customer_name}}\nTotal: ${{total}}\n\nRevisa tu app para confirmar.', '["order_id", "customer_name", "total"]'),
(NULL, 'order_confirmed', 'whatsapp', '✅ *Pedido Confirmado*', '¡Tu pedido #{{order_id}} ha sido confirmado!\n\nEstamos preparándolo.\nTe avisamos cuando esté listo.', '["order_id"]'),
(NULL, 'order_ready', 'push', '📦 Pedido Listo', 'Tu pedido #{{order_id}} está listo para recoger', '["order_id"]'),
(NULL, 'order_ready', 'whatsapp', '📦 *Pedido Listo*', '¡Tu pedido #{{order_id}} está listo!\n\nPuedes pasar a recogerlo a:\n{{business_address}}', '["order_id", "business_address"]'),
(NULL, 'order_delivered', 'whatsapp', '🎉 *Pedido Entregado*', '¡Tu pedido #{{order_id}} ha sido entregado!\n\nTotal: ${{total}}\n\n¡Gracias por tu compra!', '["order_id", "total"]'),
(NULL, 'order_cancelled', 'whatsapp', '❌ *Pedido Cancelado*', 'Tu pedido #{{order_id}} ha sido cancelado.\n\nSi tienes dudas, contáctanos.', '["order_id"]'),
-- Payment notifications
(NULL, 'payment_received', 'push', '💰 Pago Recibido', 'Se recibió pago de ${{amount}} de {{customer_name}}', '["amount", "customer_name"]'),
-- Alert notifications
(NULL, 'low_stock', 'push', '⚠️ Stock Bajo', '{{product_name}}: quedan {{quantity}} unidades', '["product_name", "quantity"]'),
(NULL, 'fiado_reminder', 'whatsapp', '💳 *Recordatorio de Pago*', 'Hola {{customer_name}},\n\nTe recordamos que tienes un saldo pendiente de ${{balance}} en {{business_name}}.\n\n¿Cuándo podrías pasar a abonar?', '["customer_name", "balance", "business_name"]'),
-- Report notifications
(NULL, 'daily_summary', 'push', '📊 Resumen del Día', 'Ventas: ${{total_sales}} | Pedidos: {{orders_count}}', '["total_sales", "orders_count"]'),
(NULL, 'weekly_report', 'whatsapp', '📊 *Reporte Semanal*', '📈 Resumen de la semana:\n\n💰 Ventas: ${{total_sales}}\n📦 Pedidos: {{orders_count}}\n🎫 Ticket promedio: ${{avg_ticket}}\n\n¿Necesitas más detalles?', '["total_sales", "orders_count", "avg_ticket"]'),
-- System notifications
(NULL, 'welcome', 'whatsapp', '👋 *¡Bienvenido!*', '¡Hola {{name}}! Bienvenido a {{business_name}}.\n\nPuedes escribirme para:\n• Ver productos\n• Hacer pedidos\n• Consultar tu cuenta\n\n¿En qué te puedo ayudar?', '["name", "business_name"]');
-- ============================================
-- Updated_at trigger
-- ============================================
CREATE OR REPLACE FUNCTION notifications.update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_notifications_updated_at
BEFORE UPDATE ON notifications.notifications
FOR EACH ROW EXECUTE FUNCTION notifications.update_updated_at();
CREATE TRIGGER trg_templates_updated_at
BEFORE UPDATE ON notifications.notification_templates
FOR EACH ROW EXECUTE FUNCTION notifications.update_updated_at();
CREATE TRIGGER trg_preferences_updated_at
BEFORE UPDATE ON notifications.notification_preferences
FOR EACH ROW EXECUTE FUNCTION notifications.update_updated_at();
CREATE TRIGGER trg_device_tokens_updated_at
BEFORE UPDATE ON notifications.device_tokens
FOR EACH ROW EXECUTE FUNCTION notifications.update_updated_at();