Skip to main content
Back to the garden
·🌿 12 min · Medium read

Why I built TricomHub

Hospitality platforms in East Africa underserve small operators. This is the long-form story behind a multi-tenant SaaS I built solo — schema decisions, M-Pesa surprises, and what shipping a security-tested PWA actually takes.

SaaSTricomHubPostgreSQL

The booking problem in South Sudan, in one sentence

Hospitality operators in Juba, Wau, and Malakal were running their bookings on WhatsApp threads, paper ledgers, and the occasional Excel sheet — because every off-the-shelf platform was either priced for global chains or built around payment rails that don't exist locally.

I knew this because I'd watched a friend's hotel manager spend forty minutes confirming a reservation that should have taken thirty seconds.

What I actually built

TricomHub is a multi-tenant hotel booking SaaS / PWA. One operator account = one tenant; one tenant = its own scoped data, its own RBAC, its own branded guest experience. Guests install the PWA, browse rooms, and pay with M-Pesa STK Push. Operators get a dashboard, automated WhatsApp Business API notifications (27 templates), email via Resend, and live chat via tawk.to with AI context.

Under the hood:

  • Next.js 15 App Router on Vercel
  • Supabase Postgres — 40+ tables, row-level security on every scope
  • Better Auth for sessions and roles (Owner / Manager / Staff / Guest)
  • Cloudflare in front for DNS and edge caching
  • Playwright — 18 specs covering CRUD, auth, stress, and four security surfaces (SQLi / XSS / IDOR / JWT)

Three decisions worth defending

Why Better Auth over NextAuth

Better Auth's session model maps cleanly onto Supabase RLS — the JWT carries the org and role, RLS policies read them directly, and there's no adapter glue I have to remember to update when a new role lands. NextAuth would have worked, but at the cost of a wrapper layer that drifts every time the auth schema evolves.

Why WhatsApp templates over SMS

SMS delivery in South Sudan is uneven enough that I couldn't trust booking confirmations to land. WhatsApp delivery in the same network is closer to 99% and the templates also let operators stay within Meta policy without per-message review. The cost difference is meaningful too — templates are a fraction of an SMS once you're past the free tier.

Why a 40-table schema instead of fewer wider tables

Multi-tenant SaaS with strict RLS rewards normalisation. Every wide table makes policy auditing harder — you have to remember which columns belong to which scope and which queries can join across them safely. Narrow, single-purpose tables let RLS be obvious. Reads cost more joins, which is fine; writes cost less coordination, which is the part you can't fix later.

What surprised me

How much of "shipping the platform" was the stuff around the platform — Cloudflare TLS edge cases, M-Pesa sandbox parity with production, getting WhatsApp Business templates through Meta review the first time. The actual product code was the easy part by month four.

Also: security tests catch real things. I wrote the SQLi specs as a discipline exercise and they immediately surfaced a comparison query I'd authored that bypassed RLS in a corner case. Catching that in a Playwright run beats catching it in a customer's logs.

What I'd do differently

I'd wire the Playwright suite into Vercel preview deployments earlier. Running it locally caught most regressions, but two issues made it to staging because I added the GitHub Actions integration only after the launch sprint settled down. The cost of getting CI right early is paid back the first time you avoid pushing a broken deploy on a Friday.

I'd also build the operator onboarding wizard with a state machine from day one. The ad-hoc "next step" ordering accumulated edge cases I had to refactor when a real-world operator hit a path I hadn't planned for.


If you're shipping a multi-tenant SaaS into a market with thin payment-rail and connectivity infrastructure, the hardest decisions aren't framework choices — they're the boring integration details. WhatsApp templates over SMS. STK Push semantics over card-first checkout. RLS over middleware-policed access control. Each of those felt obvious in hindsight; none of them did the first time around.