Skip to main content
Case Study

Food Ordering App and Restaurant Aggregator

Mobile App React Native Laravel Food Delivery

An order that is late is a problem. An order whose status nobody agrees on is a worse one. The client's aggregator had a customer app, a restaurant tablet and a rider app that each held their own idea of where an order had reached, and support spent its day reconciling the three. ELIVTECH rebuilt the platform around a single order state machine on Laravel, with React Native apps that render that state rather than infer it.

The client aggregates restaurants across several cities with its own delivery fleet. Its original build had grown one interface at a time, each with its own status logic, so a restaurant could mark food ready while the customer app still displayed the order as unconfirmed and the rider had not been notified. Menus were updated by phone. Serviceability was a static radius that ignored whether a kitchen was accepting orders. ELIVTECH rebuilt the system with one authoritative order lifecycle, a menu service restaurants maintain themselves, Elasticsearch-backed discovery that reflects live kitchen state, and React Native apps sharing a codebase across iOS and Android.

At a glance

0 Weeks End-to-End
0 Client Applications Delivered
0 Order Lifecycle States
0 p95 Status Propagation to All Parties

The challenge

Three applications, three versions of the truth, and a support team paid to reconcile them.

Order state implemented three times

Customer app, restaurant tablet and rider app each carried their own status logic and polled at different intervals. A kitchen marking food ready did not reliably reach the other two, so the same order could be preparing, ready and unassigned simultaneously depending on which screen you looked at.

Menus maintained by phone call

Restaurants reported price changes and sold-out items to an operations team who entered them manually. Between the call and the update, customers ordered dishes the kitchen could not make, and every one of those became a refund conversation rather than a meal.

Serviceability as a fixed radius

Discovery listed any restaurant within a set distance regardless of whether the kitchen was open, accepting orders or already beyond its capacity. Customers browsed and ordered from restaurants that would reject them, and rejection arrived after payment.

Rider tooling that assumed connectivity

The rider app required a live connection for every action. In basements, lifts and dense buildings, marking a pickup or delivery simply failed, so riders retried at the next signal or called operations, and the customer's tracking view stalled at the last successful update.

Two mobile codebases drifting apart

Native iOS and Android builds were maintained by separate efforts. Features landed on one platform first and the other followed weeks later, so behaviour differed by device and every bug had to be diagnosed and fixed twice.

Delivery estimates with no basis

The promised time was a fixed figure applied to every order regardless of kitchen load, distance or time of day. It was routinely wrong in both directions, which trained customers to distrust it and gave riders no useful sequencing information.

Our solution

One order lifecycle every application renders, and mobile apps built to work when the network does not.

Order Lifecycle Design

Four weeks defining the order lifecycle as an explicit state machine with named states, permitted transitions and the actor allowed to trigger each one. Cancellation, rejection, partial availability and reassignment were modelled as first-class transitions rather than exceptions handled in support. Every later interface was built to render this model, never to maintain a parallel one.

Laravel Core and Event Distribution

The Laravel backend owns the state machine and rejects any transition not valid from the current state, which removed a whole class of race conditions between a restaurant accepting and a customer cancelling. Each committed transition emits an event that fans out over queues to push notifications and live socket channels, so all three applications learn about the change from the same source. Transitions are written to an append-only log rather than overwriting a status column, which means an order's full history is reconstructable and support can answer what happened without inference.

Restaurant Self-Service and Live Discovery

Restaurants manage menus, pricing, preparation times and item availability from their own dashboard, and mark themselves busy or closed directly. Those signals write into the Elasticsearch index that powers discovery, so a kitchen that pauses disappears from listings within seconds instead of continuing to take orders it cannot fulfil.

React Native Apps with an Offline Action Queue

Customer and rider apps share a React Native codebase across iOS and Android. Rider actions are written to a local queue with a client-generated identifier and replayed when connectivity returns, so a pickup recorded in a basement is not lost. The server treats those identifiers as idempotency keys, making a replayed action safe rather than duplicated. The queue preserves ordering per order, so a pickup recorded before a delivery cannot arrive reversed after a long outage, and the app surfaces pending actions to the rider so nothing sits silently unsent.

Technology stack

React Native Laravel PHP 8 MySQL 8 Elasticsearch Laravel Queues Redis WebSockets Push Notifications AWS ECS Fargate Amazon RDS Amazon SQS Amazon S3 Amazon CloudWatch CI/CD Pipeline

Results

Measured once all three applications were serving from the new order lifecycle.

0 p95 Status Propagation to All Parties
0 Crash-Free Sessions Across Both Platforms
0 Codebase Shipping to iOS and Android
0 Rider Actions Lost to Connectivity Gaps

Before and after: platform engineering measures

Before
  • Order status logic implemented separately in three applications
  • Menu and price changes relayed by phone to an operations team
  • Discovery listed restaurants by fixed radius regardless of state
  • Rider actions failed outright without connectivity
  • Separate native iOS and Android builds drifting apart
  • A single fixed delivery estimate applied to every order
  • Support reconciled conflicting statuses by phone
After
  • One server-side state machine every interface renders
  • Restaurants maintain menus, availability and prep times directly
  • Kitchen state writes to the index and gates discovery within seconds
  • Offline action queue with idempotent replay on reconnect
  • One React Native codebase shipping to both platforms together
  • Estimates derived from kitchen load, distance and time of day
  • Every transition carries an audit record with actor and timestamp

Project timeline

Weeks 1-4

Lifecycle Design and Research

Order state machine definition with permitted transitions and actors, restaurant and rider workflow observation, failure mode cataloguing from support records, and the target Laravel and React Native architecture.

Weeks 5-12

Backend Core and Event Distribution

Laravel state machine with transition guards, MySQL schema with append-only transition audit, queue-backed event fan-out, socket channels and push delivery, idempotency key handling, and the deployment pipeline on containerised AWS infrastructure.

Weeks 13-19

Restaurant Dashboard and Discovery

Self-service menu, pricing, availability and preparation time management, busy and closed controls, Elasticsearch index design with live kitchen state, geo-filtered discovery, and estimate calculation from load, distance and time of day.

Weeks 20-26

Customer and Rider Applications

React Native build for both platforms, live order tracking rendered from server state, rider offline action queue with replay, route guidance and proof-of-delivery capture, and accessibility work on the ordering and tracking journeys.

Weeks 27-30

Field Testing and City Rollout

Automated end-to-end tests covering every lifecycle transition, deliberate connectivity-loss testing with riders in the field, load testing on dinner-peak profiles, monitoring on transition latency and queue depth, then a city-by-city rollout.

Key takeaways

What shaped the engineering decisions

  • One state machine, rendered everywhere: Letting each client hold its own status logic was the root cause of the reconciliation work. Making the server the only authority on state, with transitions it can refuse, eliminated the disagreement rather than improving the sync between three versions of it.
  • Idempotency keys make offline safe: Retrying a queued rider action without a client-generated identifier risks double-marking a delivery. Treating that identifier as an idempotency key means a replayed action is recognised as the same action, so the queue can retry freely.
  • Let the kitchen gate discovery: A fixed serviceability radius was rejected because availability is a live property, not a geographic one. Writing busy and closed signals into the search index means a paused kitchen leaves the listings instead of accepting orders it will reject.
  • Give restaurants the controls: Routing menu changes through an operations team guaranteed a lag between reality and the catalogue. Self-service removed the intermediary and made the party with the information responsible for it.
  • Record transitions, do not overwrite status: An append-only transition log with actor and timestamp turned disputes into a lookup. It also made estimate calculation possible, because the data on how long each stage actually takes was finally being retained.
  • Test the network failing, not only the network working: Connectivity loss was scripted into the test plan and rehearsed with riders in real buildings, because the offline queue only earns trust if it has been proven against the conditions that motivated it.
Where this platform goes next. With every transition timestamped and retained, the platform now has an accurate record of how long each stage of an order really takes. The team is using it to sharpen delivery estimates per restaurant and time of day, to sequence rider assignments against kitchen readiness rather than order time, and to give restaurants operational reporting drawn from the same lifecycle data.

Want results like these?

Let's discuss how ELIVTECH can drive measurable outcomes for your business.

Start your project