Hello World

portfolio-img1

The global on-demand delivery market crossed $500 billion in 2024, and the platforms powering that growth are more technically demanding than ever. Whether you're building a grocery app, a dark kitchen ordering system, or a multi-vendor marketplace, the technology choices you make in year one will either accelerate or constrain you for the next decade.

In this article we'll break down the architectural decisions, technology selections, and implementation patterns that our engineering team has refined across 40+ delivery platform builds. We'll use real numbers from production deployments — not theoretical benchmarks.

The Core Challenge

Delivery platforms face a uniquely hostile performance environment. You have three concurrent audiences — customers, drivers, and merchants — each with different latency tolerances, data freshness requirements, and interaction patterns. A customer browsing menus can tolerate a 200ms page load. A driver receiving a new job assignment cannot tolerate a 30-second delay. A merchant watching their live order queue needs sub-second updates.

  • Real-time location tracking across thousands of concurrent drivers
  • Order state machines with complex branching logic and rollback scenarios
  • Multi-region database replication to minimise query latency
  • Payment processing with PCI-DSS compliance and fraud detection
  • Push notification delivery with guaranteed at-least-once semantics

Solution Architecture

After dozens of iterations, we've converged on a layered architecture that separates concerns cleanly while remaining operable by a team of four to eight engineers. The key insight is that not every service needs to be microserviced — premature decomposition creates operational overhead that kills velocity at small scale.

"The best architecture is one your team can fully understand, debug at 2am, and evolve without fear. Complexity is a liability, not a feature."
— Daniel Osei, Platform Architect at Crayola Digital

Implementation

Here's the core order state machine implementation pattern we use in Laravel, which handles the full lifecycle from placement through delivery confirmation with built-in rollback support:

// OrderStateMachine.php
class OrderStateMachine {
const TRANSITIONS = [
‘pending’ => [‘confirmed’, ‘cancelled’],
‘confirmed’ => [‘preparing’, ‘cancelled’],
‘preparing’ => [‘ready’, ‘failed’],
‘ready’ => [‘dispatched’],
‘dispatched’ => [‘delivered’, ‘failed’],
];
public function transition(Order $order, string $to): bool {
$allowed = self::TRANSITIONS[$order->status] ?? [];
if (!in_array($to, $allowed)) return false;
return DB::transaction(fn() => $order->update([‘status’ => $to]));
}
}

This pattern ensures that invalid state transitions are caught at the application layer before they ever hit the database, reducing the need for complex compensating transactions.

Results & Learnings

Across six client deployments using this architecture over the past 18 months, we've observed consistent improvements in both engineering velocity and platform reliability:

Uptime across all deployments

0 %

Average cost-per-delivery reduction

0 %

Faster feature delivery vs. monolith

0 x

The most consistent finding: teams that invest in a solid state machine and event bus in the first sprint ship twice as fast in months three through twelve. The upfront cost pays off within weeks.

Amir Hassan

Amir is Lead Flutter Engineer at Crayola Digital with 6+ years building cross-platform apps, recently focused on integrating LLM-powered UX into mobile products.

Share your thoughts

Have questions or feedback? We'd love to hear from the community.

Contents

Need help building your app?

We ship Flutter, Laravel, and AI-powered platforms end-to-end.

Ready to build your platform?

Our team ships production-grade delivery and AI apps. Let's talk about your project.