Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Pulse ⚡ — real-time API uptime & incident monitoring

CI Live Demo

Live demo → (free-tier host, spins down after 15 min idle — first load may take ~30-50s to wake up)

A self-hostable uptime monitoring platform in the spirit of BetterStack / Checkly: create HTTP monitors, watch latency live over WebSockets, get incidents opened and resolved automatically, and publish a public status page — all from one Node.js codebase.

Built to production standards: worker-thread check engine, atomic multi-instance scheduling, MongoDB aggregation analytics, JWT + API-key auth, REST and GraphQL, a fully tested API, Docker deployment, and CI.

Demo in 30 seconds

# zero configuration needed — uses an in-memory MongoDB in dev
cd server && npm install && npm run dev
# in another terminal
cd client && npm install && npm run dev
# open http://localhost:5173, sign up, add https://example.com — watch it go live

Production (real MongoDB, single container serving API + dashboard):

cp .env.example .env   # set JWT_SECRET
docker compose up --build
# open http://localhost:8000

What it does

  • Monitors — HTTP(S) checks with configurable interval (10s–1h), timeout, expected status, and response-keyword assertion.
  • Live dashboard — every check result is pushed to the browser over Socket.io (JWT-authenticated handshake, one private room per user). No refresh, ever.
  • Incidents — opened automatically after N consecutive failures, resolved on recovery, with duration tracking for MTTR reporting. Toast notifications in real time.
  • Analytics — uptime %, average and p95 latency, and time-bucketed latency series computed in MongoDB aggregation pipelines (not in JS).
  • Public status pages/status/:slug, unauthenticated, status.stripe.com-style.
  • Two APIs — versioned REST (/api/v1) and GraphQL (/api/graphql) over the same auth and data layer. Programmatic access via X-Api-Key.

Architecture

flowchart LR
    subgraph Browser
        UI[React dashboard]
    end
    subgraph Node.js — clusterable
        API[Express REST v1 + GraphQL]
        WS[Socket.io<br/>JWT handshake, room per user]
        SCHED[Scheduler<br/>atomic claim via findOneAndUpdate]
        POOL[worker_threads pool<br/>HTTP checks off the event loop]
        INC[Incident engine<br/>threshold open / auto resolve]
    end
    DB[(MongoDB<br/>TTL-expired checks, aggregations)]
    TARGETS[[Your endpoints]]

    UI <-->|REST / GraphQL| API
    UI <-->|live check results| WS
    SCHED -->|claims due monitors| DB
    SCHED --> POOL --> TARGETS
    POOL --> SCHED
    SCHED --> INC --> WS
    SCHED -->|check results| DB
    API --> DB
Loading

Design decisions worth reading

  • Checks never block the API. HTTP probes run on a fixed-size worker_threads pool. A burst of slow or hung endpoints saturates the pool queue, not the event loop serving requests.
  • Horizontally scalable scheduling. Due monitors are claimed with an atomic findOneAndUpdate that pushes nextRunAt forward using an aggregation-pipeline update. Run 1 process or 10 (CLUSTER=true forks per core) — each check still executes exactly once.
  • High-volume data is bounded. Raw check documents carry a 30-day TTL index; dashboards read denormalised live state on the monitor document, so listing 100 monitors costs one query, not a join.
  • Analytics belong in the database. Uptime %, p95, and time-bucketed series are single aggregation pipelines — the Node process never loads raw check history into memory.
  • Security defaults on. Helmet, per-route and global rate limits (tighter on auth to slow credential stuffing), bcrypt password hashing, JWT expiry, request-body size limits, per-user data isolation enforced in every query, and API keys that are hashed-key-shaped secrets rotated server-side.
  • Zero-config developer experience. No MONGO_URL in dev? The server boots mongodb-memory-server automatically. Clone → npm run dev → working product.

API quick reference

POST   /api/v1/auth/register        {email, name, password} → {user, token}
POST   /api/v1/auth/login           {email, password} → {user, token}
GET    /api/v1/auth/me
POST   /api/v1/auth/api-key         rotate programmatic API key

GET    /api/v1/monitors             ?page&limit&status&q (paginated)
POST   /api/v1/monitors             {name, url, intervalSeconds, expectedStatus, keyword?}
GET    /api/v1/monitors/:id
PATCH  /api/v1/monitors/:id
DELETE /api/v1/monitors/:id
GET    /api/v1/monitors/:id/checks  recent raw checks
GET    /api/v1/monitors/:id/stats   ?range=1h|24h|7d → summary + chart series

GET    /api/v1/incidents            ?status&monitor (paginated)
GET    /api/v1/status/:slug         public status page (no auth)

POST   /api/graphql                 e.g. { monitors { name status summary { uptimePct p95Latency } } }

WebSocket events (Socket.io, auth: { token }): check:result, incident:opened, incident:resolved.

Testing

19 integration tests (Jest + Supertest + in-memory MongoDB) cover auth, ownership isolation, monitor CRUD and validation, the full incident lifecycle against a real local HTTP target that is toggled healthy/unhealthy mid-test, stats aggregations, GraphQL, and public status pages.

cd server && npm test

CI (GitHub Actions) runs the suite on Node 20 and 22, builds the dashboard, and builds the production Docker image on every push.

Performance & scaling

  • CLUSTER=true npm start forks one worker per core; the atomic scheduler claim makes this safe.
  • Stateless API (JWT) → drop it behind any load balancer.
  • To go multi-node with WebSockets, add the Socket.io Redis adapter — the emit layer is isolated in src/sockets/io.js for exactly that reason.

Stack

Node.js · Express · MongoDB/Mongoose · Socket.io · worker_threads · GraphQL · JWT · Jest/Supertest · React (Vite) · Docker · GitHub Actions

Deploying your own instance

Deploy to Render

  1. Create a free MongoDB Atlas M0 cluster, add a database user, and allow network access from 0.0.0.0/0 (or Render's static IPs on paid plans). Copy the connection string.
  2. Click Deploy to Render above (or New + → Blueprint, connect this repo — Render reads render.yaml automatically).
  3. Paste the Atlas connection string into the MONGO_URL environment variable when prompted. JWT_SECRET is generated for you.
  4. Render builds the Dockerfile (client build → server) and deploys a single web service exposing the API, GraphQL endpoint, WebSocket server, and the React dashboard.

About

Real-time API uptime & incident monitoring platform — Node.js, Express, MongoDB, Socket.io, worker_threads, GraphQL, Docker, CI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages