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>
This commit is contained in:
parent
ad9944d86b
commit
c730a9672d
156
schemas/notifications.sql
Normal file
156
schemas/notifications.sql
Normal file
@ -0,0 +1,156 @@
|
||||
-- ============================================
|
||||
-- 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();
|
||||
Loading…
Reference in New Issue
Block a user