The observability dashboard for the Smart Router — every value on screen maps to a real Prometheus series or renders an honest empty state. No invented numbers, ever.
Quick Start · How it works · Pages · Authentication · Development · Releases · License · Contributing · Security
- Live metrics, honestly sourced - KPIs, RPS, latency and error breakdowns straight from the router's
smartrouter_*/rpc_endpoint_*Prometheus families, and the per-request error and transaction logs from its own log lines (Loki). Metric families the router hasn't emitted yet render the design's own empty states and light up automatically when they appear. - Topology-aware — one values file drives both the router and the dashboard, so the Upstreams page always reflects the running configuration.
- Live test console — fire requests at any chain × interface the router serves, straight from the browser, with a full method catalog generated from the lava-specs repo (238 chains, jsonrpc/rest/tendermint/grpc, archive/debug/trace tiers).
- Self-contained —
make upgives you router + Prometheus + api + web from nothing. No accounts, no cloud, optional auth. - Optional authentication —
AUTH_MODE=enabledadds Auth.js sign-in (email+password + Google/GitHub) backed by Postgres. Default is open (disabled) for private deployments.
Repo layout: a pnpm/TypeScript monorepo —
apps/api(Fastify 5 Prometheus proxy) +apps/web(Next.js 16) +packages/shared+packages/db. Everything runs from the repo root.
make up # router + Prometheus + api (:8000) + web (:3000) + logs (Grafana :3001), detached
make up-cache # ...plus the smart-router cache sidecar (:20100, metrics :5555)
make ps # show what's running
make down # stop everythingUI → http://localhost:3000 · API → http://localhost:8000 · Prometheus → http://localhost:9090 · router → http://localhost:3360-3367 (ETH1 · SOLANA · BTC · HYPERLIQUID · COSMOSHUB rest/tendermint/grpc · APT1)
The router pulls the published image (ghcr.io/magma-devs/smart-router:latest) and loads chain specs straight from the lava-specs GitHub repo — no checkout, no volume mounts. The default config is multichain with cross-validation policies enabled; see dev-config/values.yml.
With a router already running on the host's :7779:
docker compose up --build # dashboard + Prometheus onlyThe stack can run the smart-router's RAM relay cache sidecar (mirrors
smart-router/docker/docker-compose.cache.yml). It's opt-in behind the cache
profile and off by default:
make up-cache
# or: SR_CACHE_BE=cache:20100 docker compose --profile router --profile cache up --buildmake up-cache wires the router to the cache via the --cache-be flag
(SR_CACHE_BE=cache:20100) — no values.yml edit needed. The cache listens on
:20100 and exposes its own Prometheus metrics on :5555 (scraped as the
smart-router-cache job). With the profile off, SR_CACHE_BE is empty and the
router uses its in-process cache.
┌─────────────────┐ ┌──────────────────────┐ ┌──────────────┐
│ apps/web │ REST │ apps/api │ PromQL │ Prometheus │
│ Next.js 16 │───────▶│ Fastify 5 (:8000) │───────▶│ (:9090) │
│ (:3000) │ │ stateless proxy — │ └──────┬───────┘
│ │ │ every endpoint maps │ │ scrape
│ SWR-style │ │ to real PromQL │ ┌──────┴───────┐
│ hooks + charts │ └──────────┬───────────┘ │ Smart Router │
└─────────────────┘ │ reads │ (:7779) │
▼ └──────────────┘
mounted values.yml
(same file drives the router)
- The api is a stateless Prometheus proxy — no database on the metrics path, per-route caching, unbacked values returned as
null(never invented). - The web is runtime-configurable — one published image points at any api host via
DASHBOARD_API_URL. AUTH_MODE=enabledadds a Postgres users store + HS256 JWT gate on/api/*— see Authentication.
Long windows read the raw router metrics unless the store evaluates the
twelve recording rules in docs/RECORDING-RULES.md;
with them, windows of three hours and up read a few hundred recorded series
instead of every raw histogram bucket, within a fraction of a percent of the
same numbers, provided the routers are scraped every 15 seconds, which the
api checks. Without them everything works, only slower on long windows.
GET /api/metrics/reads reports which case a deployment is in.
- Overview — KPI strip (requests, RPS, errors, success rate, latency) + chart grid, all live
- Upstreams - the mounted config joined with live per-endpoint stats, carved three ways: by chain (who serves it - the default), by router (the endpoints each router publishes), or by upstream (what it serves)
- Metrics - four tabs: Overview, Upstreams, Errors, Transactions. The Transactions tab and the Errors tab's request list read the router's logs from Loki (
LOKI_URL; thelogsprofile runs one) - Live test — POST straight to the router's listen ports from the browser; full per-chain method catalog with archive/debug/trace tiers
- /standalone — the Metrics page without the shell, for sharing or embedding
Two modes via AUTH_MODE (full guide: docs/AUTH.md):
disabled(default) — no login, no database. The dashboard opens straight on Overview. For private/self-hosted deployments.enabled— Auth.js v5 sign-in backed by Postgres (Drizzle), bcrypt credentials + optional Google/GitHub (each button appears only when its client id/secret pair is set), HS256 JWT shared between web and api. The first admin is created at/setupwith the installer's setup token; everyone after that is invited.
AUTH_SECRET=$(openssl rand -base64 32) make up-auth
# open :3000 — a fresh install redirects to /setup
# setup token: the SETUP_TOKEN you set, or: docker compose logs api | grep -iE 'setup_?token'
# (make dev-auth seeds a development admin instead — see docs/AUTH.md)With INCIDENTS_ENABLED=true on both containers, the top bar carries a
Report incident button. A report (Critical / High / Medium / Low) goes to the
deployment's own inbound webhook in Magma's on-call system, which decides who
hears about it: Critical calls the on-call engineer. Off by default. Full guide:
docs/INCIDENTS.md.
make dev # hot-reload docker stack (api tsx watch · web next dev · shared tsc --watch)
# or on the host (Node 24 + pnpm 10, needs a Prometheus at PROMETHEUS_URL):
cp .env.example .env # optional — every var has a compose default
pnpm install
pnpm --filter @sr/shared build && pnpm --filter @sr/db build
pnpm dev # api :8000, web :3000
pnpm -r typecheck && pnpm -r testThe repo pins Node via .nvmrc (nvm use) and ships an
.env.example documenting every runtime knob — copy it to
.env for host dev, or read it as the reference for self-hosting one published
image against your own router.
Project structure:
apps/
api/ Fastify 5 REST api — Prometheus proxy + optional auth
web/ Next.js 16 App Router frontend
packages/
shared/ Domain types, PromQL builders, constants
db/ Drizzle schema + Postgres client (AUTH_MODE=enabled only)
dev-config/ values.yml driving both router and dashboard
docs/ AUTH.md · METRICS-MAPPING.md
docker-compose.yml / docker-compose.dev.yml / Makefile
See CLAUDE.md for the endpoint reference, env vars, and gotchas.
pnpm lint # eslint (flat config) across the whole monorepo
pnpm -r typecheck # strict TS across every package
pnpm -r test # vitest — api routes, PromQL builders, config parser, auth, chain catalog
pnpm format # prettier --write (format:check to verify only)Every push and PR to main runs the Quality Gate:
lint + typecheck + the full vitest suite, plus a spec drift check that
regenerates the chain map, the Try-it method catalog and the runnable-defaults
roll-call from the live lava-specs
repo and fails if any committed copy is stale. When it changes, the gate says
what moved and why — a base spec such as ETH1 changing is reported as one cause,
not as forty importers — and the fix is a runbook keyed on that output:
.claude/skills/chain-resync/SKILL.md
(/chain-resync in Claude Code), with the reasoning in
.claude/rules/chain-resync.md. Renovate-style dependency bumps arrive via
Dependabot (npm + GitHub Actions, weekly).
When NODE_ENV isn't production, the api also serves an interactive
OpenAPI 3.1 explorer at /docs (raw spec at
/docs/json) covering every api route — see CLAUDE.md for the
full endpoint reference.
Changes are tracked in CHANGELOG.md. Versioning is driven by the root VERSION file: pushes to main run the
Build and Push Images workflow, which tags and publishes
ghcr.io/magma-devs/smart-router-dashboard/backend— the Fastify api (apps/api)ghcr.io/magma-devs/smart-router-dashboard/frontend— the Next.js web (apps/web)
Both images are published for linux/amd64 and linux/arm64 from a single build stage (no emulation; see CLAUDE.md → Docker / images / isolation). A release's tags appear only once its arm64 images have booted in CI, and latest is always the highest released version.
Set DASHBOARD_API_URL on the web container at runtime to point one published image at any api host.
docker pull ghcr.io/magma-devs/smart-router-dashboard/backend:latest
docker pull ghcr.io/magma-devs/smart-router-dashboard/frontend:latestSee SECURITY.md. Do not open public issues for vulnerabilities — email security@magmadevs.com.
Dual-licensed: noncommercial use is free under the PolyForm Noncommercial License 1.0.0; commercial use requires a separate Magma Devs Enterprise License — contact sales@magmadevs.com.
- Issues — bugs and feature requests
- Smart Router — the router this dashboard observes