Notifications Service
The ultimate communication orchestration layer. Decouple business logic from delivery concerns with a policy-driven engine for Email, SMS, Push, In-App, and more.
System Overview
In a modern microservices architecture, communication is the most fragile domain. The Launch Rail Notifications Service is a policy-driven orchestration engine that sits between your business logic and delivery providers. It handles the "Last Mile" of communication—ensuring messages are localized, legal, and delivered at the perfect moment.
Decoupled Producers
Backend services emit business intents (e.g. "order.shipped"), not formatting. The service handles HTML/Push rendering, translations, and templates.
Regulatory Guardrails
Natively enforces unsubscribe links, opt-out headers, quiet hours, and global rate limits to protect your sender reputation and compliance status.
The Orchestration Pipeline
Contract Validation
The ConnectRPC layer validates the event payload against the Catalog's JSON Schema. Immediate rejection on mismatch.
Rules & Preferences
Fetches user categories, quiet hours, and topic mutes. Determines if the event is "Critical" enough to bypass filters.
Localized Copy
Resolves the best template for the user's locale and resolves data variables using high-performance Go templates.
Multi-Worker Out
Asynchronous workers hand off to SMTP, FCM, or Twilio. Records the provider message ID for tracking.
The Events Catalog
The catalog is the runtime configuration that defines your notification taxonomy. Every event must be registered here before it can be triggered.
Comprehensive YAML Structure
events:
- name: "billing.invoice_reminder"
category: "billing"
priority: "HIGH" # LOW, NORMAL, HIGH, CRITICAL
bypass_user_preferences: false
supports_topic_mute: true
allowed_channels: ["EMAIL", "PUSH", "IN_APP"]
default_channels: ["EMAIL", "IN_APP"]
allowed_override_fields: ["locale", "priority_override"]
default_locale: "en-US"
fallback_locales: ["en", "uk-UA"]
default_ttl: "48h" # Drop if not delivered in 2 days
deduplication_window: "24h" # Prevent duplicate reminders
supports_digest: true
default_digest_policy:
aggregation_key: "invoice_id"
window: "24h"
rate_limit:
scope: "RECIPIENT_AND_TENANT"
max_events: 5
window: "24h"
payload_schema:
type: "object"
required: ["invoice_id", "due_date"]
properties:
invoice_id: { type: "string" }
due_date: { type: "string", format: "date" }Deduplication logic
If an event with the same Recipient + EventType + Category arrives within the deduplication_window, the service returns INGEST_STATUS_DUPLICATE and prevents a second delivery. This is perfect for noisy monitoring alerts or repeated user actions.
Throttling Policy
Rate limits are evaluated at the ingestion point. A RECIPIENT_AND_TENANT scope ensures a single workspace doesn't flood a single user, even across multiple projects.
Backend Producer SDK
Trigger & Batch RPCs
The service provides three primary ways to emit alerts:
Single Trigger
Synchronous validation for one recipient. Best for transactional actions.
Multi-Batch
Highly parallelized ingest for concrete recipient lists (up to 1,000 items).
Audience Job
Fires an asynchronous job to target large segments (e.g. "active-enterprise-users").
Advanced Scheduling Logic
Absolute UTC Time
The event fires at a specific global moment. 2 PM UTC is 2 PM UTC for everyone. Best for webinars or maintenance windows.
ScheduleAt: timestamppb.New(utcTime),Recipient Local Wall-Time
The service uses the recipient's resolved IANA TimeZone to determine the dispatch moment. "9 AM Local" means users in Tokyo receive it 8 hours before London.
LocalWallTime: "09:00:00",The Idempotency Guard
Producers should derive stable keys from business entities. If your payment service retries a request, use the payment_id as the key.
Delivery State Machine
Once an event is accepted, it transitions through several states. Monitoring these via the Admin API or Webhooks allows for high-granularity support observability.
Accepted for orchestration.
Waiting for local-time window.
Handed to Provider (Email/SMS API).
Provider confirmed delivery.
Permanent failure (Max retries hit).
Provider reported inbox rejection.
Suppressed by policy or TTL.
Canceled via CancelScheduledEvent.
Dropped to protect tenant throughput.
Frontend Integration
Patching Preferences with FieldMasks
// Correct way to update only Quiet Hours
await prefClient.updateUserPreferences({
preferences: {
quietHours: {
enabled: true,
startHour: 22,
endHour: 8
}
},
updateMask: { paths: ["quiet_hours"] } // Explicitly targets this field
});Push Device Lifecycle
Tokens are volatile. The system expects regular idempotent refreshes. Register the token on every app launch to ensure the server-side TTL never expires.
Automatic Expiry
Inactive devices are automatically marked EXPIRED after 90 days of silence, protecting you from FCM "ghost" send costs.
Multi-Device Routing
The service manages a set of active tokens per user. One "PUSH" trigger fans out to all active devices simultaneously.
Admin Operations
Provider Compatibility Matrix
| Channel | Technical Driver | Service Type |
|---|---|---|
| SMTP / SendGrid API / AWS SES | Transactional | |
| SMS | Twilio / Vonage / Amazon SNS | Legacy / Direct |
| PUSH | FCM (Android/Web) / APNS (Apple) | App Native |
| SLACK | OAuth App / Incoming Webhooks | Collaboration |
| WEBHOOK | HTTPS (HMAC Signed) | Enterprise |
Webhook HMAC Security
The service signs every outbound webhook with a SHA-256 HMAC signature. Consumers must verify the X-LaunchRail-Signature header against their shared secret.
// Verifying signature in Go
expectedMAC := hmac.New(sha256.New, secret)
expectedMAC.Write(bodyBytes)
expectedSignature := hex.EncodeToString(expectedMAC.Sum(nil))
if !hmac.Equal([]byte(receivedSignature), []byte(expectedSignature)) {
return status.Error(codes.Unauthenticated, "invalid signature")
}Compliance & GDPR Flow
One-Click Unsubscribe
Transactional emails automatically include List-Unsubscribe headers. The system exposes an unauthenticated compliance endpoint that uses signed tokens to record opt-outs without friction.
The "Right to be Forgotten"
The DeleteUserData RPC scrubs all delivery history, archived in-app items, and preference records across all providers instantly.
Technical Mastery Awaits.
The Notifications Service is built on Go 1.25, using ConnectRPC for networking and NATS for massive asynchronous fan-out. It is designed to scale to millions of alerts per minute.