Skip to content
Seifeldin Ali

Amana for Ghost Burgers · 2025, actively developed

Amana

Three-sided delivery logistics platform: a REST API, web dashboard, and native rider app in one monorepo.

Built + maintained by Iano

Visit live site ↗

1 / 10

Summary

Amana is a three-sided delivery logistics platform connecting restaurants, riders, and customers, delivered as a single monorepo with a Node.js/Express API, a Next.js admin dashboard, and a React Native (Expo) rider app. It runs real-time order and rider tracking over WebSockets, takes payments through M-Pesa, and handles routing via Google Maps, all deployable as a containerized stack.

Context

A delivery operation needed one connected system covering order intake, dispatch, live rider tracking, payments, and admin oversight, instead of stitching together separate restaurant, rider, and back-office tools.

Role & team

Iano, a two-person marketing agency I co-founded. Both founders engineered the build.

Stack

  • Express
  • Socket.IO
  • Mongoose / MongoDB 7
  • Redis 7
  • Next.js 16
  • React 19
  • Tailwind CSS 4
  • Zustand
  • React Native 0.83
  • Expo 55
  • Expo Router
  • M-Pesa (Safaricom Daraja)
  • Google Maps Platform
  • Cloudinary
  • Turborepo + pnpm workspaces
  • Docker
  • PM2
  • Nginx
  • GitHub Actions

Key decisions

  1. Chose a Turborepo monorepo over separate repos so the API, dashboard, rider app, and shared validation/config evolve together with shared schemas (`packages/shared`).
  2. Chose Socket.IO over polling to power real-time order status and rider location updates.
  3. Chose M-Pesa (Daraja) STK-push as the payment rail, matching the Kenyan market.
  4. Chose a native React Native rider app over a mobile web view for reliable background location, notifications, and on-the-road performance.

Architecture

Three apps sit under `apps/`: an Express REST + WebSocket API (`config`, `middleware`, `models`, `routes`, `services`, `socket`, scheduled `jobs`), a Next.js admin dashboard, and an Expo rider app (Zustand stores, location/notification/socket services), alongside shared `packages/`. MongoDB is the primary store with Redis for caching; real-time events flow through Socket.IO; payments via M-Pesa STK-push with a callback endpoint; geocoding/directions via Google Maps; media via Cloudinary; JWT access/refresh auth with OTP verification. Deploy: API on PM2 + Nginx, dashboard via Docker, mobile via EAS build/submit.

Challenges

  • Coordinating three runtimes in one codebase: Solved with Turborepo + pnpm workspaces and shared validation/config packages.
  • Real-time, role-aware data flow: Orders, riders, and admin each see the right live view, scoped by role through the API and Socket.IO channels.