We launched a shop selling technical products: valves, actuators, sensors, thermostats, automation controllers.
After it went live, most incoming questions were not about price. The most repeated one was:
“My model is discontinued. What can I fit instead?”
A search box cannot answer that. The customer is not searching for a product; they are looking for an equivalent.
Why it is hard
“Equivalent” is not one thing. For one valve to replace another, several things must hold simultaneously:
| attribute | kind | why |
|---|---|---|
| Nominal diameter | mandatory | physical — if it does not match it does not fit |
| Connection type | mandatory | threaded or flanged; otherwise an adapter is needed |
| Pressure class | mandatory | insufficient rating means unusable |
| Control signal | mandatory | 0–10 V and 3-point are not the same thing |
| Supply voltage | mandatory | 24 V and 230 V cannot be confused |
| Capacity (Kvs) | tolerance | should be close, need not be identical |
| Body material | preference | flexible in most applications |
So the engine runs two kinds of logic: mandatory attributes eliminate, tolerant attributes rank. That is the same hard/soft filter split I built into catalogue search — and it works for the same reason.
And the feature shipped switched off
The engine worked. I still put it on the site disabled, behind a single switch.
Whoever sees this recommendation will buy the product and install it in a system. A wrong recommendation is a completely different thing from a wrong search result: lost money, delayed work and a safety risk.
The correctness of a feature like this cannot be measured by “I tested it, it works”. Someone with domain expertise has to verify it against a sample. Until that verification is done, the feature stays off.
The code being ready does not mean the feature is ready.
Keeping the switch in one place was deliberate too: if something goes wrong it can be turned off with a single setting, without waiting for a deployment.
The product feed: two silent faults
The shop’s products go to a shopping platform through a feed file. The first scan produced two problems.
1. An empty identifier tag
For products with no barcode, the tag was emitted but empty.
<g:gtin></g:gtin> ← validator: "invalid value"
(tag absent entirely) ← validator: "optional field missing" — fine
An empty tag is worse than an absent one. If there is no value, do not write the field.
2. Products with no price
Products with no price defined and no stock were also entering the feed. The platform rejects them, and the account’s error rate climbs.
A filter was added: a product without a price does not enter the feed. A simple rule, but before it nobody noticed — because rejected products look perfectly normal in the shop.
Honesty in the cart
The cart summary was fixed in the same pass, and those changes are not technical but about honesty:
- VAT on separate lines per rate. With mixed rates, one total means the cart does not match the invoice and the customer rightly asks why.
- Shipping line: “calculated at the delivery step”. Saying what will happen instead of showing zero. A customer who sees zero assumes it is free.
- The return period written on the page. Not only in the terms, but where the decision is made.
- One bank account preselected for transfers. Listing six accounts does not produce a decision, it produces confusion.
None of these is a “feature”. All of them are about the customer knowing what will happen before pressing pay.
And a help desk
In a technical shop support requests are inevitable. But most questions repeated.
I turned the help desk into a support centre: frequently asked questions, installation notes, scope explanations. The aim is not to block requests — it is not answering the same question a third time.
What I learned
The hardest part of an online shop is not the payment flow. It is being able to answer the question the customer is actually asking.
And some features do not ship just because the code is finished. A recommendation system being wrong is worse than not existing — which is why the switch is still off, and why the day it turns on will not be my decision alone.