A point of sale counter, production software used while taking money

WezDev

Production SaaS · Manchester

SaaS that still works when the network does not.

MOMO Lens is merchant mobile-money ops: sales, matching, receipts. React Native on the phone, NestJS behind the ledger. It is in production in select markets. That is the bar, not a demo on wifi.

The work

What I mean by production SaaS.

Taking a sale, matching the payment, keeping the books. On a phone, often on a slow network, with a merchant who will abandon the app the first time the numbers disagree with their wallet. MOMO Lens does that in select markets. That is the bar I mean when I say production: not a login screen, not a dashboard that only works on office wifi. I do this work from Manchester.

What production actually means here

A demo that works on office wifi is not the product. Merchants take money on 2G and 3G, sometimes in a stall with one bar of signal. The ledger has to survive a duplicate SMS, a reversal that arrives hours later, a sale captured while offline, and a retry that must not double-count. Those are not edge cases. They are Tuesday afternoon. If you leave them for “v2”, the merchant will trust a notebook again. My opinion is blunt: production SaaS in this lane is the set of failures you have already designed for, not the happy path you showed in a pitch.

Phone for the stall, web for the exceptions.

React Native is what the merchant uses to take a sale: products, cash or mobile money, a receipt before the customer walks off. Next.js is what someone uses when a match is wrong, a reversal needs review, or the day’s cash-up does not line up. Same ledger, different jobs, different permission sets. If you only ship the phone, the ugly cases end up in WhatsApp screenshots and a spreadsheet nobody owns. If you only ship the web, nobody at the stall will use it. I build both surfaces against one NestJS API so an exception on the web is correcting the same books the phone wrote, not a second source of truth.

The ledger is the product

Reconciliation is a matching problem, not a form. You get a payment signal (API event or SMS), a sale the merchant recorded, and a pile of ambiguity: phone numbers with different formats, amounts that almost match, timing windows, duplicates, reversals. Automated rails such as Flutterwave and fee-sensitive manual SMS have to live in one system, because many merchants mix both in the same day. A wrong match is worse than no match. Confidence scoring, a queue, and an operator path to confirm or reject beat a spreadsheet every time. That engine is why MOMO Lens is a product instead of a payment button with a hope.

Offline is not a nice-to-have

React Native with an offline queue. Capture the sale on device. Sync when the radio comes back. Never corrupt the books because the request retried twice or the SMS arrived late. That means idempotent writes, clear sync state, and UI that tells the merchant what is pending versus settled. It is slower to build than a happy-path checkout that assumes London wifi. It is also why the thing is still in production in markets where the network is the constraint, not the exception. If your SaaS cannot tell the truth after a drop, it is not production. It is a demo with a store listing.

What I shipped

NestJS, PostgreSQL, Redis, and Prisma on the backend, with RBAC and adapters for telco and payment rails. React Native on the App Store and Play Store in select locations. Next.js for operators who fix matches and read the day. Coverage designed for seven African markets and more than twelve mobile-money providers, because the product shape changes by country even when the ledger rules stay the same. The merchant loop is complete: sales, payments, matching, receipts, expenses, reporting. That is the case I point at when someone asks what production SaaS looks like in my hands.

Proof

MOMO Lens is in production, not a pitch deck.

Tap a screen. Products, a new sale, cash, reconciliation. That is the merchant loop. The hard part is keeping it honest when the network is not.

MOMO Lens products screen

SaaS · payments

MOMO Lens

Screen: Products

Hard part: Mobile-money flows differ by country, and merchants need a ledger that survives bad networks.

Outcome: Production React Native and NestJS stack with reconciliation, sales, and reporting in select markets.

Who it has to survive

Same product, different pressure.

Select a seat. If any of these is an afterthought, the SaaS will look fine in a demo and fail in a stall.

Merchants

Take the sale

Take a sale, take payment, see if it matched. The app has to be obvious at a stall, on a small phone, with a thumb. If it needs a training day, it will not be used.

Merchants
Take the sale. Take a sale, take payment, see if it matched. The app has to be obvious at a stall, on a small phone, with a thumb. If it needs a training day, it will not be used.
Staff
Inventory and cash. Products, cash, receipts. Different permissions from the owner. RBAC is not a nice label on a slide. It is how you stop a junior login from emptying the books.
Back office
The ugly exceptions. Reconciliation, reporting, duplicates, reversals. This is where NestJS, Prisma, and Redis earn their keep. The operator web surface exists so someone can fix a match without SSH.
The network
2G, 3G, late SMS. The product is designed for a bad radio, not against it. Offline queue, SMS parsing, adapters per telco. If you assume London wifi, you will ship a toy.

Hard parts

The work that decides if merchants stay.

These are the MOMO Lens problems. They show up on any payments SaaS that leaves the demo environment.

Matching, not just capture

Phone numbers, amounts, timing, duplicates, reversals. A sale that never matches is worse than no sale. The engine needs confidence, not hope.

Two payment modes, one ledger

Automated collection and fee-sensitive SMS reconciliation have to coexist. Forking the product per country is how you get twelve codebases.

Offline without corrupting the books

Queue the sale. Sync later. Never double-count because the app retried. That constraint is the architecture, not a flag you flip at the end.

What you hire

Performance and session metrics on a monitoring dashboard

04

Production

Cypress and CI before code reaches production. Dynatrace, CloudWatch, and CloudTrail when something pages. Dashboards and internal tools so one incident does not mean five tabs and a guessing game.

FAQ

Straight answers.

Who builds this at WezDev?

Wez Kambele is a software engineer based in Manchester. MOMO Lens is his production SaaS case: merchant mobile-money reconciliation and micro-ERP, live on the App Store and Play Store in select markets.

What stack is MOMO Lens?

React Native on the phone, Next.js for operators, NestJS with Prisma, PostgreSQL, and Redis on the backend. Flutterwave for automated rails, plus SMS parsing where the country still works that way.

Do you only do fintech?

No. Payments made the constraints obvious: ledger, permissions, bad networks. The same bar applies to other production SaaS. If the product only needs a marketing site, I am the wrong hire.

Where are you based?

Manchester, United Kingdom. Remote is normal. UK and Africa-facing product work is a natural fit.

How do I start?

Read Work with me, then send a short brief on Get started: who takes money, what the ledger has to survive, and what is already live. You can also email contact@wezdev.co.uk.

Is this the same as web development Manchester?

No. This page is for production SaaS and payments, not WordPress or a brochure. If you need a marketing site, look elsewhere.

Related: Product platforms in Manchester · AWS infrastructure in Manchester · Work with me

Next

If the ledger has to hold, start with a brief.

Tell me who takes money, what the network looks like, and what already exists. I will tell you whether I am the right engineer for it.

Your privacy

Cookies help us understand journeys — not sell your data.

We use essential cookies for theme and consent. With your permission, analytics shows which pages and projects people explore so the site can improve. You can change this anytime.