[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. 🫖 Status page with uptime monitoring & API monitoring as code 🫖 openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
openstatus apps dashboard
2 folders · 20 files

README.md

OpenStatus Dashboard #

Manual Setup #

Requirements #

  • Node.js >= 20.0.0 — runtime
  • pnpm >= 8 — monorepo package manager (see root package.json for pinned version)
  • Deno — runs the db env/migrate/seed scripts in packages/db
  • Bun — optional, used by the utility scripts in src/scripts
  • Turso CLI — starts the local libSQL server via pnpm --filter '@openstatus/db' dev

Environment #

Two .env files are involved:

  • apps/dashboard/.env — copy manually now (this step)
  • packages/db/.env — copied automatically by pnpm dx in step 3 below
cp apps/dashboard/.env.example apps/dashboard/.env

The defaults in .env.example are dummy values that work for local dev — no real API keys needed. Fill them in before deployment to enable optional functionality (Resend for real magic-link emails, Stripe, Tinybird analytics, Sentry, GitHub/Google OAuth, etc.). Magic-link login works everywhere; in dev the link is printed to the terminal instead of emailed.

Startup #

  1. Install dependencies
pnpm install
  1. Start the libSQL server (keep this terminal running)
pnpm --filter '@openstatus/db' dev
  1. In a second terminal, set up the dev database
pnpm -w dx

This chains three turbo tasks (env → migrate → seed):

  • env copies packages/db/.env.example → packages/db/.env
  • migrate runs Drizzle migrations against the libSQL server
  • seed inserts a default workspace, user (ping@openstatus.dev), monitors, and a status page
  1. Stop the terminal from step 2

pnpm -w dev:dashboard starts its own libSQL on port 8080 — leaving the step-2 server running causes a port conflict.

  1. Start the dashboard from the repo root
pnpm -w dev:dashboard

Turbo runs the dashboard (apps/dashboard) and @openstatus/db together.

  1. Open http://localhost:3001

Logging in #

The dashboard uses NextAuth with GitHub, Google, SSO and a Resend magic-link provider.

In NODE_ENV=development, src/lib/auth/providers.ts prints the magic link to the dashboard's terminal stdout instead of emailing it; the dummy RESEND_API_KEY from .env.example is enough and no OAuth credentials are required. Everywhere else the link is emailed through Resend. A self-hosted deployment (SELF_HOST=true) whose Resend send fails still tells the user to check their inbox but prints the link to the server log instead, so look there when running without a real key.

To log in:

  1. Open http://localhost:3001/login
  2. Enter ping@openstatus.dev (the seeded user, bound to workspace 1) in the magic-link form
  3. Watch the dashboard terminal — the magic link is logged there. Open it in your browser.

Troubleshooting #

  • Port 8080 already in use — a leftover libSQL server from step 2. Kill that terminal and re-run pnpm -w dev:dashboard.
  • Magic link doesn't arrive — it isn't emailed in dev. Look in the dashboard terminal stdout for >>> Magic Link: ....
  • Reset the dev DB — stop the libSQL server, delete openstatus-dev.db at the repo root, restart libSQL, re-run pnpm -w dx.
  • No Turso CLI or Deno on the machine (a cloud sandbox) — node scripts/dev-stack.mjs up does steps 2 to 5 with sqld and deno fetched from npm; down stops them. Its database is .screenshots/stack/openstatus-dev.db: up --reseed resets the fixtures, or delete the directory while the stack is down.

The dashboard's tRPC API runs on its own Next.js edge routes, so basic CRUD works without the other apps. You may also want to run:

  • apps/server (Hono) — for API-key features and operations that go through the public HTTP API
  • apps/checker (Go) — actually executes scheduled monitor checks; without it, monitors are listed but never probed
  • Tinybird — uptime / latency time-series graphs; without it, those charts stay empty