The Monday report is the one managers open first, and it is the one that crawls. An export for a customer, a branch comparison, a summary of last week's calls: someone starts it, waits, and then asks whether it is time to replace the CRM. A replacement quote answers a different question. The report is slow. A new product can still build that report the same way: inside the click, row by row, on a table nobody indexed, in a database shared by every branch.
This is for the owner of that product. The words that matter are the report, the person who waits, and whether one customer's data can appear on another customer's screen. Queues and indexes are how you fix those, not a reason to rewrite the platform. Time the report you already have. Then decide whether the wait belongs in a background job, in an index, or in a smaller response. A full rewrite is the last option, and only after those checks have a result.
1. Name the report people already wait on
A meeting that says "reporting is broken" and then jumps to a vendor shortlist has skipped the only fact you need. Broken does not say which report, which branch, or how long the wait is. Two reports can live in the same product and have nothing in common. One is a short list. The other joins every call, invoice and message for a month.
The person who feels it is not looking at the database. They feel a spinner, a timeout, or a spreadsheet that arrives after the stand-up is over. The proposal that follows is a new CRM, because that is a decision they know how to make. The report itself stays unnamed, so the new CRM inherits the same shape of question.
Write this on one page, next to the report:
A platform-wide claim — "the CRM is slow" — will not tell a developer which query to open. The same habit applies on a public site: name the screen before you redesign it. That pass is written up separately as what to check before a redesign.
2. Why a report crawls without the product being old
Age is a weak explanation. A young product crawls for the same reasons as an old one. The report reads the database once per row. The filtered column has no index. The response carries every field when the screen shows five.
The first version of a report is often a loop. For each customer, load their calls. For each call, load a score. It is correct, and it is slow once the rows are real. The same shape shows up outside CRMs. On one product, a query loop became a single aggregating query and that operation dropped from a bit over twelve seconds to a bit over two. The number belongs to that operation. It is not a forecast for your Monday export. What it shows is the shape of the work: one query instead of a loop, an index where search needed one, a response no larger than the screen.
Ask the person who can open the query:
3. When the report should leave the click
Some reports hold the browser open until every row is done. People retry. A retry that starts the same heavy work again makes the wait worse, and it can double a side effect if the job sends mail, writes a charge, or posts a score.
The report was built as a page because a page was the fastest way to show it once. Monthly ranges, branch roll-ups and file exports outgrow that page. The work is still correct. It no longer fits inside one request. A queue takes the run off the click, stores the result, and lets the person come back when it is ready. That is a smaller change than replacing the CRM.
Move it off the click when these are true:
On one multi-tenant CRM, call processing ran as queue jobs. A retry had to find the work already recorded and stop, so a second attempt did not create a second result. The workflow connected call handling, telephony, messaging and accounting, then exposed the outcome through reporting. Your report may not be a call score. The question is the same: if this run is attempted twice, do you get one row or two? Ask that even when the queue is a simple one you already operate.
4. Check branch and customer boundaries before you speed the report up
A faster report that shows the wrong customer's rows is a worse report. Speed makes a leak easier to notice. In a CRM or SaaS product, branches, tenants or accounts share one application and must not share one another's records.
The convenient query is "all calls this month", with the filter applied in the page. Or there is one shared database, and some queries forget the column that says whose rows these are. An index makes that query faster. It does not add the missing filter. On one product, each branch had its own database, and the migrations and indexes were designed for that separation. The index served the boundary. It was not a substitute for the boundary.
Check the boundary before you celebrate a faster export:
5. A short plan that is not a rewrite
A proposal with two lines — "reporting is slow" and "replace the CRM" — is missing the third line you can write today. Immediate: the report people wait on, timed, with a suspected cause. Next: either one aggregating query and an index, or a background run that is safe to retry, plus a written answer on how accounts stay separate. Later: a new platform, if the product still fails the decision the report is for after those changes. Inherited production systems are usually steadied before anyone treats them as disposable. The decision is what to steady.
Keep the plan small enough to finish:
When to bring in a specialist
You can name the report, time it, and click through two accounts yourself. Ask for help when the suspected cause is a query or an index and nobody inside can read it, when a retry might send a second email or a second charge, or when a replacement quote is already moving and it does not mention this report.
I do this kind of reporting work on an existing CRM or SaaS product, without starting from an empty repository. Services cover performance, SaaS and backend systems, and AI integration, including the case where a report sits on top of telephony or another system you already run. Selected work is the same class of system: a report that had to stay correct under retry, and data that had to stay inside its own account. If you want to walk through one crawling report, message me on LinkedIn with its name, who waits on it, and the seconds you wrote down.