About me
I'm a Full Stack Developer with 5+ years building enterprise web and mobile applications — C#/.NET, Node.js/NestJS and Go on the backend, React on the front, React Native, Flutter and native Swift on mobile, Postgres underneath. Based in Lagos, Nigeria.
Most of that work has been in fintech, banking and professional networking platforms: real-time messaging, AI moderation pipelines, field-level encryption and approval-gated workflows — the kind of features where being wrong is expensive. Alongside it I build infrastructure of my own: a webhook normaliser, a reconciliation service, a compliance decision engine and an embeddable dispute system, each published with the architecture decisions behind it.
More recently I've been building for the Nigerian market directly — Backhaul, freight tracking for road logistics, Grid, electricity accountability for households disputing a bill, and Vitals, a primary health record that lives on the clinic's tablet and the patient's phone and merges two copies edited while neither could see the other, without losing a fact. All three are cross-platform from one codebase and drop into Kotlin and Swift where the platform makes you: background location that keeps recording when the network goes, on-device OCR, a proof of delivery that can be signed and sealed at a market gate with no signal at all. And two that are native Swift outright, because the platform is the point: Tender, a naira note identifier for blind and low-vision users, where the accessibility layer is not a feature of the interface but the interface itself; and Snag, a move-in condition report sealed with a key in the Secure Enclave, so that two years later the argument about the cracked tile has something to argue with.
I write things down before I build them, and I try to make failure modes explicit — a service that says it does not know is more useful than one that guesses confidently. That extends to what isn't finished: each project says where it stopped and what would actually close it, because a blocker that needs a device or a translator is not the same as one that needs an afternoon.
What i'm doing
-
Data & infrastructure
Postgres and SQL Server schemas, Docker, and CI pipelines that run the tests before anything ships.
-
Web development
React, Next.js and TypeScript front ends — accessible, responsive, and fast on the networks people actually have.
-
Mobile apps
Cross-platform apps in React Native and Flutter, dropping to Kotlin and Swift where the platform makes you — background location, foreground services, on-device OCR. One rules package, shared by every face.
-
Backend Development
Go, .NET and Django services on Postgres — payment infrastructure, reconciliation and compliance, designed around what happens when things fail.
Evidence
- 4,500/sec events sustained through StatusHub at p99 27.9 ms, measured under load test
- 1,244 tests across 72 Jest suites, 70% coverage, on the platform I architected at Eucharovia Ventures
- 40% faster page loads at Ausome Bee via Redis caching, lazy loading and code splitting
- 30% better data-fetching efficiency by redesigning API endpoints around what the frontend needed
- 0 hard-coded strings across Backhaul's 27 screens in four languages — enforced by a build gate, not by review
Decisions worth reading
Every project I build carries architecture decision records — not just what was chosen, but what was rejected and why. Six of them:
-
Persist, then acknowledge
Raw webhook bytes hit Postgres before anything tries to parse them. A payload we cannot understand is still a payload we did not lose — and the provider will not send it twice.
StatusHub · ADR-001 → -
Ingest gaps route to suspect, not to reversal
If our own ingest had a gap over the window, a missing credit proves nothing. The transaction goes to a human instead of triggering an automated reversal that would take real money back.
ReconSync · ADR-0004 → -
Division is not in the rule grammar
Not restricted — absent. A compliance rule cannot produce a float, because 100% reproducibility and floating point do not sit together in a system that has to explain a decision made six months ago.
ComplyLayer · D6 → -
A phone number names a party and never answers a question
A shipper opening a trip has phone numbers, not user IDs. The obvious fix — look the number up — is an endpoint that turns the Nigerian mobile range into a list of who is running freight. So there is no lookup: opening a trip resolves the number as a side effect and answers identically whether it found an account or created one.
Backhaul · ADR-0016 → -
The device seals a delivery; the server countersigns
The draft used to live on the server, which is durable and unreachable — so a driver at a market gate with no signal could photograph the goods, take a signature and have nothing. The phone seals it now, and the server's timestamp becomes a second fact rather than a permission. Unpaid drivers are what the alternative costs.
Backhaul · ADR-0018 → -
Unobserved time is
unknown, and coverage is always reportedSupply hours are inferred from a phone that is sometimes off, elsewhere or killed by the OEM. Interpolating across the gaps produces a clean chart and a confident average — and fabricates evidence, inside a document whose whole purpose is to be believed. So
Grid · ADR-0006 →unknownis a first-class state and the gaps are shown.