One engine, many trades: how not to rewrite a system for every industry
Is a lead-finding system for garages and one for clinics a single system or two? Here is the line that separates the engine from the data, and what it costs when you draw that line slightly wrong.
Can a lead-finding system be built once and moved to other industries?
It can, as long as the trade is data rather than code. The engine knows how to search, reject, read for meaning and verify a quote, but nowhere does it know which trade it is working in. Everything trade-specific sits in one pack: the queries, the words, the phrases a buyer actually uses, the places they post and the thresholds. A new trade is then a new pack, not a new branch of code.
I build automation for clinics, garages, beauty salons and a few other trades. The question that comes up straight away: is that one system or eight?
The answer depends on where the line runs between what the system can do and what it knows about the trade.
The line runs along knowledge of the trade
The rule is simple: the name of a trade never appears inside the engine. Nowhere. Not in a condition, not in a function name, not in a comment.
That sounds like a detail, but it can be checked mechanically, which is why it holds. The moment “if this is a clinic, then” appears in the code, the system stops being one system. From there it forks, and every trade after that adds another fork to a place that is already hard to read.
The engine does the general work. Find pages. Throw out the obviously wrong ones by address and title, without reading the text. Check whether the needed words are present. Judge whether the text resembles someone describing a problem. Have a model read it and pull out who the person is and what they need. Check the stored quote against the source page word for word. Score it and sort it into buckets.
None of those steps needs to know the subject is garages.
What “the trade is data” means
Everything trade-specific goes into one pack. The search queries worth running at all. The words used for the fast reject. The phrases people in that trade use to describe their problem — and those differ everywhere: a garage owner and a clinic receptionist complain about the same thing in different words. The places those people post. And the cut-offs where “this looks like a lead” begins.
A pack like that can be shown to the client. It reads as text rather than as a program, and someone who works in that trade sees immediately where I guessed right and where I did not. That turns out to be unexpectedly valuable: corrections arrive from the person in the trade, not from a programmer.
After that, a new trade is not new development. It is a new pack and a run against it.
What the slightly wrong line cost me
The honest part. I did not get the line right the first time.
At first there was one kind of pack, for finding people. Then more was needed: not only finding them but writing the first message, keeping a record, handling the reply. Instead of reworking the first kind, I built a second, extended kind on top of it.
The result is two registries instead of one, two environment variables that select the active pack, and a precedence rule between them. Every new trade now has to be registered in two places. Forget the second and search works while outreach cannot see the pack, for reasons that are not obvious.
That is the standard price for adding a capability by extension rather than by replacement. It works, but explaining it takes longer than it would have if I had folded everything into a single kind of pack with optional parts.
The lesson I took: when a new capability needs the description extended, spend the day extending the one description rather than the hour building a second one beside it.
When you should not do this
Splitting engine from data is worth the effort once there is going to be more than one trade. For a single trade it is an extra layer: you end up maintaining an abstraction with exactly one implementation.
The sign that it is time is simple. You catch yourself copying a file and changing a dozen lines in it. Those dozen lines are your trade pack. Everything else is the engine.
What to take from this
Three things that do not depend on tools.
Set a rule that can be checked mechanically: the name of a trade never appears in the engine. A rule a machine can check outlives an agreement.
Keep trade knowledge in one pack that a person from that trade can read. Then the corrections come from them rather than from you.
And when a new capability needs the description extended, extend the one you have instead of putting a second one next to it. The second description then lives forever.
What this looks like in practice is in the case about finding clients with a CRM inside Telegram. The industry pages are the same idea applied to services: clinics, garages and the rest are assembled from one set of building blocks. If you need something like it for your trade, get in touch.