Skip to main content

Notifications

The Notifications service is a YAML-driven worker that monitors platform usage and sends email alerts to organization administrators when transaction limits are approaching or exceeded.

Architecture

┌──────────────────────────────────────────────────────┐
│ Notifications Service │
│ │
│ ┌─────────────────┐ ┌──────────────────────────┐ │
│ │ YAML Job Loader │──▶│ NotificationScheduler │ │
│ │ (startup) │ │ (poll every 60s) │ │
│ └─────────────────┘ └───────────┬──────────────┘ │
│ │ │
│ ┌──────────────┐ ┌──────────────▼──────────────┐ │
│ │ RedisService │──▶│ Check thresholds │ │
│ │ (txn:* keys) │ │ per organization │ │
│ └──────────────┘ └──────────────┬──────────────┘ │
│ │ │
│ ┌──────────────┐ ┌──────────────▼──────────────┐ │
│ │ S3Service │──▶│ Cooldown / dedup check │ │
│ │ (cooldown) │ └──────────────┬──────────────┘ │
│ └──────────────┘ │ │
│ ┌──────────────▼──────────────┐ │
│ ┌──────────────┐ │ Render Handlebars template │ │
│ │ EmailService │◀──│ and send via SES │ │
│ │ (AWS SES) │ └─────────────────────────────┘ │
│ └──────────────┘ │
│ ┌─────────────────────────────┐ │
│ ┌──────────────┐ │ DatabaseService │ │
│ │ PostgreSQL │◀──│ (org names, admin users, │ │
│ │ │ │ plan limits) │ │
│ └──────────────┘ └─────────────────────────────┘ │
└──────────────────────────────────────────────────────┘

How It Works

  1. On startup, the service loads all YAML notification job definitions from src/notifications/
  2. A polling loop runs every 60 seconds (configurable) for each job
  3. For Redis-sourced jobs, it scans txn:*:{period} keys to find organizations with usage above the threshold
  4. For each qualifying organization:
    • Check S3 cooldown to avoid sending duplicate notifications
    • Look up admin users from the database to determine recipients
    • Render the Handlebars email template with organization and usage data
    • Send the email via AWS SES
    • Write a cooldown marker to S3

Notification Types

Usage Warning (70%)

File: src/notifications/usage-warning-70pct.yaml

Sent when an organization's transaction usage reaches 70% of their plan limit but has not yet exceeded it.

FieldValue
identifierusage-warning-70pct
sourceredis
threshold0.7
upperBound1.0
cooldownHours24

Usage Exceeded (100%)

File: src/notifications/usage-exceeded.yaml

Sent when an organization's transaction usage reaches or exceeds 100% of their plan limit.

FieldValue
identifierusage-exceeded
sourceredis
threshold1.0
cooldownHours24

YAML Job Format

Each notification job is defined as a YAML file:

identifier: usage-warning-70pct
description: Warn organizations approaching their transaction limit
source: redis
threshold: 0.7
upperBound: 1.0
cooldownHours: 24

email:
subject: "RocketWave Pulse: You've used {{percentUsed}}% of your transaction limit"
body: |
<h2>Usage Alert for {{organizationName}}</h2>
<p>Your organization has used <strong>{{currentCount}}</strong> of
<strong>{{limit}}</strong> transactions this billing period
({{percentUsed}}% of your limit).</p>
<p>Consider upgrading your plan to avoid service interruption.</p>

Job Fields

FieldTypeDescription
identifierstringUnique job name (used for S3 cooldown keys)
descriptionstringHuman-readable description
source"redis" or "database"Where to check for threshold data
thresholdnumberMinimum usage ratio to trigger (0.0 - 1.0)
upperBoundnumberMaximum usage ratio (optional, excludes orgs above this)
cooldownHoursnumberHours between repeat notifications for the same org
email.subjectstringHandlebars template for email subject
email.bodystringHandlebars HTML template for email body

Template Variables

The following variables are available in Handlebars templates:

VariableDescription
{{organizationName}}Organization display name
{{currentCount}}Current transaction count
{{limit}}Plan transaction limit
{{percentUsed}}Usage percentage (e.g., "73")
{{planKey}}Subscription plan key (e.g., "free", "individual")
{{period}}Billing period identifier

Cooldown and Deduplication

Notifications use S3 for cooldown tracking to prevent sending duplicate alerts:

  • Key format: {identifier}/{orgId}/last-notification.json
  • Bucket: S3_NOTIFICATIONS_BUCKET (default: rw-stream-notifications)
  • Check: Before sending, the service checks if a notification was sent within the cooldown window
  • Write: After sending, a timestamp is written to track the last notification time

Configuration

Environment VariableDefaultDescription
DATABASE_URL(required)PostgreSQL connection string
REDIS_URL(required)Redis connection URL
S3_NOTIFICATIONS_BUCKETrw-stream-notificationsS3 bucket for cooldown state
SES_FROM_NAMERocketWave PulseSender display name
SES_FROM_EMAIL(required)Sender email address
AWS_REGIONus-east-2AWS region for SES and S3
ENVIRONMENTproductionEnvironment name
LOG_LEVELinfoPino log level
STRIPE_PRICE_ID_FREEStripe price ID for free plan
STRIPE_PRICE_ID_INDIVIDUALStripe price ID for individual plan
STRIPE_PRICE_ID_TEAMStripe price ID for team plan

The Stripe price IDs are used to map subscriptions to plan keys for resolving transaction limits.

Deployment

The Notifications service runs as a Docker container on AWS ECS Fargate:

  • Cluster: RW-Streaming-Notifications-Cluster
  • Service: RW-Streaming-Notifications
  • Logs: CloudWatch /ecs/rw-streaming-notifications
  • CI/CD: GitHub Actions deploys on push to main