Skip to content
Ritesh FirodiyaGet in touch

Work / Chitragupt / Wiki / Decisions

2026-09-11-support-desk-stays-in-house

Decisioncanonicalverified 2026-09-11

DECISION.2026-09-11.SUPPORT-DESK-STAYS-IN-HOUSE

Support desk stays in-house — no Zendesk, no Freshdesk

Decision

The support-ticket desk and the DPDP grievance desk both stay in-house. No third-party helpdesk ships in V1. If ticket volume ever justifies revisiting, Freshdesk on its IND data centre is the only candidate — Zendesk is ruled out on data residency.

Why

Raised as a scope-reduction idea: the product felt large and the admin side felt unfinished, so buying a helpdesk looked like a way to save time. Two things made it the wrong trade.

The admin side was already built. 30 admin callables across 12 files in apps/functions/src/admin/, 12 live queues, 11 wireframes, 11 surface pages, and committed composite indexes for support_tickets and grievances. Buying would have orphaned working code, not replaced missing code. The support desk's own state machine (open → in_progress → resolved) is the thing a helpdesk sells.

Buying costs more than it saves, and fixes nothing that was broken. Adopting a vendor means a new infra-sub-processors row, a sign-up consent re-flow, PII redaction on egress, and a ticket migration. It collides with data-residency-dpdp ("No transfer of personal data outside India in V1") and follows the same shape as 2026-06-10-no-recaptcha-ever, which rejected a third party specifically for cross-border data flow.

It also would not have helped, because the admin half worked and the user half was severed:

  • adminReplySupportTicket wrote status: "first_responded", a value absent from SUPPORT_TICKET_STATUSES. The website store drops any ticket that fails safeParse, so a ticket vanished from the user's own list the moment an admin replied.
  • Neither reply nor resolve sent email, and the settings surface has no thread — so an admin's answer was unreachable by any path.
  • Nothing ever flipped sla_breached, so the admin dashboard's breach tile — a V1 launch gate — read zero regardless of queue age.

Those were a day's work, not a migration.

The grievance desk cannot move regardless. DPDP §13 carries a statutory deadline and wires hard_delete_user_content into the account-deletion cascade. A bought helpdesk means running two desks.

Vendor findings (2026-09-11)

Vendor India data region Verdict
Zendesk No — US / EEA / Australia, and residency is a paid Data Center Location add-on Ruled out
Freshdesk (Freshworks) Yes — IND, chosen at signup and pinned thereafter Only viable fallback
Intercom / Crisp / HelpScout No India region Ruled out

Note for accuracy: the DPDP Act itself does not mandate blanket localisation — it uses a negative-list model. "No transfer outside India in V1" is our own stricter constraint, so it is ours to relax deliberately rather than a legal wall.

Impact

  • No helpdesk vendor is added to infra-sub-processors; the consented list is unchanged.
  • Ticket statuses trimmed to the three the wireframe shows. Every status write is typed SupportTicketStatus, so an unknown value is a build error.
  • Admin reply and resolve now email the user. Not gated on notification preferences — the user opened the ticket.
  • dailySupportTicketSlaCheck stamps sla_approaching (internal first-response target) and sla_breached (the public 7-working-day promise from copy-strings COPY.SUPPORT-SLA).
  • SLA.support_working_days corrected 1 → 7. The pricing feature table collapsed to the single support row the wireframe carries, dropping a "Phone support during tax season" row and an "Email support · 24h SLA" row that promised more than the design does.
  • Revisit trigger: sustained volume where macros, CSAT, a knowledge base or inbound email-to-ticket would pay for the migration. Not at soft-launch scale.

Status

Active.

Sources

Every project of mine is written down like this.

Read the résumé