We Walked Our Own CRM Page by Page. It Was Lying to Us.
Disclosure up front: the product in this post is ours. It's ClientForge, the CRM inside EternalEngineOS, the software our one-person company is building. That matters because this isn't a review — it's an audit we ran on
Disclosure up front: the product in this post is ours. It's ClientForge, the CRM inside EternalEngineOS, the software our one-person company is building. That matters because this isn't a review — it's an audit we ran on ourselves, and a lot of what we found was embarrassing.
The audit method was boring on purpose. No test scripts, no analytics dashboards, no "QA pass" from the people who wrote the code. One person opened the live product the way a stranger would, created a small cast of realistic clients, deals, and tasks, and worked every page to the end of its job: 19 pages, 385 individual points of contact — every button, link, field, tab, and dialog — each one marked works, broken, dead, or untested. Then the cast was deleted, and we checked what the product said about itself with zero records in it.
That last step is where it got interesting.
The dashboard lied with a straight face
Our dashboard had an "AI vs Team" comparison widget showing won value of $112.50. The true won value, from the deals sitting right there in the pipeline, was $6,250.
The bug was a classic: a cents-versus-dollars error, a 100× factor, in exactly one aggregation path. Pipeline said $18,300. Weighted pipeline said $14,850. Deals, dashboard, and reports each computed "the same number" through different code, and two of the three disagreed — in one case by two orders of magnitude. One of the figures also kept counting a deal we had deleted.
Worse: after we deleted the entire test cast — every contact, every deal, every task — the ghost figures persisted. A brand-new user with zero records would open the dashboard and see analytics for a business that doesn't exist. Some of that was caching. Some was default state baked into empty-state rendering. Either way, "empty" is a state your product will be in for every single new user, and we had never once looked at it.
A related find: the dashboard's default date range, "Last 30 Days," zeroed out all analytics. Switch to "All Time" and every number was exactly right. Our newest users were landing on the broken view by default, because defaults are the product for anyone who hasn't learned to change them yet.
Dead buttons are worse than missing features
Two controls simply did nothing:
- Create Task — click, nothing. No error, no toast, no network request worth the name. The single most common action in a CRM, silently dead.
- Delete on lead forms — dead on every form we tried, while other delete paths in the app worked fine.
A missing feature is a roadmap item. A dead button is a broken promise at the exact moment of intent, and it's worse than an error message because the user blames themselves first. They click again. They refresh. They wonder what they did wrong. Nothing in our automated tests caught either one, because the components rendered fine and the handlers existed — they just didn't survive contact with the real page composition.
Small lies compound
Individually minor, collectively corrosive:
- Deal close dates rendered one day early — a timezone boundary bug that only shows up if you compare the stored value against the displayed one.
- A task due date entered as 9:00 AM was stored as 2:00 PM.
- The app carried two different stage-probability tables (10/30/50/75 in one place, 50/65/80/95 in another), so two screens produced two different weighted forecasts from identical data. Neither was "wrong" in isolation. Together they made every forecast suspect.
- Owners rendered as raw UUIDs instead of names.
- Dropdown options were stored concatenated — "EmailPhoneText" as a single value.
- Creating a new contract from a won deal opened a blank form instead of carrying the deal's data across.
- Outbound email failed silently because an email profile setting was unset; the UI reported nothing. The seam between two of our own modules failed in total silence.
- The public lead form counted submissions and created no lead. The counter went up. Nothing arrived.
None of these would trend on a status page. All of them teach users, one small moment at a time, not to trust the numbers the product shows them. For a CRM — a product whose entire job is being the place you trust your numbers — that's the fatal category.
What was actually fine
The audit wasn't a demolition. The core record-keeping worked end to end: contacts, deals, pipeline stages. Convert-to-Client, which had been on our worry list, worked. A contract-duplication bug we'd seen in an earlier pass was gone — someone had fixed it properly, and the re-walk proved it instead of assuming it. By the end of the walk the dashboard settled at the true figures: $18,300 pipeline, $14,850 weighted. The bones are honest. Several of the surfaces were not.
Final tally: 78 open findings, 10 closed, across critical, major, and minor. The fix list is ordered worst-first, and the money-truth items — the won-value computation, the ghost figures, the probability tables — are at the top, ahead of every cosmetic issue, because a pretty CRM that misstates money is worse than an ugly one that doesn't.
Lessons we'd hand to any builder
- Walk your own product on a schedule, as a stranger. Not a demo, not a script. Create realistic data, do real jobs, then delete everything and look at what's left.
- Zero records is a test case. Empty states are where ghost data, bad defaults, and baked-in sample numbers hide.
- One number, one computation. If two screens can produce the same figure through different code paths, they eventually will produce different figures.
- Test the click, not the render. Dead buttons pass component tests. Only walking the page catches them.
- Silent seams fail silently. When two modules hand work to each other, the handoff needs a visible failure mode, or it has an invisible one.
- Defaults are the product. Whatever your default range, sort, and view is, that's what most users think your product is.
We're a one-person company, and this audit hurt in the useful way. The CRM is a capable contact-and-deal tracker. It is not yet a money-truth product — and now we know exactly which 78 things stand between here and there, in order.
If you've walked your own product like this, I'd genuinely like to hear what it was hiding from you.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.