Skip to content

gauravpsingh07/pulseops

Repository files navigation

PulseOps

Serverless Monitoring and Incident Status Platform

PulseOps is a portfolio-grade uptime monitoring platform built with React, TypeScript, Cloudflare Workers, Cloudflare D1, Worker Cron Triggers, and Discord webhooks. It lets users create monitors, run checks manually or on a schedule, track latency, automate incidents, and publish public status pages.

Live Demo

Deployment Status

PulseOps is deployed on a free-tier Cloudflare architecture:

  • Frontend: Cloudflare Pages
  • Backend API: Cloudflare Workers
  • Database: Cloudflare D1
  • Scheduler: Cloudflare Cron Triggers
  • Alerts: Discord Webhooks
  • CI/CD: GitHub Actions

The deployed app supports user registration, login, monitor creation, manual checks, scheduled checks, incident detection, Discord outage/recovery alerts, and public status pages.

Demo Flow

  1. Register or log in.
  2. Create a website/API monitor.
  3. Run a manual check or wait for scheduled checks.
  4. View uptime, response time, check history, and incidents.
  5. Add a Discord webhook to receive outage and recovery alerts.
  6. Enable public status and open /status/:slug in an incognito browser.

1. Overview

PulseOps monitors websites and APIs from a Cloudflare Worker. Authenticated users can manage monitors, inspect uptime metrics, view recent check history, configure Discord alerts, and expose a public status page for selected services.

2. Problem

Small projects and portfolio apps often need visibility into uptime but do not need expensive infrastructure. Typical monitoring tools can be overkill, while basic cron pings do not provide incident history, alert deduplication, response-time metrics, or public status communication.

3. Solution

PulseOps provides a lightweight monitoring system on a free-tier-friendly serverless architecture:

  • Cloudflare Workers run the API and monitoring engine.
  • Cloudflare D1 stores users, monitors, checks, incidents, alert logs, and rate limits.
  • Cloudflare Cron Triggers schedule checks.
  • Discord webhooks notify teams when incidents open or resolve.
  • Cloudflare Pages can host the React dashboard and public status pages.

4. Features

  • Email/password authentication with hashed passwords and JWT sessions.
  • Monitor CRUD for website and API endpoints.
  • Heartbeat (dead-man-switch) monitors: cron jobs ping a secret URL, and a missed ping past the interval + grace window records a failure and opens incidents through the normal pipeline.
  • Manual uptime checks from the dashboard.
  • Scheduled checks through Cloudflare Cron Triggers.
  • 90-day uptime history bars backed by per-day rollups (daily_stats), shown on monitor detail and public status pages.
  • Combined status board: one public page per user showing all public monitors with an overall system banner.
  • Response-time tracking and metrics cards.
  • Recharts response-time charts.
  • Incident automation with a 3-failure outage threshold.
  • Incident deduplication and automatic recovery resolution.
  • Discord webhook alerts and alert log persistence.
  • Public status pages for selected monitors.
  • Embeddable live SVG status badges (/api/status/:slug/badge.svg) for READMEs and docs.
  • D1-backed rate limiting for auth, monitor creation, manual checks, and cron fallback.
  • CORS, security headers, Zod validation, and clean error responses.
  • GitHub Actions CI for install, lint, typecheck, tests, and build.

5. Architecture

User Browser
 -> Cloudflare Pages React App
 -> Cloudflare Worker API
 -> Cloudflare D1

Scheduled monitoring flow:

Cloudflare Cron Trigger
 -> scheduled()
 -> monitor runner
 -> checks table
 -> incident service
 -> Discord alert service

See docs/architecture.md for more detail.

6. Tech Stack

  • Frontend: Vite, React, TypeScript, Tailwind CSS, React Router, Recharts
  • Backend: Cloudflare Workers, TypeScript
  • Database: Cloudflare D1
  • Scheduler: Cloudflare Worker Cron Triggers
  • Alerts: Discord webhooks
  • Validation: Zod
  • Tests: Vitest
  • Package manager: pnpm workspaces
  • CI: GitHub Actions

7. System Design

PulseOps separates the system into a React web app and a Worker API:

  • apps/web: authenticated dashboard, monitor detail pages, and public status UI.
  • worker: API routes, auth, D1 queries, monitor runner, incident logic, alerts, rate limiting, and cron entrypoint.
  • worker/src/db/schema.sql: D1 schema.
  • .github/workflows/ci.yml: CI workflow.

The frontend uses a Vite dev proxy for local /api calls. In production, set VITE_API_BASE_URL to the deployed Worker URL if the frontend and API are on different origins.

8. Database Schema

Main D1 tables:

  • users: account records, password hashes, and the public status-board slug.
  • monitors: endpoint configuration, monitor type (http or heartbeat), heartbeat token/grace, current status, counters, public slug, and optional alert webhook.
  • checks: individual check results with status code, response time, error, and timestamp.
  • daily_stats: per-monitor per-day rollups powering the 90-day uptime bars.
  • incidents: open and resolved outage records.
  • alert_logs: Discord alert delivery attempts, skipped alerts, and failures.
  • rate_limits: D1-backed rate-limit counters.

Schema source: worker/src/db/schema.sql

Existing deployments upgrade with the incremental migration (creates daily_stats, backfills ~30 days of rollups from retained checks, and adds the board and heartbeat columns):

corepack pnpm --filter worker exec wrangler d1 execute pulseops-db --remote --file=src/db/migrations/002_features.sql

Run it once; the ALTER TABLE statements are not re-runnable.

9. API Documentation

See docs/api.md.

Route groups:

  • POST /api/auth/register
  • POST /api/auth/login
  • GET /api/auth/me
  • GET /api/monitors
  • POST /api/monitors
  • GET /api/monitors/:id
  • PATCH /api/monitors/:id
  • DELETE /api/monitors/:id
  • POST /api/monitors/:id/check
  • GET /api/monitors/:id/checks
  • GET /api/monitors/:id/metrics
  • GET /api/monitors/:id/incidents
  • GET /api/incidents
  • PATCH /api/incidents/:id/resolve
  • GET /api/status/:slug
  • GET /api/status/:slug/metrics
  • GET /api/status/:slug/incidents
  • GET /api/status/:slug/badge.svg
  • GET /api/board and POST /api/board (authenticated board slug management)
  • GET /api/board/:slug (public combined status board)
  • GET|POST /api/ping/:token (heartbeat pings)
  • POST /api/cron/check-monitors

10. Monitoring Logic

See docs/monitoring-logic.md.

Summary:

  • HTTP 2xx and 3xx responses count as success.
  • Other HTTP responses, network errors, and timeouts count as failure.
  • A successful check marks the monitor operational, resets failure_count, and increments success_count.
  • Failed checks increment failure_count.
  • Failures 1 and 2 mark the monitor degraded.
  • Failure 3 and later mark the monitor down.
  • The first down transition opens one incident.
  • Duplicate open incidents are not created.
  • Recovery resolves the open incident and can send a Discord resolution alert.
  • Heartbeat monitors invert the flow: pings record successful checks, and the scheduler records a failed check when a ping is overdue (interval + grace). A never-pinged heartbeat stays pending instead of alerting.
  • Scheduled check retention deletes checks older than 30 days, rate-limit counters older than 24 hours, and daily rollups older than 90 days.

11. Local Development

Install dependencies:

corepack enable
corepack pnpm install

Create local Worker secrets:

Copy-Item .env.example worker/.dev.vars

Edit worker/.dev.vars:

JWT_SECRET=replace-with-long-random-secret
CRON_SECRET=replace-with-long-random-secret

Apply the D1 schema locally:

corepack pnpm --filter worker exec wrangler d1 execute pulseops-db --local --file=src/db/schema.sql

Run both the Worker and web app:

corepack pnpm dev

Or run them separately:

corepack pnpm --filter worker dev -- --port 8787
corepack pnpm dev:web

Open the Vite URL, usually http://localhost:5173.

12. Cloudflare D1 Setup

Create a D1 database:

corepack pnpm --filter worker exec wrangler d1 create pulseops-db

Copy the returned database_id into worker/wrangler.toml:

[[d1_databases]]
binding = "DB"
database_name = "pulseops-db"
database_id = "YOUR_DATABASE_ID"

Apply the schema locally or remotely:

corepack pnpm --filter worker exec wrangler d1 execute pulseops-db --local --file=src/db/schema.sql
corepack pnpm --filter worker exec wrangler d1 execute pulseops-db --remote --file=src/db/schema.sql

13. Worker Deployment

Set Worker secrets:

corepack pnpm --filter worker exec wrangler secret put JWT_SECRET
corepack pnpm --filter worker exec wrangler secret put CRON_SECRET

Deploy:

corepack pnpm --filter worker deploy

14. Frontend Deployment

Deploy apps/web to Cloudflare Pages.

Recommended Pages settings:

  • Build command: corepack pnpm --filter web build
  • Build output directory: apps/web/dist
  • Root directory: repository root
  • Environment variable: VITE_API_BASE_URL=https://YOUR_WORKER_URL

If the frontend and Worker are on different origins, keep Worker CORS configured with the deployed frontend origin.

15. Cron Trigger Setup

worker/wrangler.toml includes:

[triggers]
crons = ["*/5 * * * *"]

Cloudflare invokes the Worker's scheduled() handler. For local fallback testing:

curl.exe -X POST http://localhost:8787/api/cron/check-monitors -H "x-cron-secret: YOUR_CRON_SECRET"

16. Free-Tier Notes

PulseOps is designed for a free-tier-friendly architecture:

  • Cloudflare Workers host the API without a separate Node server.
  • Cloudflare D1 stores relational data.
  • Cloudflare Pages can host the static React app.
  • Cron Triggers run scheduled checks.
  • Discord webhooks provide alerting without a paid notification provider.

Production usage should still consider Worker invocation limits, D1 read/write limits, Cron frequency, and check volume.

17. Security Notes

  • Passwords are hashed with PBKDF2-SHA256.
  • JWTs are signed with JWT_SECRET; the cron fallback secret is compared in constant time.
  • Secrets are never hardcoded.
  • Zod validates request bodies.
  • Monitor URLs are restricted to http/https, and alert webhooks are restricted to Discord webhook endpoints so the Worker never POSTs to arbitrary destinations.
  • D1-backed rate limits protect auth, monitor creation, manual checks, and cron fallback.
  • CORS allows configured frontend origin or localhost development origins.
  • Security headers include X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and restrictive Permissions-Policy.
  • Public status routes intentionally omit user IDs, webhook URLs, and private monitor fields.

18. Testing

Run the full local validation path:

corepack pnpm lint
corepack pnpm typecheck
corepack pnpm test
corepack pnpm build

Backend service tests use Vitest and mocked D1/fetch behavior. They do not require a Cloudflare account or a Discord webhook.

19. Screenshots

Login

PulseOps login page

Dashboard

PulseOps dashboard

Monitor Settings

PulseOps monitor settings

Monitor Detail - Operational

PulseOps operational monitor detail

Monitor Detail - Degraded

PulseOps degraded monitor detail

Public Status Page

PulseOps public status page

Discord Alerts

PulseOps Discord outage and recovery alerts

20. Future Improvements

  • Multi-region checks.
  • Team accounts and role-based access.
  • Email or Slack alerts.
  • Monitor tags and filtering.
  • Custom status page branding.
  • Status page custom domains.
  • More granular uptime windows.
  • Frontend component tests.
  • Cloudflare analytics integration.

About

Serverless uptime monitoring and incident status platform built with React, TypeScript, Cloudflare Workers, D1, Cron Triggers, and Discord Webhooks.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages