# Notification Service ## Overview The **Notification Service** handles multi-channel communication with bakery owners, managers, and staff through Email (SMTP) and WhatsApp (Twilio). It delivers critical operational alerts (stockouts, quality issues, equipment maintenance), business insights (daily summaries, forecast updates), and customer communications (order confirmations, delivery notifications). The service ensures that important information reaches the right people at the right time through their preferred communication channel. ## Key Features ### Multi-Channel Communication - **Email (SMTP)** - Professional email notifications - **WhatsApp (Twilio)** - Instant messaging for urgent alerts - **SMS (Twilio)** - Fallback text messaging - **Channel Prioritization** - Auto-select channel by urgency - **Channel Preferences** - User-defined communication preferences - **Multi-Recipient** - Send to individuals or groups - **Delivery Tracking** - Monitor delivery status per channel ### Email Capabilities - **HTML Templates** - Professional branded emails - **Plain Text Fallback** - Ensure compatibility - **Attachments** - PDF reports, invoices, documents - **Inline Images** - Logo, charts embedded - **Email Templates** - Pre-designed templates per alert type - **Variable Substitution** - Dynamic content per recipient - **Batch Sending** - Efficient bulk email delivery ### WhatsApp Integration - **Twilio API** - Official WhatsApp Business API - **Rich Messages** - Text, images, documents - **Message Templates** - Pre-approved templates for compliance - **Interactive Messages** - Quick reply buttons - **Media Support** - Send images, PDFs - **Delivery Receipts** - Read/delivered status - **Opt-In Management** - GDPR-compliant consent tracking ### Notification Types - **Critical Alerts** - Stockouts, equipment failure, quality issues - **High Priority** - Low stock warnings, forecast anomalies - **Medium Priority** - Daily summaries, scheduled reports - **Low Priority** - Weekly digests, monthly reports - **Informational** - System updates, tips, best practices - **Customer Notifications** - Order confirmations, delivery updates ### Template Management - **Template Library** - 20+ pre-built templates - **Template Versioning** - Track template changes - **Multi-Language** - Spanish, English, Catalan - **Variable Placeholders** - Dynamic content insertion - **Template Preview** - Test before sending - **Custom Templates** - Create tenant-specific templates - **Template Analytics** - Open rates, click rates ### Delivery Management - **Queue System** - Prioritized delivery queue - **Retry Logic** - Automatic retry on failure - **Rate Limiting** - Respect API rate limits - **Delivery Status** - Track sent, delivered, failed, read - **Failure Handling** - Fallback to alternative channels - **Bounce Management** - Handle invalid addresses - **Unsubscribe Management** - Honor opt-out requests ### Analytics & Reporting - **Delivery Metrics** - Success rates per channel - **Open Rates** - Email open tracking - **Click Rates** - Link click tracking - **Response Times** - Time to read/acknowledge - **Channel Effectiveness** - Compare channel performance - **Cost Analysis** - Communication costs per channel - **User Engagement** - Active users per channel ## Business Value ### For Bakery Owners - **Real-Time Alerts** - Know critical issues immediately - **Channel Flexibility** - Email for reports, WhatsApp for urgent - **Cost Effective** - WhatsApp cheaper than SMS - **Professional Communication** - Branded emails enhance reputation - **Customer Engagement** - Order updates improve satisfaction - **Remote Management** - Stay informed from anywhere ### Quantifiable Impact - **Response Time**: 90% faster with WhatsApp alerts (minutes vs. hours) - **Issue Resolution**: 50-70% faster with immediate notifications - **Cost Savings**: €50-150/month (WhatsApp vs. SMS or phone calls) - **Customer Satisfaction**: 20-30% improvement with order updates - **Staff Efficiency**: 3-5 hours/week saved on manual communication - **Alert Reliability**: 99%+ delivery rate ### For Operations Staff - **Instant Alerts** - WhatsApp notifications on critical issues - **Actionable Information** - Clear instructions in alerts - **Mobile Access** - Receive alerts on phone - **Alert History** - Review past notifications - **Acknowledgment** - Confirm receipt of critical alerts ### For Customers - **Order Confirmation** - Immediate order receipt - **Delivery Updates** - Know when order is ready - **Personalized Communication** - Address by name - **Multiple Channels** - Choose email or WhatsApp - **Professional Image** - Branded communication ## Technology Stack - **Framework**: FastAPI (Python 3.11+) - Async web framework - **Database**: PostgreSQL 17 - Notification history - **Queue**: RabbitMQ 4.1 - Notification queue - **Caching**: Redis 7.4 - Template cache - **Email**: SMTP (SendGrid, Amazon SES, SMTP server) - **WhatsApp**: Twilio API - WhatsApp Business - **SMS**: Twilio API - SMS fallback - **Templates**: Jinja2 - Template rendering - **Logging**: Structlog - Structured JSON logging - **Metrics**: Prometheus Client - Delivery metrics ## API Endpoints (Key Routes) ### Notification Sending - `POST /api/v1/notifications/send` - Send notification - `POST /api/v1/notifications/send-email` - Send email - `POST /api/v1/notifications/send-whatsapp` - Send WhatsApp - `POST /api/v1/notifications/send-sms` - Send SMS - `POST /api/v1/notifications/send-batch` - Bulk send ### Notification Management - `GET /api/v1/notifications` - List notifications - `GET /api/v1/notifications/{notification_id}` - Get notification details - `GET /api/v1/notifications/{notification_id}/status` - Check delivery status - `POST /api/v1/notifications/{notification_id}/retry` - Retry failed notification - `DELETE /api/v1/notifications/{notification_id}` - Cancel pending notification ### Template Management - `GET /api/v1/notifications/templates` - List templates - `GET /api/v1/notifications/templates/{template_id}` - Get template - `POST /api/v1/notifications/templates` - Create template - `PUT /api/v1/notifications/templates/{template_id}` - Update template - `POST /api/v1/notifications/templates/{template_id}/preview` - Preview template - `DELETE /api/v1/notifications/templates/{template_id}` - Delete template ### User Preferences - `GET /api/v1/notifications/preferences` - Get user preferences - `PUT /api/v1/notifications/preferences` - Update preferences - `POST /api/v1/notifications/preferences/opt-out` - Opt out of notifications - `POST /api/v1/notifications/preferences/opt-in` - Opt in to notifications ### Analytics - `GET /api/v1/notifications/analytics/dashboard` - Notification dashboard - `GET /api/v1/notifications/analytics/delivery-rates` - Delivery success rates - `GET /api/v1/notifications/analytics/channel-performance` - Channel comparison - `GET /api/v1/notifications/analytics/engagement` - User engagement metrics ### Webhooks - `POST /api/v1/notifications/webhooks/twilio` - Twilio status webhook - `POST /api/v1/notifications/webhooks/sendgrid` - SendGrid webhook - `POST /api/v1/notifications/webhooks/ses` - Amazon SES webhook ## Database Schema ### Main Tables **notifications** ```sql CREATE TABLE notifications ( id UUID PRIMARY KEY, tenant_id UUID NOT NULL, notification_type VARCHAR(100) NOT NULL, -- alert, report, customer, system priority VARCHAR(50) NOT NULL, -- critical, high, medium, low channel VARCHAR(50) NOT NULL, -- email, whatsapp, sms status VARCHAR(50) DEFAULT 'pending', -- pending, queued, sent, delivered, failed, cancelled -- Recipient recipient_user_id UUID, recipient_name VARCHAR(255), recipient_email VARCHAR(255), recipient_phone VARCHAR(50), -- Content subject VARCHAR(500), message_body TEXT NOT NULL, template_id UUID, template_variables JSONB, -- Attachments attachments JSONB, -- Array of attachment URLs -- Delivery scheduled_at TIMESTAMP, sent_at TIMESTAMP, delivered_at TIMESTAMP, read_at TIMESTAMP, failed_at TIMESTAMP, failure_reason TEXT, retry_count INTEGER DEFAULT 0, max_retries INTEGER DEFAULT 3, -- External IDs external_message_id VARCHAR(255), -- Twilio SID, SendGrid message ID external_status VARCHAR(100), -- Tracking opened BOOLEAN DEFAULT FALSE, clicked BOOLEAN DEFAULT FALSE, open_count INTEGER DEFAULT 0, click_count INTEGER DEFAULT 0, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), INDEX idx_notifications_tenant_status (tenant_id, status), INDEX idx_notifications_recipient (recipient_user_id), INDEX idx_notifications_scheduled (scheduled_at) WHERE status = 'pending' ); ``` **notification_templates** ```sql CREATE TABLE notification_templates ( id UUID PRIMARY KEY, tenant_id UUID, -- NULL for global templates template_name VARCHAR(255) NOT NULL, template_code VARCHAR(100) NOT NULL, -- Unique code for reference template_type VARCHAR(100) NOT NULL, -- alert, report, customer, system channel VARCHAR(50) NOT NULL, -- email, whatsapp, sms, all -- Content subject_template TEXT, body_template TEXT NOT NULL, html_body_template TEXT, -- For email -- Variables required_variables JSONB, -- Array of required variable names sample_variables JSONB, -- Sample data for preview -- Configuration language VARCHAR(10) DEFAULT 'es', -- es, en, ca is_active BOOLEAN DEFAULT TRUE, is_system_template BOOLEAN DEFAULT FALSE, -- Cannot be modified by users version INTEGER DEFAULT 1, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), UNIQUE(tenant_id, template_code, channel) ); ``` **notification_preferences** ```sql CREATE TABLE notification_preferences ( id UUID PRIMARY KEY, tenant_id UUID NOT NULL, user_id UUID NOT NULL, -- Channel preferences email_enabled BOOLEAN DEFAULT TRUE, whatsapp_enabled BOOLEAN DEFAULT TRUE, sms_enabled BOOLEAN DEFAULT TRUE, preferred_channel VARCHAR(50) DEFAULT 'email', -- Notification type preferences critical_alerts_enabled BOOLEAN DEFAULT TRUE, high_priority_enabled BOOLEAN DEFAULT TRUE, medium_priority_enabled BOOLEAN DEFAULT TRUE, low_priority_enabled BOOLEAN DEFAULT TRUE, -- Timing preferences quiet_hours_start TIME, -- e.g., 22:00 quiet_hours_end TIME, -- e.g., 08:00 weekend_notifications BOOLEAN DEFAULT TRUE, -- Specific notification types stockout_alerts BOOLEAN DEFAULT TRUE, quality_alerts BOOLEAN DEFAULT TRUE, forecast_updates BOOLEAN DEFAULT TRUE, daily_summary BOOLEAN DEFAULT TRUE, weekly_report BOOLEAN DEFAULT TRUE, -- Contact details email_address VARCHAR(255), phone_number VARCHAR(50), whatsapp_number VARCHAR(50), whatsapp_opt_in BOOLEAN DEFAULT FALSE, whatsapp_opt_in_date TIMESTAMP, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), UNIQUE(tenant_id, user_id) ); ``` **notification_delivery_log** ```sql CREATE TABLE notification_delivery_log ( id UUID PRIMARY KEY, notification_id UUID REFERENCES notifications(id) ON DELETE CASCADE, attempt_number INTEGER NOT NULL, channel VARCHAR(50) NOT NULL, status VARCHAR(50) NOT NULL, -- success, failed, bounced status_code VARCHAR(50), status_message TEXT, provider_response JSONB, attempted_at TIMESTAMP DEFAULT NOW(), INDEX idx_delivery_log_notification (notification_id) ); ``` **notification_events** ```sql CREATE TABLE notification_events ( id UUID PRIMARY KEY, notification_id UUID REFERENCES notifications(id) ON DELETE CASCADE, event_type VARCHAR(50) NOT NULL, -- opened, clicked, bounced, complained event_data JSONB, user_agent TEXT, ip_address INET, occurred_at TIMESTAMP DEFAULT NOW(), INDEX idx_events_notification (notification_id), INDEX idx_events_type (notification_id, event_type) ); ``` **notification_costs** ```sql CREATE TABLE notification_costs ( id UUID PRIMARY KEY, tenant_id UUID NOT NULL, month DATE NOT NULL, -- First day of month channel VARCHAR(50) NOT NULL, -- Volume notifications_sent INTEGER DEFAULT 0, notifications_delivered INTEGER DEFAULT 0, -- Costs (in euros) estimated_cost DECIMAL(10, 4) DEFAULT 0.0000, calculated_at TIMESTAMP DEFAULT NOW(), UNIQUE(tenant_id, month, channel) ); ``` ### Indexes for Performance ```sql CREATE INDEX idx_notifications_tenant_priority ON notifications(tenant_id, priority, status); CREATE INDEX idx_notifications_sent_at ON notifications(sent_at DESC); CREATE INDEX idx_templates_tenant_active ON notification_templates(tenant_id, is_active); CREATE INDEX idx_preferences_user ON notification_preferences(user_id); CREATE INDEX idx_delivery_log_status ON notification_delivery_log(status, attempted_at DESC); ``` ## Business Logic Examples ### Send Email Notification ```python async def send_email_notification( tenant_id: UUID, recipient_email: str, recipient_name: str, subject: str, body: str, html_body: str = None, priority: str = 'medium', attachments: list = None ) -> Notification: """ Send email notification via SMTP. """ # Create notification record notification = Notification( tenant_id=tenant_id, notification_type='email', priority=priority, channel='email', status='queued', recipient_name=recipient_name, recipient_email=recipient_email, subject=subject, message_body=body, attachments=attachments ) db.add(notification) await db.flush() try: # Configure SMTP smtp_config = await get_smtp_config(tenant_id) # Create email message from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.base import MIMEBase from email import encoders msg = MIMEMultipart('alternative') msg['From'] = smtp_config.from_address msg['To'] = recipient_email msg['Subject'] = subject # Add plain text body part1 = MIMEText(body, 'plain', 'utf-8') msg.attach(part1) # Add HTML body if provided if html_body: part2 = MIMEText(html_body, 'html', 'utf-8') msg.attach(part2) # Add attachments if attachments: for attachment in attachments: part = MIMEBase('application', 'octet-stream') with open(attachment['path'], 'rb') as file: part.set_payload(file.read()) encoders.encode_base64(part) part.add_header( 'Content-Disposition', f'attachment; filename= {attachment["filename"]}' ) msg.attach(part) # Send email import smtplib with smtplib.SMTP(smtp_config.host, smtp_config.port) as server: if smtp_config.use_tls: server.starttls() if smtp_config.username and smtp_config.password: server.login(smtp_config.username, smtp_config.password) server.send_message(msg) # Update notification status notification.status = 'sent' notification.sent_at = datetime.utcnow() # Log delivery log = NotificationDeliveryLog( notification_id=notification.id, attempt_number=1, channel='email', status='success' ) db.add(log) await db.commit() logger.info("Email sent successfully", notification_id=str(notification.id), recipient=recipient_email) return notification except Exception as e: notification.status = 'failed' notification.failed_at = datetime.utcnow() notification.failure_reason = str(e) notification.retry_count += 1 # Log failure log = NotificationDeliveryLog( notification_id=notification.id, attempt_number=notification.retry_count, channel='email', status='failed', status_message=str(e) ) db.add(log) await db.commit() logger.error("Email send failed", notification_id=str(notification.id), error=str(e)) # Retry if within limits if notification.retry_count < notification.max_retries: await schedule_retry(notification.id, delay_minutes=5) raise ``` ### Send WhatsApp Notification ```python async def send_whatsapp_notification( tenant_id: UUID, recipient_phone: str, recipient_name: str, message: str, priority: str = 'high', template_name: str = None, template_variables: dict = None ) -> Notification: """ Send WhatsApp notification via Twilio. """ # Check user opt-in preferences = await get_user_preferences_by_phone(tenant_id, recipient_phone) if not preferences or not preferences.whatsapp_opt_in: raise ValueError("User has not opted in to WhatsApp notifications") # Create notification record notification = Notification( tenant_id=tenant_id, notification_type='alert', priority=priority, channel='whatsapp', status='queued', recipient_name=recipient_name, recipient_phone=recipient_phone, message_body=message ) db.add(notification) await db.flush() try: # Configure Twilio from twilio.rest import Client twilio_config = await get_twilio_config(tenant_id) client = Client(twilio_config.account_sid, twilio_config.auth_token) # Format phone number (E.164 format) formatted_phone = format_phone_e164(recipient_phone) # Send WhatsApp message if template_name: # Use WhatsApp template (pre-approved) twilio_message = client.messages.create( from_=f'whatsapp:{twilio_config.whatsapp_number}', to=f'whatsapp:{formatted_phone}', content_sid=template_name, content_variables=json.dumps(template_variables) if template_variables else None ) else: # Send freeform message twilio_message = client.messages.create( from_=f'whatsapp:{twilio_config.whatsapp_number}', to=f'whatsapp:{formatted_phone}', body=message ) # Update notification status notification.status = 'sent' notification.sent_at = datetime.utcnow() notification.external_message_id = twilio_message.sid notification.external_status = twilio_message.status # Log delivery log = NotificationDeliveryLog( notification_id=notification.id, attempt_number=1, channel='whatsapp', status='success', status_code=twilio_message.status, provider_response={'sid': twilio_message.sid} ) db.add(log) await db.commit() logger.info("WhatsApp sent successfully", notification_id=str(notification.id), recipient=recipient_phone, twilio_sid=twilio_message.sid) return notification except Exception as e: notification.status = 'failed' notification.failed_at = datetime.utcnow() notification.failure_reason = str(e) notification.retry_count += 1 log = NotificationDeliveryLog( notification_id=notification.id, attempt_number=notification.retry_count, channel='whatsapp', status='failed', status_message=str(e) ) db.add(log) await db.commit() logger.error("WhatsApp send failed", notification_id=str(notification.id), error=str(e)) # Fallback to SMS if critical if priority == 'critical' and notification.retry_count >= notification.max_retries: await send_sms_notification( tenant_id, recipient_phone, recipient_name, message, priority ) raise def format_phone_e164(phone: str) -> str: """ Format phone number to E.164 standard (e.g., +34612345678). """ import phonenumbers # Parse phone number (assume Spain +34 if no country code) try: parsed = phonenumbers.parse(phone, 'ES') return phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.E164) except: # If parsing fails, return as-is return phone ``` ### Template Rendering ```python async def render_notification_template( template_id: UUID, variables: dict ) -> dict: """ Render notification template with variables. """ # Get template template = await db.get(NotificationTemplate, template_id) if not template: raise ValueError("Template not found") # Validate required variables required_vars = template.required_variables or [] missing_vars = [v for v in required_vars if v not in variables] if missing_vars: raise ValueError(f"Missing required variables: {', '.join(missing_vars)}") # Render subject from jinja2 import Template subject = None if template.subject_template: subject_template = Template(template.subject_template) subject = subject_template.render(**variables) # Render body body_template = Template(template.body_template) body = body_template.render(**variables) # Render HTML body if available html_body = None if template.html_body_template: html_template = Template(template.html_body_template) html_body = html_template.render(**variables) return { 'subject': subject, 'body': body, 'html_body': html_body, 'template_name': template.template_name, 'channel': template.channel } ``` ### Smart Channel Selection ```python async def send_smart_notification( tenant_id: UUID, user_id: UUID, notification_type: str, priority: str, subject: str, message: str, template_id: UUID = None, template_variables: dict = None ) -> Notification: """ Send notification via optimal channel based on priority and user preferences. """ # Get user preferences preferences = await get_user_preferences(tenant_id, user_id) user = await get_user(user_id) # Determine channel based on priority and preferences channel = None if priority == 'critical': # Critical: WhatsApp if enabled, else SMS, else email if preferences.whatsapp_enabled and preferences.whatsapp_opt_in: channel = 'whatsapp' elif preferences.sms_enabled: channel = 'sms' else: channel = 'email' elif priority == 'high': # High: Preferred channel if enabled if preferences.preferred_channel == 'whatsapp' and preferences.whatsapp_enabled: channel = 'whatsapp' elif preferences.preferred_channel == 'sms' and preferences.sms_enabled: channel = 'sms' else: channel = 'email' else: # Medium/Low: Email default channel = 'email' # Check quiet hours if not priority == 'critical': if await is_quiet_hours(preferences): # Delay notification until quiet hours end send_at = await calculate_quiet_hours_end(preferences) logger.info("Delaying notification due to quiet hours", user_id=str(user_id), send_at=send_at) return await schedule_notification( tenant_id, user_id, channel, subject, message, scheduled_at=send_at ) # Send via selected channel if channel == 'whatsapp': return await send_whatsapp_notification( tenant_id, preferences.whatsapp_number or user.phone, user.name, message, priority, template_variables=template_variables ) elif channel == 'sms': return await send_sms_notification( tenant_id, user.phone, user.name, message, priority ) else: # email # Render template if provided if template_id: rendered = await render_notification_template(template_id, template_variables) subject = rendered['subject'] message = rendered['body'] html_body = rendered['html_body'] else: html_body = None return await send_email_notification( tenant_id, preferences.email_address or user.email, user.name, subject, message, html_body=html_body, priority=priority ) ``` ## Events & Messaging ### Published Events (RabbitMQ) **Exchange**: `notifications` **Routing Keys**: `notifications.sent`, `notifications.failed`, `notifications.delivered` **Notification Sent Event** ```json { "event_type": "notification_sent", "tenant_id": "uuid", "notification_id": "uuid", "channel": "whatsapp", "priority": "critical", "recipient_name": "Juan García", "notification_type": "stockout_alert", "timestamp": "2025-11-06T09:00:00Z" } ``` **Notification Failed Event** ```json { "event_type": "notification_failed", "tenant_id": "uuid", "notification_id": "uuid", "channel": "email", "priority": "high", "failure_reason": "SMTP connection timeout", "retry_count": 2, "max_retries": 3, "will_retry": true, "timestamp": "2025-11-06T10:30:00Z" } ``` **Notification Delivered Event** ```json { "event_type": "notification_delivered", "tenant_id": "uuid", "notification_id": "uuid", "channel": "whatsapp", "delivered_at": "2025-11-06T09:01:00Z", "read_at": "2025-11-06T09:02:00Z", "delivery_time_seconds": 60, "timestamp": "2025-11-06T09:02:00Z" } ``` ### Consumed Events - **From Alert Processor**: Alert events trigger notifications - **From Orchestrator**: Daily summaries, scheduled reports - **From Orders**: Order confirmations, delivery updates - **From Production**: Quality issue alerts, batch completion - **From Procurement**: Stockout warnings, purchase order confirmations ## Custom Metrics (Prometheus) ```python # Notification metrics notifications_sent_total = Counter( 'notifications_sent_total', 'Total notifications sent', ['tenant_id', 'channel', 'priority', 'status'] ) notification_delivery_time_seconds = Histogram( 'notification_delivery_time_seconds', 'Time from creation to delivery', ['tenant_id', 'channel'], buckets=[1, 5, 10, 30, 60, 300, 600] ) notification_delivery_rate = Gauge( 'notification_delivery_rate_percentage', 'Notification delivery success rate', ['tenant_id', 'channel'] ) notification_costs_euros = Counter( 'notification_costs_euros_total', 'Total notification costs', ['tenant_id', 'channel'] ) email_open_rate = Gauge( 'email_open_rate_percentage', 'Email open rate', ['tenant_id', 'template_type'] ) ``` ## Configuration ### Environment Variables **Service Configuration:** - `PORT` - Service port (default: 8015) - `DATABASE_URL` - PostgreSQL connection string - `REDIS_URL` - Redis connection string - `RABBITMQ_URL` - RabbitMQ connection string **Email (SMTP) Configuration:** - `SMTP_HOST` - SMTP server host - `SMTP_PORT` - SMTP server port (default: 587) - `SMTP_USERNAME` - SMTP username - `SMTP_PASSWORD` - SMTP password - `SMTP_FROM_ADDRESS` - From email address - `SMTP_USE_TLS` - Enable TLS (default: true) **Twilio Configuration:** - `TWILIO_ACCOUNT_SID` - Twilio account SID - `TWILIO_AUTH_TOKEN` - Twilio auth token - `TWILIO_WHATSAPP_NUMBER` - WhatsApp sender number (format: +1234567890) - `TWILIO_SMS_NUMBER` - SMS sender number **Delivery Configuration:** - `MAX_RETRY_ATTEMPTS` - Maximum retry attempts (default: 3) - `RETRY_DELAY_MINUTES` - Delay between retries (default: 5) - `ENABLE_QUIET_HOURS` - Respect user quiet hours (default: true) - `BATCH_SIZE` - Bulk sending batch size (default: 100) **Cost Configuration:** - `WHATSAPP_COST_PER_MESSAGE` - Cost per WhatsApp (default: 0.005 EUR) - `SMS_COST_PER_MESSAGE` - Cost per SMS (default: 0.08 EUR) - `EMAIL_COST_PER_MESSAGE` - Cost per email (default: 0.001 EUR) ## Development Setup ### Prerequisites - Python 3.11+ - PostgreSQL 17 - Redis 7.4 - RabbitMQ 4.1 - SMTP server or SendGrid account - Twilio account (for WhatsApp/SMS) ### Local Development ```bash cd services/notification python -m venv venv source venv/bin/activate pip install -r requirements.txt export DATABASE_URL=postgresql://user:pass@localhost:5432/notification export REDIS_URL=redis://localhost:6379/0 export RABBITMQ_URL=amqp://guest:guest@localhost:5672/ export SMTP_HOST=smtp.sendgrid.net export SMTP_USERNAME=apikey export SMTP_PASSWORD=your_sendgrid_api_key export TWILIO_ACCOUNT_SID=your_twilio_sid export TWILIO_AUTH_TOKEN=your_twilio_token alembic upgrade head python main.py ``` ## Integration Points ### Dependencies - **SMTP Server** - Email delivery (SendGrid, SES, SMTP) - **Twilio API** - WhatsApp and SMS delivery - **Auth Service** - User information - **PostgreSQL** - Notification history - **Redis** - Template caching - **RabbitMQ** - Alert consumption ### Dependents - **Alert Processor** - Sends alerts via notifications - **Orders Service** - Customer order notifications - **Orchestrator** - Daily summaries and reports - **All Services** - Critical alerts routing - **Frontend Dashboard** - Notification preferences UI ## Business Value for VUE Madrid ### Problem Statement Spanish bakeries struggle with: - Delayed awareness of critical issues (stockouts discovered too late) - Manual phone calls and texts consuming staff time - No systematic customer communication (order confirmations) - Expensive SMS costs (€0.08/message in Spain) - No record of communications sent - Staff missing important alerts ### Solution Bakery-IA Notification Service provides: - **Real-Time Alerts**: WhatsApp notifications within seconds - **Multi-Channel**: Email for reports, WhatsApp for urgent - **Cost Effective**: WhatsApp 90% cheaper than SMS - **Customer Communication**: Professional order updates - **Communication History**: Complete audit trail - **Smart Routing**: Right message, right channel, right time ### Quantifiable Impact **Cost Savings:** - €50-150/month using WhatsApp vs. SMS (90% cost reduction) - 3-5 hours/week saved on manual phone calls/texts (€180-300/month) - **Total: €230-450/month savings** **Operational Efficiency:** - 90% faster response to critical issues (minutes vs. hours) - 50-70% faster issue resolution with immediate awareness - 99%+ alert delivery reliability - 24/7 notification delivery (no manual intervention) **Customer Satisfaction:** - 20-30% improvement with order confirmation/updates - Professional brand image with branded emails - Customer choice of email or WhatsApp - Personalized communication ### Target Market Fit (Spanish Bakeries) - **WhatsApp Culture**: Spain has 91% WhatsApp penetration rate - **Mobile First**: Bakery owners/managers always on mobile - **Cost Sensitive**: SMS costs high in Spain (€0.08 vs. €0.005 WhatsApp) - **Communication Style**: Spanish business culture values personal touch - **GDPR Compliance**: Opt-in management meets EU regulations ### ROI Calculation **Investment**: €0 additional (included in subscription) + Twilio costs **Cost Savings**: €230-450/month (vs. SMS + manual communication) **Operational Value**: 50-70% faster issue resolution **Monthly Value**: €230-450 savings + operational efficiency **Annual ROI**: €2,760-5,400 value per bakery **Payback**: Immediate (cost savings from day one) ### Competitive Advantage - **WhatsApp Integration**: Few Spanish bakery platforms offer WhatsApp - **Multi-Channel**: Flexibility competitors don't provide - **Smart Routing**: Auto-select channel by urgency/preference - **Cost Effective**: 90% cheaper than SMS-only solutions - **GDPR Compliant**: Built-in opt-in management --- **Copyright © 2025 Bakery-IA. All rights reserved.**