Skip to content

nutritious33/ApiMonitor

Repository files navigation

ApiMonitor

Monitors the availability and latency of HTTPS endpoints. A Spring Boot backend polls each active endpoint on a configurable interval; a React SPA displays live status cards and refreshes every 10 seconds.

Features

  • Status cards showing current status (UP/DOWN), latency, uptime percentage, and last-checked time
  • Latency leaderboard of the three fastest active endpoints
  • Public watchlist management — any visitor can activate or deactivate catalog endpoints without logging in
  • Admin custom endpoint tracking — add arbitrary HTTPS URLs via the UI
  • Public submission queue — visitors suggest endpoints; admins approve or deny from the dashboard
  • Drag-and-drop card ordering, persisted to localStorage
  • Optional email notification when a new public submission arrives
  • Single-container deployment via multi-stage Docker build

Stack

Layer Technology
Backend Java 21, Spring Boot 3.5, Spring Data JPA
Database (dev) H2 (in-memory)
Database (prod) PostgreSQL 16
Migrations Flyway
Frontend React 18, TypeScript, Vite 5, Tailwind CSS
Data fetching @tanstack/react-query v5
Drag-and-drop @dnd-kit/sortable
HTTP client axios
Container Docker (multi-stage), Docker Compose
CI GitHub Actions

Auth model

The lock icon in the top-right corner of the dashboard opens the admin login modal. Submitting the correct API key calls POST /api/auth/ping; the server validates it and sets an httpOnly admin_session cookie with an 8-hour sliding window. On subsequent page loads the frontend calls /api/auth/status to restore admin mode silently. Clicking "Sign out" invalidates the session server-side immediately.

Everything else is public: viewing the dashboard, activating and deactivating catalog endpoints, clearing the watchlist, and submitting endpoint suggestions. This is intentional for a shared dashboard. If you want watchlist operations to be gated, add an authenticated() rule to the relevant routes in SecurityConfig.java.

Security notes

All URLs submitted for monitoring are validated before the first health check: HTTPS is required, the hostname is checked against private and loopback ranges, and DNS resolution is performed with the resolved IPs re-checked at connection time to close the DNS-rebinding window. The backend applies a rate limit of 120 requests per minute per IP; requests over the limit get a 429. If the app is behind a Cloudflare Tunnel, set RATE_LIMIT_TRUST_PROXY=true so the real client IP is read from the CF-Connecting-IP header. The client-side login lockout (10 failures in 10 minutes triggers a 1-hour lockout stored in localStorage) is UX friction only; a determined attacker can bypass it by clearing storage, so the server-side rate limit is the actual control.

Running locally

Docker Compose

cp .env.example .env
# Set SECRET_SECURITY_KEY and DB_PASSWORD in .env
docker compose up --build

The app is at http://localhost:8080. The default admin key is whatever you set for SECRET_SECURITY_KEY. The cloudflared service in the Compose file will fail on startup if TUNNEL_TOKEN is blank, but the rest of the stack runs fine.

Hot reload (optional)

The dev Spring profile uses H2 in-memory.

# Terminal 1
cd backend
mvn spring-boot:run -Dspring-boot.run.profiles=dev

# Terminal 2
cd frontend
npm install
npm run dev

Frontend dev server is at http://localhost:5173 and proxies /api to :8080. The admin key in dev mode is dev-api-key (hardcoded in application-dev.properties).

Configuration

All variables are read from .env by Docker Compose or passed directly as container environment variables.

Variable Default Notes
SECRET_SECURITY_KEY dev-api-key Admin API key. Required in production.
DB_PASSWORD changeme PostgreSQL password. Required in production.
DB_USERNAME apimonitor PostgreSQL username.
CORS_ALLOWED_ORIGINS http://localhost:8080 Comma-separated list of allowed origins.
TUNNEL_TOKEN (empty) Cloudflare Tunnel token. Leave blank to skip the cloudflared container.
MONITOR_CHECK_INTERVAL_MS 60000 Poll interval in milliseconds.
MAIL_HOST (empty) SMTP hostname. Leave blank to disable email notifications.
MAIL_PORT 587 SMTP port.
MAIL_USERNAME (empty) SMTP username.
MAIL_PASSWORD (empty) SMTP password.
MAIL_TO (empty) Address that receives new-submission alerts.

The three variables that actually matter in production are SECRET_SECURITY_KEY, DB_PASSWORD, and CORS_ALLOWED_ORIGINS. The rest can stay at their defaults.

API reference

All paths are relative to the server root. "Admin" means the request must include an X-API-Key header on first login, or the admin_session cookie set after a successful login.

Health metrics

Method Path Auth Description
GET /api/health-metrics Public List all endpoint metrics
POST /api/health-metrics/activate/{id} Public Activate a catalog endpoint
POST /api/health-metrics/deactivate/{id} Public Deactivate a catalog endpoint
POST /api/health-metrics/deactivate/all Public Deactivate all active endpoints

Custom endpoints

Method Path Auth Description
POST /api/custom-endpoints Admin Add a custom HTTPS endpoint
DELETE /api/custom-endpoints/{id} Admin Remove a custom endpoint

Submissions

Method Path Auth Description
POST /api/submissions Public Submit an endpoint suggestion
GET /api/submissions/{token} Public Poll submission status by UUID token
GET /api/submissions Admin List pending submissions
POST /api/submissions/{id}/approve Admin Approve a submission
POST /api/submissions/{id}/deny Admin Deny a submission

Auth

Method Path Auth Description
POST /api/auth/ping Key header Validate key; sets session cookie on 204, returns 401 on failure
GET /api/auth/status Public Returns {"admin": true} if a valid session cookie is present
POST /api/auth/logout Public Invalidates the session and clears the cookie

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages