PesaFii
A multi-tenant platform for people who sell Wi-Fi: hotspot routers, vouchers, customer payments by mobile money, and the ledger underneath.
Live site (pesafii.net)
Private repository


What it enables
- Business owners connect MikroTik routers, set prices and sell access from a captive portal.
- Customers pay with MTN or Airtel mobile money and are let through by the router.
- Owners run sales, vouchers, agents, wallet and live sessions from a web dashboard or the React Native operator app (16 feature areas).
My contribution
I am the only engineer: the React dashboard, the React Native operator app, the Express API, the PostgreSQL schema and ledger, RADIUS accounting and the router integration.
Engineering decisions
Customers could be charged twice
- Problem
- If the captive portal lost its payment-intent ID mid-flow, initiation could run again and take a second payment.
- Decision
- Made payment initiation idempotent against the intent, so a retry settles onto the same charge.
- Result
- A repeated request can no longer create a second charge.
The portal was slow where it mattered most
- Problem
- Customers on cheap phones and thin signal waited for a package request that started 83.9 KB into the document.
- Decision
- Moved the request to 2.3 KB into the document and opened DNS, TCP and TLS at parse time with preconnect.
- Result
- About 330 ms of handshake removed from the critical path, and returning devices paint from cache.
A revoked session could come back
- Problem
- Caching session validity in Redis makes the hot path fast, and lets a stale “yes” outlive a revocation.
- Decision
- Fenced revocation so a cached positive can never resurrect a dead session, and reconciled fences at startup.
- Result
- PostgreSQL stays the only authority on whether a session is valid.
One RADIUS site was a single point of failure
- Problem
- Every login authorised through one site.
- Decision
- Brought up a second site and made disconnects site-aware, so a router is reached over the tunnel it is attached to.
- Result
- Failover verified by taking the primary away, not by reading the configuration.
Stack
- React
- React Native · Expo
- Node · Express
- PostgreSQL
- Redis
- FreeRADIUS
- MikroTik RouterOS
- WireGuard
Boundaries
Screens here are from the public website only. The dashboard and app handle real businesses’ data, so they are not shown.