NotifyHub is a multi-tenant event delivery platform built with a Node.js + Express backend and a React dashboard frontend.
A tenant can:
- register and log in
- generate an API key
- create event subscriptions
- publish events into NotifyHub
- fan those events out to email and webhook destinations
- inspect event history and delivery logs from the dashboard
The main idea is:
- A tenant publishes an event to
POST /api/v1/eventsusing an API key. - NotifyHub stores the event and accepts it immediately.
- The event processor finds all matching active subscriptions for that tenant and event type.
- NotifyHub delivers the event to every matching channel:
- webhook
- Delivery attempts are recorded in delivery logs with status, attempts, and error details.
This means one event publish can trigger multiple downstream deliveries automatically.
- Multi-tenant auth with JWT access and refresh tokens
- API key based event ingestion
- Email delivery via SMTP and Nodemailer
- Webhook delivery with signing secret support
- Delivery logs for each subscription attempt
- Retry support for failed or partial events
- Subscription management with active/inactive toggle
- Dashboard with overview stats, event list, event detail view, and test publisher
- Official shadcn UI based frontend setup
- Node.js
- Express 5
- MongoDB + Mongoose
- Zod
- JWT
- bcryptjs
- Axios
- Nodemailer
- Handlebars
- React 18
- Vite
- TypeScript
- React Router v6
- Tailwind CSS v4
- shadcn/ui
- Axios
MERN/
├── client/ # React dashboard
└── server/ # Express API
├── app.js
├── server.js
└── src/
├── app.routes.js
├── lib/
├── middleware/
└── modules/
├── auth/
├── event/
├── notification/
├── stats/
└── subscription/
POST /api/auth/registerPOST /api/auth/loginPOST /api/auth/refreshPOST /api/auth/logoutPOST /api/auth/api-key
The dashboard uses JWT auth. The event ingestion endpoint uses API key auth.
A tenant creates subscriptions such as:
order.created-> email ->alerts@example.comorder.created-> webhook ->https://example.com/webhook
Each matching subscription becomes one delivery route when the event arrives.
An external system or the dashboard test publisher sends:
POST /api/v1/events
X-API-Key: <tenant-api-key>
Content-Type: application/json{
"eventType": "order.created",
"payload": {
"orderId": "ORD-1001",
"amount": 500
},
"idempotencyKey": "order-created-ORD-1001"
}NotifyHub matches active subscriptions by:
tenantIdeventType
Then it attempts delivery to all matching destinations.
The dashboard provides:
- stats overview
- subscription CRUD
- event list
- event detail
- delivery log inspection
- retry action for failed or partial events
POST /api/auth/registerPOST /api/auth/loginPOST /api/auth/refreshPOST /api/auth/logoutPOST /api/auth/api-key
GET /api/subscriptionsPOST /api/subscriptionsGET /api/subscriptions/:idPUT /api/subscriptions/:idDELETE /api/subscriptions/:idPATCH /api/subscriptions/:id/toggle
POST /api/v1/eventsGET /api/eventsGET /api/events/:idPOST /api/events/:id/retry
GET /api/stats/overview
Success responses:
{
"success": true,
"data": {}
}Error responses:
{
"success": false,
"message": "Something went wrong",
"statusCode": 400
}Validation errors are routed through the shared error pipeline so frontend error handling stays consistent.
Create a .env file in server/ for backend config.
Typical backend variables:
PORT=8000
MONGODB_URL=your_mongodb_connection_string
DBNAME=your_database_name
JWT_ACCESS_SECRET=your_access_secret
JWT_REFRESH_SECRET=your_refresh_secret
SMTP_HOST=your_smtp_host
SMTP_PORT=587
SMTP_USERNAME=your_smtp_username
SMTP_PASSWORD=your_smtp_password
SMTP_FROM=no-reply@notifyhub.local
SMTP_SECURE=false
SMTP_TIMEOUT_MS=15000
FRONTEND_URL=http://localhost:5173Create a .env file in client/ for frontend config:
VITE_API_URL=http://localhost:8000cd server
npm installcd ../client
npm installcd ../server
npm run devBackend default URL:
http://localhost:8000
cd ../client
npm run devFrontend default URL:
http://localhost:5173
- Register a tenant
- Log in
- Generate an API key from the dashboard
- Create an email subscription or webhook subscription
- Use the Test Event Publisher on the dashboard
- Open Events and inspect the delivery logs
- Register and log in
- Generate an API key using the authenticated auth endpoint
- Create subscriptions with JWT auth
- Publish an event to
POST /api/v1/eventsusingX-API-Key - Inspect event status and delivery logs with JWT auth
Use Mailtrap or another SMTP provider, then:
- create an
emailsubscription - publish a matching event
- confirm message delivery in the provider inbox
Use a webhook catcher such as webhook.site, then:
- create a
webhooksubscription - publish a matching event
- confirm payload receipt in the target URL
- Event ingestion returns quickly and processes delivery asynchronously
- API key authentication uses an indexed tenant lookup flow instead of scanning all tenants
- Event and delivery log models use timestamps for reliable ordering
- Duplicate active subscriptions are guarded against
- Switching a subscription to webhook provisioning also ensures a signing secret is available
- SMTP connectivity is verified on server startup so mail issues surface earlier
- Protected routes require
nh_tokenin local storage - Refresh token support is used to avoid unnecessary logout on normal auth expiry
- API key publishing is isolated from the JWT interceptor flow so publish failures do not wrongly log the user out
- The UI uses official shadcn-generated primitives with project-specific styling layered on top
This project is in a strong MVP state and already supports the full core loop:
- onboard tenant
- configure subscription
- publish event
- deliver by email and webhook
- inspect logs
- retry failed delivery