Skip to content

ADR-006: Separate Notification Service ​

Status ​

Accepted

Context ​

Multiple services need to send notifications (welcome emails, verification alerts, subscription reminders). We needed to decide:

  • Embedded in each service: Simple but duplicated logic
  • Shared package: No independent scaling
  • Separate service: Independent, scalable, single responsibility

Decision ​

We will create a separate Notification Service for email/SMS notifications.

Rationale ​

Why Separate Service? ​

ReasonExplanation
Cross-cutting concernIdentity, Admin, Subscription, Prescription all need notifications
External integrationsEmail provider (SES), SMS gateway (Twilio)
Retry logicFailed notifications need retries, backoff
Template managementEmail/SMS templates with variables
Rate limitingProvider-specific rate limits
SchedulingTrial ending reminders, subscription renewals
Audit trailTrack what was sent, when, delivery status

Event-Driven Integration ​

Other services publish events → Notification service consumes and sends:

Identity Service          Notification Service
     │                          │
     │── user.registered ──────>│── Welcome email
     │── doctor.profile.created │── Verification pending email
     │                          │
Admin Service                 │
     │                          │
     │── doctor.verified ──────>│── Congratulations email
     │── doctor.rejected ──────>│── Rejection email
     │                          │
Organization Service          │
     │                          │
     │── member.invited ────────│── Invitation email
     │                          │
Subscription Service          │
     │                          │
     │── subscription.canceled ─│── Confirmation email
     │── subscription.trial.ending │── Reminder email

Provider Ports ​

go
type EmailProvider interface {
    Send(ctx context.Context, to, subject, body string) error
}

type SMSProvider interface {
    Send(ctx context.Context, to, message string) error
}

Stub Providers for Development ​

go
// Logs to console instead of sending
emailProvider := email.NewStubEmailProvider()
smsProvider := sms.NewStubSMSProvider()

Replace with real implementations (AWS SES, Twilio) when going to production.

Consequences ​

Positive ​

  • Single responsibility for notifications
  • Independent scaling
  • Easy to swap providers
  • Template management centralized

Negative ​

  • Additional service to deploy
  • Eventual consistency for notification delivery
  • ADR-003: Event-Driven Architecture

Documentation follows the source. Planned contracts are marked explicitly.