Should I vibe code
Manage tickets from email and a web form with priorities, owners, and a help center
A help desk gives every customer conversation a URL. Sequential ids plus a weak check is a breach.
?
Their verdict, the Growth price and the build-time estimate come from their entry, MIT-licensed. Checked 2026-08-04.
?
Our verdict, the regret score and everything below it. Editorial and unsponsored — nobody can pay to be moved.
The honest answer
why the verdict is what it is
Inbound webhook, ticket row, reply — three days of work, and it demonstrably functions on day four. What separates Freshdesk from a shared mailbox is the shape of the thing you have accidentally agreed to run: a customer portal and a help centre, which means every support conversation now has a URL that a stranger can type. The homemade help desk does not usually fail by dropping mail. It fails when /tickets/1043 loads for anyone with a session, and one customer reads another's refund thread with an order number and a home address in it.
What actually breaks
not "if". the specific failures.
- Authorisation on the portal — a ticket id in the URL, and a check that only asks whether you are logged in at all
- Threading, where a mangled References header starts a new ticket and the customer's third message reads like their first
- Auto-responders answering auto-responders, until an out-of-office has been mailed two thousand times
- Attachments: someone sends a photo of their passport to prove who they are, and it lands in a bucket with a guessable path
- The help centre, which is a CMS you now own, with a search that is worse than the one you replaced
- Reply-all on a ticket that was merged, sending one customer's thread to another's address
A refund thread contains an order number, a delivery address and a phone number, because that is what a refund thread contains. On Saturday a customer writes in to say the ticket she opened is showing her somebody else's conversation. You look: the portal loads a ticket by id and checks that the session is valid, which it is — she is a real customer, correctly logged in, viewing /tickets/8841 by editing the number in /tickets/8840. It has behaved this way for eleven weeks. Your access logs record page views but not which ticket, so the honest answer to "how many" is that you cannot say, and the honest answer to your customers is a notification you now have to write.
Is that you?
the verdict is a default, not a law
- It is an internal queue and everyone who can open it already works for you
- There is no customer-facing portal at all — replies go by email, and only by email
- Inbound arrives through a provider that parses the mail for you, and every message is stored before it is acknowledged
- Customers log in to view their own tickets
- Nothing alerts you when the mail poller stops
- You cannot produce every message relating to one person on request, or delete them
- Agents will paste passwords, card numbers or ID scans into tickets — and they will
If you build it anyway
the checklist, then the prompt that enforces it
- Authorise every ticket read against the requester, not the session. Write the test that fetches ticket N+1 as the wrong customer and expects a 404 — and make it a 404, not a 403.
- Use random ids in customer-facing URLs. It is not a security control, but it removes the accident that leads to the incident.
- Persist inbound mail before you acknowledge it. A 200 to the webhook is a promise nobody will repeat.
- Never auto-reply to a message carrying Auto-Submitted or Precedence: bulk, and rate-limit per address regardless. Mail loops are cheap to start and expensive to stop.
- Alert when nothing has arrived for an hour. The failure mode of an inbox is silence, and silence looks exactly like a quiet Tuesday.
- Serve attachments through an authorising handler with random keys, never from a public bucket path, and make agent-side deletion actually delete.
- Strip anything shaped like a card number on ingest, before it reaches storage, logs or a search index.
I am building a help desk: email in, tickets out, and a portal where customers
see their own tickets. Treat authorisation as the product. Apply these and push
back if I ask you to break them.
1. Before any ticket UI exists, implement authorisation: every read and write
is checked against the requesting customer, not merely against a valid
session. Write the test that requests someone else's ticket and expects a
404, and run it in CI.
2. Customer-facing URLs use random ids, not sequential integers. Enumeration
should be impossible, not merely tedious.
3. Inbound mail is persisted raw — full RFC 5322 message, headers included —
before the webhook or poller acknowledges it. Never acknowledge and then
process; a crash in between is silent, permanent loss.
4. Thread on Message-ID, In-Reply-To and References. Do not thread on subject
line. When threading is ambiguous, create a new ticket and flag it rather
than guessing into an existing one.
5. Never auto-reply to mail carrying Auto-Submitted: auto-generated or
Precedence: bulk, and rate-limit auto-replies per address per day.
6. Attachments are served through an authorising handler with random keys.
Never a public bucket path, never a predictable filename.
7. Redact on ingest: anything matching a card number pattern is masked before
it reaches the database, the logs or the search index.
8. Add a heartbeat alert that fires when no mail has arrived in an hour, and
tell me where it pages. Silence is this system's failure mode.
9. Give me one operation that exports and one that deletes everything tied to
an email address — tickets, messages, attachments, audit rows. Before the
help centre.
10. Log every ticket view with the viewing identity and the ticket id, so
"who saw what" is answerable after an incident.
11. Out of scope: live chat, SLA automation and a public knowledge base. Each
one is a separate product wearing this one's clothes.That one keeps you out of trouble. For the prompt that actually builds it, canivibecodeit.com has one.
their build prompt ↗Or don’t build it
the boring option, and the way back out
The day the first customer logs in to look at their own ticket. $18 an agent buys an authorisation model, threading, loop protection and a portal that strangers have been probing for a decade. You are not paying for the ticket list — you are paying for everything that stops one customer reading another's.
$18/mo is cheaper than your weekend.
Keep every message as raw RFC 5322 with its Message-ID intact, not as a row of parsed text and a rendered HTML blob. If the mail survives in its original form, tickets can be rebuilt by anything — including a real help desk's importer — and the migration is a script rather than a rewrite. Store attachments as files next to a manifest, so they survive the database that indexed them.
Mature open-source customer engagement and shared-inbox platform, with the portal and permissions work already done.
Self-hosted PHP help desk modelled on Help Scout. Closer in shape to a small support inbox than Chatwoot, and actively maintained.
Questions
Is inbound email really still the hard part?
No, and that is exactly the trap. Postmark, SES and friends turned "receive and parse mail" into a webhook, which is why the first two days feel so productive. The difficulty moved to the parts that come after: who may read this, what happens when nothing arrives, and what a merge does to two people's threads.
Why does the customer portal change the verdict so much?
Because it converts an internal tool into a public one. Without it, your worst bug is an agent seeing a ticket they did not need to see. With it, the same bug is a stranger reading a customer's address, and the remedy is a disclosure rather than a patch.
We get forty tickets a month. Isn't this overkill?
At forty tickets a month the honest build is the SHIP IT line: an internal queue, no portal, replies by email. That is a genuinely good weekend project. The verdict here is about the moment you add the login, which is usually the third week.
- GDPR Art. 5 — principles relating to processing of personal data (EU)
- GDPR Art. 32 — security of processing (EU)
Every week, someone ships something they shouldn’t have.
New verdicts, the worst thing that landed in the trap, and the occasional incident report. No other email, ever.
A dropped support email is invisible. You find out from the refund request.
An AI that answers your customers wrongly is a support ticket that scales.
A chat widget is an unauthenticated write endpoint pointed at your phone. Guess who finds it first.
last reviewed 2026-08-04 · verdict is editorial and unsponsored · shared entry data from canivibecodeit under MIT · not legal advice