← Back to all notes

Meridian — how it came to be

Published:

A self-hosted analytics tool for product development — born from the pain of scraping answers like "are we shipping the right thing?" together from five different tools.

Why at all

Anyone steering product development knows the game: a question like "are we shipping the right thing, at reasonable quality, without technical debt running away?" — and to answer it you click through the issue tracker, the git history and a code-quality tool and assemble the numbers in your head. Every week again.

I wanted a dashboard that answers these questions without keeping five tabs open. And because the data is sensitive, it should run self-hosted — inside the team's network, not in some cloud.

How it came to be

Meridian grew in clear phases, each with its own architecture decisions. First the foundation — persistence and tenant isolation — then upwards:

  • Authentication with JWT and OIDC, so you can sign in with your company login.
  • A setup wizard that walks a fresh instance through first-time configuration.
  • A module system that unlocks individual analyses via licensing.
  • A connector framework that taps Jira, GitHub and a code-quality scanner.
  • An async sync worker that collects the data on a schedule.
  • A KPI engine with a Redis cache that turns raw data into the actual metrics.
  • Internationalization and, finally, the frontend with five dashboards.

There's a second, smaller project attached: the remote service in Python/FastAPI. It runs on my side and handles two things — license validation for the modules and anonymous industry benchmarks: core instances send aggregated, pseudonymized metrics, and a comparison value only comes back above a minimum group size. That way a team sees where it stands relative to others without anyone becoming identifiable.

What went well

  • The split into "core runs at the customer, remote service runs on my side" kept the privacy story clean from the start.
  • The connector framework as an abstraction: adding a new source system now means writing a connector — not touching half the system.
  • A grace period: if the remote service goes down, the licensed modules keep running for a while. No hard stop over a network blip.

What didn't go so well

  • Two stacks in parallel — Java/Spring on one side, Python/FastAPI on the other — is powerful, but you do maintain two worlds.
  • Getting the KPI formulas actually right is surprisingly tricky: what exactly is "lead time", what counts as "done"? There's more definition work in there than code.
  • Anonymity in the benchmarks isn't a checkbox but diligence — minimum group size, pseudonymization, no clear names. Better too cautious than once too loose.