Skip to content
All case files
Case study — 01Mobility · 2024

Taxi Booking Platform

Rider, driver and dispatch — one realtime system

Role
Full Stack & Mobile Engineer
Timeline
2024
Stack
FlutterDartNode.jsPostgreSQLWebSocketsREST APIs
Taxi Booking Platform cover artwork

A local operator needed to move from phone-call dispatch to an app-based service without losing the control their staff had over the fleet. The answer was three coordinated clients on one realtime backbone.

Problem

Bookings arrived by phone, were written into a shared sheet, and were relayed to drivers by call. Under load, the process broke down in predictable ways:

  • No live picture of where drivers were or which were free.
  • Riders had no visibility — no ETA, no fare estimate, no trip history.
  • Dispatch decisions depended on one person's memory of the fleet.

Solution

Three clients on one platform: a rider app for booking and live tracking, a driver app for accepting and running trips, and a web dashboard giving operations a real map of the fleet. Fare estimation, trip state and notifications all flow through a single Node.js API, so every screen agrees on what is happening at any moment.

Architecture

Architecture — booking to completed trip

Clients

  • Rider app (Flutter)
  • Driver app (Flutter)
  • Ops dashboard (web)

API layer

  • Node.js REST API
  • WebSocket gateway
  • JWT auth

Core services

  • Trip lifecycle
  • Driver matching
  • Fare engine
  • Push notifications

Data

  • PostgreSQL
  • Geospatial queries
  • Trip event log

Trip state lives server-side as a small state machine (requested, assigned, en route, completed, cancelled). Clients subscribe over WebSockets and render whatever the server says — which eliminated a whole class of "my app shows something different" bugs.

Challenges

Location updates without draining batteries

Streaming driver GPS continuously killed devices in hours. The fix was adaptive: high-frequency updates only during an active trip, coarse updates while idle, and server-side interpolation so rider maps still feel live.

Assignment race conditions

Two dispatch paths could grab the same driver at once. Moving assignment into a single transactional operation in PostgreSQL — with row-level locking on the driver record — made double-booking structurally impossible rather than merely unlikely.

Flaky networks mid-trip

Trips continue when phones lose signal. Both apps queue state transitions locally and reconcile against the server's event log on reconnect, with the server as the single source of truth.

Technologies

  • Mobile — Flutter and Dart for both rider and driver apps from a shared core package.
  • Backend — Node.js REST API plus a WebSocket gateway for live trip and location events.
  • Data — PostgreSQL with geospatial queries for nearest-driver matching and a trip event log for auditability.
  • Delivery — Environment-based configs and versioned releases for the two store apps.

Screens

Taxi Booking Platform — screen 1
Screen 01
Taxi Booking Platform — screen 2
Screen 02

Lessons Learned

  • Realtime UX is a server-state problem first; the client is a projection of it.
  • Battery budget is a feature requirement, not an optimisation pass.
  • A boring, explicit state machine beats clever event handling every time a dispute needs to be replayed.

EOF — SANTHILA DEVIN

© 2026 Santhila Devin. All rights reserved.