The complaint register: three people complained about the same thing, and nobody put it together
Complaints arrive in five places and each one is fixed and forgotten, so the same fault gets paid for six times. Everything lands in one list with your own categories on it, and one page a month shows what actually keeps going wrong.
Every complaint in one list whoever takes it, sorted into your own categories by a model on your own box, and one honest page a month showing what keeps going wrong
- Your own list of eight to twelve complaint categories, written before any software is installed - if you cannot name them, the model will not name them for you
- One mailbox everything can be forwarded to, and agreement that a complaint solved on the spot still gets logged
- An always-on machine with roughly 8-16 GB of RAM for the local model, or a mini-VPS at EUR 5-12/month
- Ten minutes a month, by the owner, to read the theme page and pick one cause to fix
Version history
Three complaints in a month about the same thing are not three complaints. They are one problem you paid for three times, and nobody put them together, because each one was solved by a different person on a different day and the record died with the phone call.
The architecture
the same flow as text
│ │ │
└────────────────┴────────────────┘
▼
[ n8n ] one pass every 15 minutes — makes the row, never the answer
▼
[ Local model via Ollama ] picks from your fixed list:
│ theme (8-12 options, or "other"), product/job reference,
│ what the customer is asking for — as a draft
▼
[ Grist — the register, one row per complaint ] ◄── the only record
│ acknowledge_by = received + 2 working days
│ promised_by = what you told the customer
│ adr_reply_by = body's letter + 20 working days
▼
├─ severity high (injury, food, data, money) → a person, now
├─ any clock passed → the owner, by name
└─ first Monday of the month → one page: themes, repeats, what it cost
Nothing is sent to a customer by a machine. The register classifies; people reply.
The whole design decision is that the model only ever fills the boxes. It reads a paragraph of angry text and picks a theme from a list you wrote, pulls out the order or job number, and says what is being asked for. That is copying, not judgement, and a 7-8B model does it well. The reply, the goodwill, the refund and the apology stay human, because a complaint answered by a machine is how one unhappy customer becomes a screenshot with 400 shares.
The problem
The EU switched off the central complaints button. The Online Dispute Resolution platform, the one every online seller was required to link to, stopped accepting new complaints on 20 March 2025 and was shut down on 20 July 2025, with the stored data deleted; Regulation (EU) 2024/3228 repealed the regulation that created it, and the obligation to link to it went with it. The reason it was killed is the number: 2 to 3 million visitors a year, of which about 2 percent of complaints ever got a positive reply from the trader, which came to roughly 200 resolved cases a year across the whole Union. Nine years of a button almost nobody answered.
What replaces it is aimed squarely at the trader. Directive (EU) 2025/2647 was published in the Official Journal on 30 December 2025 and entered into force on 19 January 2026, and member states have to have it in national law by 20 March 2028. Three things in it matter for a small business. When a dispute-resolution body contacts you about a case, you answer within 20 working days whether you will take part, 30 if the case is genuinely complex. The scope now also covers pre-contractual behaviour, so what you advertised and what you failed to disclose are in range, along with digital content and services. And traders are pushed to tell customers how their own in-house complaint handling works, which presumes you have one.
There is also a small job on your website today. If your legal notice, terms or email footer still links to the ODR platform, it points at something that has not existed since July 2025. German practitioners flag that a stale reference is not neutral: it can be read as a misleading commercial practice and drag in a cease-and-desist letter. Delete it.
None of that is the real reason to build this. The real reason is that complaints arrive in five places — the shared inbox, a phone call, a remark at the counter, a review, a message to a personal number — each one gets handled by whoever caught it, and none of them meet. So the same faulty batch, the same technician, the same misleading line on the quote generates six separate apologies over a quarter and no decision. The software sold for this starts at $14 per user per month for Zoho Desk Standard and runs to $40 for its top tier, with Zendesk Support Enterprise at $115 per user per month, all on Zoho's own published comparison page, checked 07/09/2026. For a business with five people and forty complaints a year, that is not the answer. A list, a fixed set of categories, and one honest page a month is the answer.
Tool choices — and why
Setup outline
- Write the theme list before you install anything. Eight to twelve categories, in your own words, from the last twenty complaints you can remember — "late", "wrong item", "damaged on arrival", "quality of the work", "billed wrong", "staff attitude", "could not reach us". If you cannot name your categories, the software will not name them for you.
- Deploy Grist and n8n on one box behind HTTPS. Build the register: received date, channel, customer, order or job reference, what happened in their words, theme, severity, what they are asking for, who owns it, what you promised, promised date, what it cost you, closed date, cause.
- Add the three formula columns — acknowledge_by, promised_by, adr_reply_by — and count them in working days, not calendar days.
- Publish two Grist forms: one public page linked from your site as "make a complaint", one internal page a member of staff fills in after a call or a counter conversation. The internal one must be answerable in 30 seconds on a phone.
- Create complaints@ and forward to it anything that arrives elsewhere. Build the n8n flow: read the mailbox, create the row, attach the original message.
- Install Ollama, pull a 7-8B instruct model, and write one prompt that returns JSON with theme, reference and requested remedy — with the category list pasted in and an instruction to answer "other" rather than invent. Run it over the last fifty complaints you can find and check it by hand before you trust a single row.
- Add the alerting pass: high severity goes to a person immediately; a passed clock goes to the owner by name, not to a channel where it becomes wallpaper.
- Build the monthly page: complaints by theme, the three that repeated, average days to close, and the total of what you paid out. Set it to arrive on the first Monday. Read it for ten minutes and pick one cause to fix. That ten minutes is the whole return on this build.
Pitfalls — what goes wrong when you build this
Verified repos
Grist — Apache-2.0, 11.7k stars, active (07/09/2026)
n8n — Sustainable Use License (free self-hosted internal use), 203.6k stars, active (07/09/2026)
Ollama — MIT, 180.3k stars, active (05/09/2026)
Zammad — AGPL-3.0, 5.9k stars, active (07/09/2026) — the alternative if you want full ticketing
Get the next blueprint as it publishes — free, practical, verified tooling only.
Subscribe · Want this audited or extended for your business? DM @RXed_EU
What this costs to run
Priced as Classify & route — one email or ticket including a short quoted thread; output is a label plus a one-line reason. the model picks one theme from a list you wrote, pulls out the order or job reference and states the remedy asked for; severity, the reply and any goodwill stay with a person, and nothing is ever sent to a customer by machine. Adjust the volume to yours; the bill is a range because the assumptions are ranges.
| Model | $/day | $/month | Reasoning |
|---|
Cheapest eight shown — straight per-token
arithmetic on list prices: no caching, no batch discount, thinking tokens bill as output.
All models + every assumption in the full explorer →
Capability & cost data: Artificial Analysis