Queue-Based Notification Service
Build a notification service in TypeScript that other applications use to send notifications to users through several channels: email, in-app messages, and push or SMS through pluggable providers (with fake providers for development). Notifications can be sent immediately or scheduled for later, respect each user's preferences (which channels, and quiet hours when nothing non-urgent is sent), are queued durably and retried when a provider fails, and every attempt is recorded, so the delivery history shows exactly what happened. A React dashboard shows notifications, their status and history. You'll learn queue-based design on Node.js, scheduling, user preferences and time zones, retries with backoff, idempotency, provider adapters, and building an operations dashboard.
- Estimate
- ~14h
- Steps
- 7
- Completed by
- 0
- Proposed by
- codeseed.app
Node.js · React
Project roadmap
- 01
Design the service
~2hWrite DESIGN.md: a notification (id, idempotency key, user, template, data, urgency, channels and send time) creates one delivery per channel, each with a status (scheduled, queued, sending, sent, failed or dead), attempts and next attempt time; user preferences (enabled channels, time zone and quiet hours); the provider interface; and the storage (SQLite or PostgreSQL). Explain how quiet hours delay non-urgent deliveries and how retries work. Done when: DESIGN.md covers notifications, deliveries, preferences and providers.
- 02
Accept and schedule notifications
~2hBuild a Node.js API with TypeScript (Fastify or Express) with POST /notifications (validated with Zod, with an API key), which stores the notification and creates deliveries for the channels the user allows, scheduled for now or a later time, adjusted for quiet hours in the user's time zone. A repeated idempotency key returns the existing notification. Add endpoints to manage user preferences. Done when: notifications create the right deliveries, and quiet hours push non-urgent ones to later.
- 03
Deliver through providers
~2.5hDefine a Provider interface (send returning success, a temporary error or a permanent error) with implementations: email through Nodemailer (tested with Mailpit), in-app (stored for the user to read through an API), and fake SMS and push providers that can be told to fail. Render templates per channel. Workers claim due deliveries in a transaction, send them, and record each attempt. Done when: deliveries go out through each channel, and each attempt is recorded.
- 04
Retry and recover
~2hRetry temporary failures with exponential backoff and jitter up to a maximum, then mark the delivery dead; don't retry permanent failures. Recover deliveries stuck in sending after a crash (with a lease timeout). Limit sending per provider (a rate limit) and per user (so nobody gets flooded). Done when: a failing provider's deliveries are retried and eventually succeed or die, and a crash loses nothing.
- 05
Build the dashboard
~2hBuild a React dashboard with counts by status and channel, a searchable list of notifications, each notification's deliveries with their full attempt history and errors, and buttons to retry dead deliveries or cancel scheduled ones. Done when: the dashboard shows accurate, live information and its actions work.
- 06
Add observability
~1hLog every attempt with the notification, channel, provider, attempt number, duration and result (never message contents), and expose metrics: deliveries sent and failed per channel per minute, queue backlog, and the age of the oldest due delivery. Done when: the metrics show the service's health.
- 07
Test it
~2.5hWrite Vitest tests with fake providers and a controllable clock: channel selection from preferences, quiet hours across time zones (including an urgent notification during quiet hours), scheduling, retries and dead deliveries, idempotency, crash recovery, and rate limits. Done when: npm test passes.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack