signoz-open-dashboard

Design rationale

Built to be safe in front of strangers

The product and technical design document is the single source of truth for this project. This page is a rendering of its decisions: goals, data flow, the read-only posture, key handling, the theme plugin architecture and the acceptance approach.

Goals

What the product must do

One-line embed

Any third-party site can embed a read-only dashboard with a single iframe URL. Callers assemble the URL; no admin UI is needed.

Console-level fidelity

Under the same dashboard id, time range and variables, chart type, data, tooltip, legend and formatting match the SigNoz console.

URL-driven view

Time, theme, color mode, locale, refresh, variables and chrome toggles all come from query params and sync back to the URL.

Graceful failure

Wrong key, wrong id and dead backend produce distinguishable empty states with Retry and a request id instead of a blank page or stack trace.

Key flexibility

A URL key wins over an env default; a missing key renders a friendly 401 state. Keys never touch localStorage, cookies or logs in plaintext.

Observable runtime

/healthz and /metrics plus JSON logs that carry only the key source and an 8-char hash.

Non-goals

What is explicitly out of scope

  • No user system, SSO or RBAC, and no key issuance or rotation. Key risk stays with the owner.
  • No dynamic switching across multiple SigNoz backends: the single upstream is fixed by SIGNOZ_BASE_URL, which prevents SSRF.
  • No domain allowlist. The embed is fully public: anyone holding the link can view.
  • No dashboard editing, creation, deletion, locking or alert management.
  • No dashboard list, playlists or snapshot export.

Phase 1 chrome decision: hide alerts, hide the lock switch and show annotations read-only.

Read-only

Default deny, enforced at the proxy

Read-only is not a UI state; it is an allowlist in the backend. The frontend implements no editing entries, and the proxy forwards only dashboard reads, the v3/v4/v5 query_range family, substitute_vars and the two variable-candidate endpoints. Everything else under /api/* returns 403, including every write interface.

This split matters because the embed is public. A hidden button is still one request away; a blocked route is not.

Key handling

Effective key, memory only

The effective key resolves as x-embed-api-key ?? URL apiKey ?? env.SIGNOZ_API_KEY. The browser keeps the URL key in memory only; it is never written to localStorage, a cookie or serialized back into the URL unless the caller put it there.

Logs and documents may only contain the key source and the first 8 characters of a hash. Query strings are redacted before serialization, so plaintext keys cannot land in logs, bug reports or commits.

Frontend

Core plus a theme plugin architecture

The frontend is split into core/ (stable: routing, auth context, data fetching, time and variables, replaceState, empty-state mapping), signoz/ (query semantics), and themes/<name>/.

A theme implements four components: Tokens, Toolbar, WidgetCard and ErrorState. The shadcn theme (default) uses Tailwind and Recharts; the legacy theme uses antd and ECharts. Unknown theme values fall back to shadcn in one registry lookup.

The rule that keeps this honest: a new theme adds a folder and one registry line, and never touches core. Theme branches inside core are treated as bugs and refactored back to the contract.

Process

Docs first, then code

Any design change (URL params, proxy matrix, trim list, env vars, error codes, deployment shape) updates the design document before the code, and a code change without the document update is invalid. Pitfalls found while developing or debugging are appended as rows to a single bug-track file with fixed columns.

This is deliberately boring: it keeps one source of truth, one TODO list and one pitfall log, so both humans and agents can audit why a decision exists.

Compatibility

Pin the API surface, do not copy the vendor

SigNoz v0.97.0 query semantics are the target. The proxy passes through the v3/v4/v5 query_range APIs and variable endpoints without validating unknown fields, so upstream payloads evolve safely.

The earlier route of copying the SigNoz frontend verbatim was abandoned: the dependency closure and provider-chain cost were too high and it conflicted with the theme extension goal. The vendor snapshot is read-only comparison material only, never built and never copied into the runtime.

Acceptance

Fixed smoke dashboards and a matrix

Four dashboards on the test backend anchor the acceptance runs: a System Overview smoke dashboard, a Kubernetes dashboard with QUERY variables, tables and clickhouse panels, a Postgres dashboard with DYNAMIC variables, and an Elasticsearch dashboard with formulas.

The matrix covers: no key with env default, wrong key, wrong id, full params and replaceState, upstream outage with self-healing retry, iframe-resizer wired or not, Chrome 108, read-only enforcement, health and metrics without plaintext keys, dozens of panels, and unknown theme fallback.

Timeline

Milestones

M1

Proxy foundation

Done

Monorepo skeleton, NestJS /api/signoz/* passthrough, /healthz and /metrics, curl proxy matrix green against a real v0.97.0 backend.

M5

Embed app redo

Done

core/ routing, auth, fetching, time and variables, replaceState and empty-state mapping; signoz/ query semantics; legacy theme; theme registry fallback.

M7

TanStack Query v5

Done

SWR updates, request dedup, placeholder-driven no-flash loading, exponential-backoff retry and focus/reconnect suppression.

M8

shadcn theme

In progress

Default theme with Tailwind and Recharts, implementing the same ThemeModule contract as legacy. Visual polish is ongoing.

M9

Distribution and docs site

Done

GitHub Actions image publish to Docker Hub plus this vinext + Magic UI website with intro, docs and design routes.

Risks

Known risks and mitigations

Full-permission keys plus public iframes invite abuse.

Documented warnings, 120 req/min/IP throttle, refresh floor of 10s, and a recommendation to use read-only short-lived keys.

Theme sprawl: themes leaking branches into core.

A new theme only adds themes/<name>/ plus one registry line. When theme conditionals appear in core, they are refactored back to the contract.

iframe-resizer height jitter under StrictMode and overlays.

lowestElement strategy plus debounce, with internal scroll as the degraded fallback.

Marketing site toolchain breaking the shipped image.

website/ is an isolated pnpm project with its own lockfile; the Docker image and root build never include it.