-- ============================================ -- 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();