Five new report pages went into an older admin area, and the first number they gave us for active paid accounts was wrong. We had counted every account whose expiry date was still in the future. That count included trials, internal test groups, and branches of the account structure that were no longer active. Any conversion or renewal figure built on it would have pointed attention at the wrong accounts. The fix was a written set of rules for what belongs in the count, and that is the work we ended up doing.

Five pages, one shape

The pages covered packages, conversions, renewals, the overlap between conversion and renewal, and the total value of sales over a customer’s time with us. That sounds like five separate jobs. We gave each one the same simple shape: a place that gathers the rows, a page that turns them into a table, and a bit of styling that keeps the table readable. Once we had that recipe, adding another report was no longer a scavenger hunt through old code. It was like using the same recipe card for five dinners and changing the main ingredient.

The consistency mattered because the admin was old. There was no shiny new reporting service sitting beside it. The reports had to live with the rest of the application, in a form someone could come back to later and understand. Each page kept its starting steps, button actions, and drawing of the page together. If we could follow one report, we could follow the next without spending half an afternoon finding where everything had been hidden.

The number that looked fine

Then we went after a number that should have been easy: how many paid accounts were active right now. Our first pass counted accounts whose expiry date was still in the future. It produced a number, and we could not trust it.

Some of those accounts were trials. Some belonged to internal test groups. Some were attached to parts of the account structure that were no longer active. Leaving any one of them in the pile would make a conversion or renewal figure wrong. People often miss this when they ask for a report. The hard work is agreeing on what belongs in the table.

The cost of that easy first answer was the time it took to spell out the real rules. It also carried a more serious cost. A wrong renewal number can put attention on the wrong accounts. We had already spent too many years learning that a report is only as honest as the small decisions underneath it.

Writing the rules down

The scary term here is SQL. It is simply a way to ask a database a very exact question. We used it to write the rules down instead of trusting ourselves to remember them later. For the renewal work, we made a separate review file and kept it beside the report code. It found accounts that had expired during a chosen period and had paid at least once before. It also found the last payment before each account expired.

That file turns a vague phrase like “lapsed paying customer” into something another person can check. The trial accounts are out. The internal test groups are out. The inactive parts of the account structure are out. The expiration window and a past payment are in. If the resulting number ever raises an eyebrow, there is a written trail back to the exact rule that produced it. We do not have to rely on memory, or reopen an old query window and hope we recreate the same answer.

Broken records from years of use

There was another wrinkle. Years of real use had left some broken records in the account structure. A few pointed to parents that did not exist. A few had priority values that should never have been there. A few were half deleted in ways the system allowed, even though ordinary use did not expect them.

A single broken record can disappear inside a normal screen. A report is less forgiving because it adds up everything. One bad row can spoil the total or stop the whole report from loading. So the report checked for the known bad shapes before adding anything together. It repaired or skipped those records rather than letting one old mistake decide whether a whole page worked.

Shipping all five together

All five pages went out together in one feature branch, which is just a separate bundle of changes that can be reviewed and merged as one. That made sense because the work added new admin pages without changing an existing customer flow. A more delicate change, one that could disrupt a live action, would deserve a smaller release that is easier to undo. The size of a release should match what can go wrong, not follow a ritual.

Which number we trusted

The first number we trusted in this project was not 3,853. It was the one that came after we wrote down the renewal rules: expired inside the chosen window, at least one payment before that, no trials, no internal test groups, no inactive branches of the account structure. Each of those exclusions changed the count, and the review file kept beside the report code is the only reason we can say by how much. The earlier figure, accounts whose expiry date was still in the future, looked fine right up until we asked what was in it.

So before you act on a conversion or renewal figure, ask to see the written rules behind it. Ask which accounts are excluded (trials, internal test groups, inactive branches) and what must be present (an expiry in the window, a prior payment).