Skip to content
All work
Live in production
Marketplace · logistics
2026

QuataFood

Food delivery, three apps, one backend

A food-delivery marketplace for Cameroon — customers order, riders deliver, restaurants manage menus and a POS, admins run the operation — across three native apps and five web portals.

Visit live site
quatafood.com

Role

Sole developer

Client

QUATA Digital Enterprise

Status

Live in production

Year

2026

2,577

E2E test blocks

567

API endpoints

122

DB tables

370k

Lines of code

9

Admin staff roles

3

Flutter apps

The hardest problem

Getting a live order to three different parties on three different devices in real time, over Cameroonian mobile networks — and behaving correctly when one of them doesn't get the message. Android push delivery there is genuinely unreliable: Doze mode, aggressive OEM battery managers on cheap devices, patchy connectivity.

What I did about it

01

Layered redundancy with server-side authority, rather than trusting any single delivery channel. Each surface gets a persistent WebSocket for live state, with dedicated E2E tests per channel.

02

FCM push over HTTP v1 acts as a wake-up channel — and where a missed message costs money, a native attention-grabber that doesn't depend on the notification tray takes over.

03

The partner app plays audio through audioplayers on the order:new event, because a restaurant tablet sits on a counter and a silent banner is invisible. The rider app draws a full-screen overlay over other apps, the only reliable way to interrupt someone on Android.

04

Acceptance is resolved server-side, not by whichever UI reacts first — the order state machine lives in the backend with order_status_history recording every transition, so two riders tapping accept in the same second produce one winner and one clean rejection.

What I rejected, and why

Polling is far simpler and would have worked. Rejected because at Cameroonian data prices, three apps polling every few seconds is a real cost passed to riders who are least able to absorb it — and it still wouldn't solve the 'phone is asleep' problem that made the native overlay necessary.

What I’d change

Only 14 of 161 pages are server-rendered — the thinnest ratio here — and for a consumer marketplace that needs restaurant pages to rank, that is a growth problem rather than a technical one. I would server-render the whole storefront and keep the client rendering to the authenticated portals.

Built with

FastAPIPostgreSQL + PostGISRedisCeleryNext.js 16MapLibre GLFlutterWebSocketsPlaywright

Next case study

Indian Cultura

Heritage commerce, two gateways, COD