Business intelligence

The problem with reporting is not charts. It is trust.

Two dashboards disagree on last month's number. Nobody in the room can say which one is right. So the decision waits, and everyone goes back to the spreadsheet they keep for themselves.

We build reporting that survives that meeting. Every metric is defined once. Every number traces back to the row it came from. The refresh time is printed on the page, so nobody has to argue about whether the data is stale.

Where trust breaks

A dashboard fails quietly, then all at once.

Two definitions of one metric

Sales counts a customer at contract signature. Finance counts one at first invoice. Both dashboards are right by their own rules, so the company has two versions of last quarter and no way to reconcile them, because nobody wrote the rules down.

Numbers nobody can trace

A total looks wrong, and there is no way to open it and see the rows behind it. A number that cannot be checked will not be trusted, and a number that is not trusted gets replaced by a private spreadsheet. Quietly, one desk at a time.

Stale data with no timestamp

The page does not say when its data was refreshed. So every surprising number starts the same argument about whether it is real or just old, and the safest move is to stop looking at the dashboard entirely. People do.

The actual hard part

Agreeing on the definitions is harder than building the system.

The hard part is getting sales, finance, and operations to agree on what counts as a customer, or when an account stops being active. Each department has an answer that is correct for its own work. The disagreement only becomes visible when the numbers meet.

So we treat that argument as part of the job, not an interruption to it. We get each definition stated, tested against real rows, and signed off by the people who own it. Then it is encoded exactly once, in the database, where every report reads it. When a definition changes, it changes in one place, and the change is recorded.

If your teams cannot agree on what active means, the dashboard was never the problem. The definition is. That is where we start.

How we build it

Three commitments, and the stack behind them.

One definition

Each metric is computed in exactly one place: a view or a stored procedure in the database, not a formula copied into every report. Every chart and every export reads the same logic, so they cannot drift apart.

Traceable numbers

Every aggregate can be opened to the rows that produced it. When a total looks wrong, you drill to the source rows and settle it with evidence instead of opinions. That is what makes a number something finance will sign.

Visible freshness

Every page states when its data was last refreshed. A number without a timestamp invites an argument. A number with one ends it.

The stack

We build on SQL Server and Azure SQL. The reporting model lives in the database, in source control, and deploys from a pipeline in Azure DevOps. When the work calls for a custom front end, we build it in .NET and Blazor, the same stack as everything else we ship.

The engagement

How a reporting engagement runs.

  1. We sit with the people who use the reports today and find where trust broke: which numbers get double-checked, which get ignored, and which spreadsheet is the real system of record.
  2. We get the definitions agreed. Customer, active, booked, churned: each term gets one written definition, tested against real rows until its owners sign off.
  3. We build the model in SQL Server or Azure SQL, one view or procedure per metric, with the definition documented next to the code that computes it.
  4. We put lineage and refresh time on every page, so any number can be traced and nobody has to argue about stale data.
  5. We hand it over: the database code, the pipeline, and the board that records every decision, including the definitions and why they were chosen.

Start here

Tell us which two reports disagree.

Not a discovery call. Name the metric, name the two places it appears, and tell us how far apart they are. We will tell you honestly whether the fix is a definition, a data problem, or a rebuild.