NotifyHub is a SaaS platform for sending notifications across email, webhooks, and push — through a single, unified API.
Developers waste time integrating multiple notification providers. Each channel has different APIs, retry logic, and monitoring needs. When something fails, there's no visibility into what went wrong or where the message got stuck.
A unified API with one endpoint to send notifications across any channel, with built-in queuing, retry, rate limiting, and real-time delivery tracking. An interactive sandbox lets you fire a notification and watch it flow through the entire pipeline — queues, processors, retries, delivery — in real time via WebSockets.
- Multi-channel: email (Resend), webhooks, push (FCM)
- Async processing with BullMQ + Redis
- Exponential backoff retry with dead letter queues (10s / 30s / 90s)
- Rate limiting per API key (Redis sliding window, 100 req/min)
- Real-time delivery tracking via WebSockets (Socket.io)
- Template engine with
{{variable}}substitution - Idempotency support for safe retries
- Interactive API documentation (Swagger/OpenAPI)
- Chaos engineering sandbox — inject failures and watch the system recover
- Multi-tenancy — JWT auth + API key per project
Client (React SPA)
|
| REST + WebSocket
v
┌─────────────────────────┐
│ NestJS API │
│ │
│ Controller → Service │
│ │ │ │
│ v v │
│ PostgreSQL BullMQ │
│ (TypeORM) (Redis) │
│ │ │
│ ┌──────┴───┐ │
│ │ Processor │ │
│ │ (email / │ │
│ │ webhook) │ │
│ └──────┬────┘ │
│ │ │
│ EventEmitter2 │
│ │ │
│ ┌────────v───┐ │
│ │ Gateway │ │
│ │ (Socket.io) │ │
│ └──────┬──────┘ │
└─────────────────│─────────┘
v
WebSocket push
to client feed
- Send —
POST /api/v1/notifications/sendwithX-API-Keyheader - Queue — Notification saved to PostgreSQL, job added to BullMQ
- Process — Worker picks up job, calls provider (mock or real)
- Retry — Failed jobs retry with exponential backoff: 10s → 30s → 90s
- Deliver — Success updates status to SENT, then DELIVERED
- Broadcast — Every status change is pushed to the client via WebSocket
| Layer | Technologies |
|---|---|
| Backend | NestJS 11, TypeORM 0.3, PostgreSQL 16, BullMQ 5, Redis 7, Socket.io 4, Passport/JWT |
| Frontend | React 19, Vite 8, TailwindCSS 4, Framer Motion 12, TanStack React Query 5, Zustand 5 |
| Monorepo | pnpm workspaces (no Turborepo) |
| Deployment | Oracle Cloud Always Free (backend, Docker Compose, Nginx), Vercel (frontend), GitHub Actions (CI/CD) |
| Testing | Jest 30 (backend, 125 tests), Vitest 4 (frontend, 65 tests) |
- Dashboard: https://notifyhub-nine.vercel.app
- API Docs (Swagger): https://notifyhub-api.iqsolutionstech.com/docs
- Guest mode: click "Try Demo" — no signup required
- Node.js >= 22
- pnpm >= 10
- Docker (for PostgreSQL and Redis)
git clone https://github.com/CamiloMaria/notifyhub.git
cd notifyhub
pnpm install
# Start PostgreSQL and Redis
docker compose up -d
# Copy environment variables
cp .env.example .env
# Start API + frontend
pnpm devThe API runs at http://localhost:3000 and the frontend at http://localhost:5173.
Swagger docs at http://localhost:3000/docs.
# Send a notification
curl -X POST http://localhost:3000/api/v1/notifications/send \
-H "Content-Type: application/json" \
-H "X-API-Key: nhk_demo_sandbox_key_for_development_only" \
-d '{
"channel": "email",
"recipient": "user@example.com",
"subject": "Hello from NotifyHub",
"body": "Your order #1234 has shipped."
}'Full API reference available at /docs (Swagger UI).
Event-driven architecture pays off. Decoupling notification dispatch from delivery via BullMQ meant adding chaos engineering, retry logic, and real-time tracking required zero changes to the send endpoint. Events flow through the system and each component reacts independently.
The sandbox is the documentation. Instead of writing architecture docs nobody reads, building an interactive demo that shows the pipeline in action communicates more in 30 seconds than diagrams ever could. The chaos mode — where you inject failures and watch the system retry and recover — is the strongest proof of fault tolerance.
Multi-tenancy is an early decision. Bolting on project isolation and API key scoping after the fact would have meant rewriting most queries. Designing for it from phase one (JWT + project ownership validation on every endpoint) kept the codebase clean.
MIT