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
- On startup, the service loads all YAML notification job definitions from
src/notifications/ - A polling loop runs every 60 seconds (configurable) for each job
- For Redis-sourced jobs, it scans
txn:*:{period}keys to find organizations with usage above the threshold - 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.
| Field | Value |
|---|---|
identifier | usage-warning-70pct |
source | redis |
threshold | 0.7 |
upperBound | 1.0 |
cooldownHours | 24 |
Usage Exceeded (100%)
File: src/notifications/usage-exceeded.yaml
Sent when an organization's transaction usage reaches or exceeds 100% of their plan limit.
| Field | Value |
|---|---|
identifier | usage-exceeded |
source | redis |
threshold | 1.0 |
cooldownHours | 24 |
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
| Field | Type | Description |
|---|---|---|
identifier | string | Unique job name (used for S3 cooldown keys) |
description | string | Human-readable description |
source | "redis" or "database" | Where to check for threshold data |
threshold | number | Minimum usage ratio to trigger (0.0 - 1.0) |
upperBound | number | Maximum usage ratio (optional, excludes orgs above this) |
cooldownHours | number | Hours between repeat notifications for the same org |
email.subject | string | Handlebars template for email subject |
email.body | string | Handlebars HTML template for email body |
Template Variables
The following variables are available in Handlebars templates:
| Variable | Description |
|---|---|
{{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 Variable | Default | Description |
|---|---|---|
DATABASE_URL | (required) | PostgreSQL connection string |
REDIS_URL | (required) | Redis connection URL |
S3_NOTIFICATIONS_BUCKET | rw-stream-notifications | S3 bucket for cooldown state |
SES_FROM_NAME | RocketWave Pulse | Sender display name |
SES_FROM_EMAIL | (required) | Sender email address |
AWS_REGION | us-east-2 | AWS region for SES and S3 |
ENVIRONMENT | production | Environment name |
LOG_LEVEL | info | Pino log level |
STRIPE_PRICE_ID_FREE | — | Stripe price ID for free plan |
STRIPE_PRICE_ID_INDIVIDUAL | — | Stripe price ID for individual plan |
STRIPE_PRICE_ID_TEAM | — | Stripe 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
Related Topics
- Dashboard - Billing — View subscription and usage
- Pricing — Available subscription plans
- Billing API — Transaction usage API endpoints