Global website-uptime monitoring from a multi-region mesh of workers.
StatusBus is an uptime monitoring service. Users add websites through a web dashboard and StatusBus automatically checks them at frequent intervals, records the response time, and flags each site as Up or Down. The interesting part is how it checks:
- A single producer duty-cycles through every monitored website and publishes a "check
this URL" job onto a Redis Stream (
statusbus:web) every 60 seconds. - Consumers run in consumer groups, one group per region (India, US, ...). Because Redis consumer groups are separate per region, every region receives every job — each site is independently probed from multiple parts of the world.
- Each consumer performs a plain HTTP GET, times it (
rt_ms), classifies itUp/Down, reports the result back to a central API, and acknowledges the stream message. - The API persists every check as a
WebsiteTickin PostgreSQL; the dashboard shows each site's latest status, response time, and last-checked time.
Built as a Bun + Turborepo monorepo — Express 5 API, Next.js 15 frontend, Redis-Stream workers, Prisma 7 data layer — designed to run via Docker Compose, kind (local Kubernetes), or the live GCP deployment (Cloud Run edge + Neon/Upstash + self-managed kubeadm worker mesh).
- Account signup / signin (JWT-based sessions).
See SECURITY.md — bcrypt-hashed passwords, expiring & strictly-parsed
Bearer JWTs, and internal-key protection (x-internal-key) plus strict validation on
the monitoring worker endpoints, keeping the application secure and robust.
- Add and track any number of websites.
- Dashboard showing each site's current status (
Up/Down/Unknown), response time and last-checked timestamp. - Checks run on a 60-second global cadence, fanning out across all configured regions.
- Automatic classification: any HTTP failure (network, DNS, TLS, non-2xx) is reported
Down; successful loads reportUpwith the measured round-trip time.
The product is a work-in-progress proof-of-concept. Per-website detail pages, uptime analytics, alerts, and edit/delete are not fully implemented yet — see Roadmap & Limitations.
Browser ──▶ apps/fe (Next.js, :3000)
│ JWT + CORS
▼
apps/api (Express + Prisma, :3001) ──▶ PostgreSQL
public: /user/signup, /user/signin, (User, Website, Region, WebsiteTick)
internal: /website, /websites, /status/:id, /health,
/monitoring/websites, /monitoring/tick
▲ │
│ POST /monitoring/tick │ GET /monitoring/websites (every 60s)
│ {website_id, region_id│ by the producer
│ rt_ms, status} ▼
│ ┌────────────────────┐
│ │ Redis Stream │
│ │ statusbus:web │
│ └─────────┬──────────┘
│ │ XREADGROUP (group = REGION_ID)
│ ▼
│ apps/consumer × per region
└────── HTTP GET the URL → report tick → XACK
Full detail in docs/ARCHITECTURE.md.
| Path | Role |
|---|---|
apps/api |
Express 5 REST API, JWT auth, zod validation |
apps/fe |
Next.js 15 frontend (landing, auth, dashboard) |
apps/producer |
Scheduler: publishes every website to the Redis stream each 60 s |
apps/consumer |
Region worker: probes URLs and reports WebsiteTicks |
apps/tests |
Bunny integration tests against a live API |
packages/store |
Prisma 7 schema + generated client (store/client) |
packages/redisq |
Redis Streams wrapper (xAdd / consumer groups / ack) |
packages/shared-types |
Shared queue types (MessageType, StreamEntry) |
kind-deploy |
Local Kubernetes manifests + deploy.sh bootstrap |
gcp-infra/k8s |
Live worker mesh: kubeadm bootstrap scripts, spot MIGs, cluster secrets, manifests |
The whole design rationale (why Redis Streams, why fan-out, why central Postgres) is documented in docs/ARCHITECTURE.md.
- Bun
>= 1.2.18and Node>= 18 - Docker + Docker Compose v2 (for the one-command stack)
gcloud+kubectl+kind(only for the Kubernetes flows)
cp .env.example .env # then fill in POSTGRES_USER, POSTGRES_PASSWORD, DATABASE_URL, JWT_SECRET
docker compose up --buildThis brings up Postgres + Redis, runs prisma migrate deploy, then starts the API
(:3001), frontend (:3000), producer, and consumer.
One-time prerequisite — seed the regions. Consumers group by REGION_ID (1 = India,
2 = US); those rows must exist. docker compose up runs this automatically via the
seed-region service, but for ad-hoc runs from the repo root (with bun install already
run and DATABASE_URL reachable):
DATABASE_URL=postgresql://<user>:<pass>@localhost:5432/statusbus bun run ./packages/store/seedRegion.tsThen:
- Frontend: http://localhost:3000
- API health: http://localhost:3001/health
- API list of monitored sites: http://localhost:3001/monitoring/websites
bun install # install workspace deps
bun run dev # turbo dev → runs every app/packagePer-app scripts (each app has build; the API also has start). The API reads
apps/api/.env for DATABASE_URL, JWT_SECRET, PORT, HOST; the consumer reads
REGION_ID / CONSUMER_ID; workers use REDIS_URL and API_URL.
cd kind-deploy
./deploy.sh # creates cluster, applies infra + secrets, migrates + seeds, deploys, port-forwardsSee docs/DEPLOYMENT.md.
Requires a running API on :3001:
cd apps/tests
bun test| Variable | Used by | Purpose |
|---|---|---|
DATABASE_URL |
API, store, migration jobs | PostgreSQL connection string |
POSTGRES_USER / POSTGRES_PASSWORD |
docker-compose | Local Postgres service credentials |
JWT_SECRET |
API | HS256 secret for signing/verifying JWTs |
REDIS_URL |
producer, consumer, redisq | Redis connection string |
API_URL |
producer, consumer | Where to reach the backend (http://api:3001 in Docker) |
REGION_ID / CONSUMER_ID |
consumer | Region group name + consumer identity |
NEXT_PUBLIC_BACKEND_URL |
frontend (build-time) | Base URL of the API, inlined into the client bundle |
PORT / HOST are also respected by the API (defaults 3001 / 0.0.0.0).
- Producer polls
GET /monitoring/websitesevery 60 s andXADDs one entry per website ({url, id}) to the Redis streamstatusbus:web. - Consumer(s) each own a Redis consumer group named after their
REGION_ID. Every group independently reads the full stream, so every region checks every website. - For each job, the consumer
GETs the URL, times it, and POSTs{website_id, region_id, rt_ms, status}toPOST /monitoring/tickon the API. - The API writes a
WebsiteTickrow; the dashboard'sGET /websitesjoins the latest tick per site for display.
Step-by-step detail, failure modes, and the full API reference live in docs/WORKFLOW.md.
Three targets are supported — see docs/DEPLOYMENT.md for full details:
- Docker Compose — full stack locally (fastest iteration).
- kind — the same stack on a local Kubernetes cluster (
kind-deploy/deploy.sh). - GCP (live) — the public edge (FE + API) runs on Cloud Run behind Cloudflare
(
https://statusbus.byaniket.site/https://api-statusbus.byaniket.site), PostgreSQL on Neon, Redis on Upstash. The monitoring mesh runs on GCP compute: a self-managed kubeadm cluster inasia-south1-a(on-demand control plane running the producer + 2 spot workers running the India consumer) plus a standalone spot consumer VM inus-central1-afor the US vantage. Bring-up and ops:gcp-infra/k8s/README.mdand docs/RUNBOOK.md. Masthead deploys auto via Cloud Build triggersstatusbus-api-deploy/statusbus-fe-deploy. Worker images are pushed withgcloud builds submit --config cloudbuild/statusbus-workers.yaml ..
| File | Covers |
|---|---|
| docs/ARCHITECTURE.md | System design, components, data model, decisions |
| docs/WORKFLOW.md | End-to-end flows, queue contract, API reference, failure modes |
| docs/DEPLOYMENT.md | Live production + Compose + kind deployment, CI/CD, known issues |
| docs/RUNBOOK.md | Day-2 ops: health checks, node loss/recovery, image rebuild, join-token, secrets |
| docs/DEVELOPMENT-CHALLENGES.md | Challenges discovered during development & deployment, their fixes, interview review notes |
| docs/ARCHITECTURE-DECISIONS.md | Architecture decision log: spot-worker bootstrap model, second-region strategy, cross-continent k8s rationale |
- Per-website detail pages, charts, uptime analytics, and edit/delete UI are not yet built.
- The monitoring interval is a single global 60 s cadence (no per-site intervals yet).
- Time-series analytics and alerting are future work — results currently live in Postgres.
- See the "Known Issues & Future Work" appendix of docs/DEPLOYMENT.md for the full catalogue.