Skip to content

Notifications: Service + Bull queue for async delivery #39

Description

@manoahLinks

Summary

Create the notification service that orchestrates multi-channel message delivery (email, SMS, WhatsApp) via a Bull queue. The service receives notification requests from other modules and routes them to the correct provider based on the channel.

Architecture

Any Module (tickets, auth, payouts)
  │
  ▼
NotificationsService.send(notification)
  │
  ▼
Bull Queue: "notifications"
  │
  ▼
NotificationProcessor
  ├── channel: EMAIL     → SendGridProvider
  ├── channel: SMS       → TwilioSmsProvider
  └── channel: WHATSAPP  → TwilioWhatsappProvider
  │
  ▼
Update Notification record: status → SENT | FAILED

NotificationsService API

interface SendNotificationDto {
  userId?: string;          // optional — for tracking
  ticketId?: string;        // optional — for tracking
  channel: NotificationChannel;  // EMAIL | SMS | WHATSAPP
  type: string;             // "ticket_confirmation" | "password_reset" | etc.
  recipient: {
    email?: string;
    phone?: string;         // +234XXXXXXXXXX
    name: string;
  };
  data: Record<string, any>;  // template variables
  attachments?: Array<{        // QR code image, etc.
    filename: string;
    content: Buffer | string;
    contentType: string;
  }>;
}

Usage from other modules:

// After ticket mint confirmed:
await this.notificationsService.send({
  ticketId: ticket.id,
  channel: ticket.deliveryChannel,
  type: 'ticket_confirmation',
  recipient: {
    email: ticket.buyerEmail,
    phone: ticket.buyerPhone,
    name: ticket.buyerName,
  },
  data: {
    ticketReference: ticket.reference,
    eventName: event.name,
    eventDate: event.startTime,
    venue: event.venue,
    ticketType: ticketType.name,
    qrCodeUrl: ticket.qrCode,
  },
});

Notification Types

Type Channels Trigger
ticket_confirmation Email + buyer's chosen channel After NFT mint + QR generation
payment_failed Email Webhook reports failed payment
password_reset Email Forgot password request
event_published Email Organizer publishes event
payout_completed Email Organizer payout processed
payout_failed Email Payout failed after retries
welcome Email User registration

Tasks

  • Create src/notifications/notifications.service.ts:
    • send(dto: SendNotificationDto) — creates Notification record, adds to Bull queue
    • sendMultiChannel(dto) — sends to Email AND another channel (for ticket confirmation)
  • Create src/notifications/processors/notification.processor.ts:
    • @Processor('notifications')
    • Routes to correct provider by channel
    • Updates Notification record: status → SENT, sentAt = now
    • On failure: status → FAILED, retries
  • Create src/notifications/notifications.module.ts:
    • Register Bull queue "notifications"
    • Register all providers
    • Export NotificationsService
  • Add retry config: 3 attempts, exponential backoff (2s, 10s, 30s)

Queue Configuration

{
  name: 'notifications',
  defaultJobOptions: {
    attempts: 3,
    backoff: { type: 'exponential', delay: 2000 },
    removeOnComplete: 100,   // keep last 100 completed jobs
    removeOnFail: 500,       // keep last 500 failed jobs
  }
}

Acceptance Criteria

  • Notifications queued asynchronously (never block the caller)
  • Notification record created in DB for every send attempt
  • Routes to correct provider based on channel
  • Status tracked: PENDING → SENT or FAILED
  • sentAt timestamp recorded on success
  • Retries 3x on transient failures
  • Multi-channel support (email + SMS/WhatsApp for ticket confirmation)

Metadata

Metadata

Assignees

No one assigned

    Labels

    notificationsEmail, SMS, and WhatsApp notificationsphase-7Phase 7: Notifications

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions