Dashboards from JSON schemas: replacing spreadsheet reports
Before KitchenSync, I worked on the casino team at LeoVegas, one of Europe's largest online casinos. It's a heavily regulated business with a high-frequency release cycle: features ship constantly, and every change has to hold up.
Most of my work there was React and GraphQL features. But one project was internal: helping product managers stop building their reports by hand.
The problem
Product managers needed numbers to make decisions, and a lot of that reporting was manual: pulling data, pasting it into spreadsheets, formatting it, and doing it again next week. It was slow and easy to get wrong, and every new report meant more manual work.
The solution had to read from PostgreSQL, MySQL and MongoDB, so data access had to be pluggable.
The approach: describe the dashboard, don't code it
I built two pieces:
- A Node.js microservice that runs the queries and returns the data.
- A dashboard framework driven by JSON schemas. A dashboard is described as data: which data source to use, which query, and how to show the result. The framework reads the schema and renders it.
The database side used plug-and-play connectors. Each connector knows how to talk to one kind of database (PostgreSQL, MySQL or MongoDB) behind the same interface. A dashboard schema just says which connector to use.
Why schemas
Describing dashboards as JSON instead of writing a React component for each one had real advantages:
- New dashboards without new UI code. Adding a report meant writing a schema, not building a page.
- Consistency. Every dashboard looks and behaves the same way, because the same code renders all of them.
- Validation. A schema can be checked before it's used: required fields, known connector, valid chart type. Mistakes show up early.
- Separation. Data access lives in the connectors, presentation lives in the framework. Adding a new database means adding a connector, not touching every dashboard.
The limits
Schema-driven UIs are not free, and it's worth being honest about where they stop working:
- They only express what the schema allows. The first time someone needs a view the schema can't describe, you either extend the schema or write custom code. Extend it too often and your "simple JSON" turns into a programming language nobody enjoys.
- Someone still has to write the queries. The framework removes the UI work, not the need to understand the data.
- Performance is the connector's job. A dashboard is only as fast as the query behind it, and a generic layer makes it easy to forget that.
The trick is to keep the schema small and focused on the common cases, and to accept that a few special reports will always be custom.
What I took from it
This project taught me a pattern I've used many times since: when the same kind of thing keeps being built by hand, turn its description into data and write one engine that handles it. I used the same idea years later at KitchenSync, where per-customer accounting rules became configuration instead of code. I wrote about that in Rules as data: onboarding customers without shipping code.
The pattern works best with the same caveat every time: treat the configuration seriously. Validate it, version it, and don't let it grow into a language of its own.