O
OpticsOps
v1Original design

Core architecture

Four pieces moving one signal end to end: a request happens somewhere in your service, gets traced, and shows up on a dashboard. This is the shape of it.

The four pieces

Your service

npm package

The @opticsops/agent package loads into your Node.js process at startup. It patches the built-in http/https modules and undici (native fetch) so every HTTP call is observed automatically — no code changes, no framework plugin.

Ingest API

Fastify on Cloud Run

Receives traces and health-check summaries from every instrumented service, authenticates each request, and is the only component with credentials to the datastore. Also serves the dashboard.

Datastore

ClickHouse

Stores traces and call-graph data, scoped per project. Every query the ingest API runs is filtered to the calling project — one project's data is never visible from another's key.

Portal

Next.js on Vercel

Where you sign up, sign in, and manage your API key. It never talks to the datastore directly, and never sees your ClickHouse credentials — it goes through the same authenticated ingest API everything else does.

The agent and the portal never talk to each other, and neither ever holds a datastore credential — the ingest API is the only thing that does.

One request, start to finish

1

A request enters your service

The agent starts a span. If the request arrived from another instrumented service, it's linked to that service's trace via a standard W3C traceparent header — not a proprietary format.

2

Your handler calls another service

The agent starts a child span and injects the trace header into the outgoing call, so the next hop can link back to this one — automatically, however deep the call chain goes.

3

The response comes back

Fast and healthy → counted in a rolling aggregate, nothing exported. Slow or an error → the full linked trace for that request is captured and sent. This is tail-based sampling: the decision happens after the request finishes, so a failing request is never the one that got sampled out.

4

Data lands, scoped to your project

The ingest API authenticates the incoming request and writes it against your project only. Every read later — the dashboard, the API — is scoped the same way.

5

You watch it happen

The dashboard polls and streams live updates: which services exist, how they call each other, and the trace of anything that went wrong, in the order it actually happened.

Isolation model

Every project gets its own API key at signup. Every write and every read is scoped to the project that key belongs to — there's no shared view, no cross-project query path, and no way to see another project's services, traces, or call graph from your key. There's one datastore behind the whole platform, not one per customer; isolation is enforced in the application layer on every single query, not by physically separate infrastructure per project.

Curious what changed since this version? Read v2 →