mobslgcy
← All work

Fintech · 2024 — Present

PayGov & Revco

Six role-specific apps merged into one multi-tenant platform for government revenue collection.

Role
Frontend Engineer, Paysure
Timeline
2024 — Present
Stack
Next.js, TypeScript, NextAuth v5, SWR, Edge Middleware, AWS
Links
Live site ↗ · 3 min read
The Revco dashboard: a green-accented revenue portal for Taraba State showing tax service categories and a payment lookup form.

The problem

PayGov is a billing, invoicing and revenue-collection platform for government agencies, ministries and their authorised partners. It covers the whole lifecycle: a bill is created, collected, remitted and reconciled for compliance.

When I joined Paysure, that lifecycle was spread across six separate Next.js apps, one per role. Each had its own login, its own copy of shared UI and its own drift. A fix in one rarely reached the other five, and every new tenant meant another round of copy-and-configure.

What I built

One multi-tenant platform in place of the six, serving 2,000+ users and ₦45M in yearly payment volume.

apps consolidated
6 → 1
BFF endpoints secured
280
route handlers guarded
243
roles
10
permission scopes
4
downtime from two RCE CVEs
0

Tenancy that lives in the URL

Each tenant is scoped by path. The slug is resolved on the server before anything renders, so a page never shows one agency's data under another's name. A reserved-segment guard stops a tenant slug from shadowing a real route, and sessions are bound to the tenant they were issued for, so a token from one agency is useless at another.

Access control as a schema, not a scattering of ifs

The platform talks to its backends through a 280-endpoint backend-for-frontend. I centralised authentication on NextAuth v5 JWT sessions, with refresh tokens rotated before they expire rather than after a request fails. Authorisation lives in one role-and-compliance schema that drives both the route guards (243 handlers, 10 roles, 4 scopes) and the navigation itself, so a user never sees a link they cannot follow.

The hard part: two RCE CVEs and no time to upgrade

Two remote-code-execution vulnerabilities were disclosed in the framework while an upgrade was not immediately viable. Rather than wait, I shipped app-wide edge middleware that rejects and logs the text/x-component POST payloads that carry the exploit. Both production apps were protected with zero downtime, and the logs showed us what was being attempted.

Smaller, everyday wins

Dashboards were refetching the same lists on every interaction, and a filtered view could not be shared. I moved table state into typed query parameters behind a debounced router push, served from SWR with stable cache keys and keepPreviousData. Redundant requests dropped, and any filtered view became a link a colleague can open.

Revco

Revco is the public face of the same work: a revenue and tax portal for state boards, with custom subdomains per tenant and admin dashboards for transaction tracking. The Taraba State deployment is live.

Something here caught your eye?

Tell me about the product you’re building, the role you’re hiring for, or the problem you’re stuck on. Pick a coffee chat, a consultation or a hiring conversation.