The brief
What needed solving
Cooking happens in the kitchen, not at a desk. The web marketplace proved that people would buy from chefs, but the actual moment of use — following a recipe, asking a chef a question, buying the missing ingredient — is a phone moment. The app had to carry the same catalogue and the same commerce rules onto mobile without becoming a second, divergent product.
Approach
How it was built
01One backend, two front ends
The app was built against the same Node.js API as the web platform, so catalogue, entitlements and subscription status are computed in exactly one place. Anything a user buys on the web is immediately theirs in the app, with no separate sync layer to fall out of step.
02AI generation as a normal, interruptible flow
Recipe generation is asynchronous and can fail, so it was designed as a first-class flow with its own loading, partial, retry and empty states rather than a spinner over a blank screen — the user always knows what the app is doing and can back out of it.
03Native-feeling interaction, shared logic
Navigation, gestures and list performance follow platform expectations on both iOS and Android, while business logic, API clients and models stay shared — the split is deliberately drawn between what must feel native and what must never be written twice.
Scope
What shipped
- AI-assisted recipe generation from what the user has on hand
- Instant ingredient carts built straight from a recipe
- Live one-to-one chef sessions with in-app booking
- Direct chef messaging for questions mid-cook
- Stripe-backed subscriptions and premium content unlocks
- Shared account and entitlements with the web platform
Engineering notes
The hard parts
Challenge
AI responses are variable in both shape and latency, which makes them hostile to a UI that assumes an immediate, well-formed answer.
Solution
Responses are validated and normalized before they touch the interface, with defined fallbacks for partial results, so a malformed or slow generation degrades into a usable screen instead of a crash.
Challenge
Payments and subscription entitlements have to agree between the app, the web platform and Stripe, on devices that lose connectivity mid-flow.
Solution
Entitlements are always resolved server-side from Stripe's state rather than trusted from the client, and purchase flows are idempotent so a retry after a dropped connection can't double-charge or half-unlock content.
Challenge
Media-rich feeds degrade quickly on mid-range Android hardware once lists get long.
Solution
Virtualized lists with capped image resolution per viewport and stable item keys, keeping scrolling smooth without shipping full-size photography to every device.
Outcome
Where it landed
- 01A single product identity across web and mobile, backed by one API and one entitlement model
- 02Chefs gained a recurring revenue path — subscriptions and paid sessions — inside the app itself
- 03Cross-platform delivery from one React Native codebase for iOS and Android
