TechVisionar
Start a Project
Back to Case Studies

Case Study · Online Taxi / Mobility

RideOn™ — Fixed-Fare Online Taxi Platform, Saudi Arabia

2+ Platforms (iOS & Android) from one codebase

<20ms Fare Calculation Latency

2 Live Cities at Launch

0× Surge Pricing — Always Fixed

Client:RideOn™
Market:Saudi Arabia (Makkah, Madinah)
Platform:iOS & Android (Hybrid)
Mobile DevelopmentBackend EngineeringReal-Time Infrastructure

The Brief

RideOn™ needed a taxi platform for the holiest cities in Saudi Arabia — Makkah and Madinah — where passengers always know their exact fare before booking. No surge pricing. No dynamic adjustments. A confirmed fare that never changes.

The environment makes this uniquely challenging:

  • Hajj and Umrah seasons bring millions of visitors in short windows, creating intense demand spikes
  • International users from 180+ countries — multilingual, unfamiliar with local pricing norms
  • Congested mobile networks near holy sites where WebSocket connections drop frequently
  • Two separate user types (riders and drivers) requiring distinct app experiences

Requirements: real-time driver location tracking, instant fare calculation from geofenced zones, and reliable booking on poor networks — all from a single development team.

Four Problems We Had to Solve

1. Surge Pricing Erodes Trust

Dynamic pricing during peak periods punishes the users who need the service most. Pilgrims near the Masjid Al-Haram can't shop around — they need a ride, and they need to know what it costs. We needed a pricing model that felt fair regardless of demand.

2. Network Congestion Near Holy Sites

Standard WebSocket connections drop silently when phones switch towers in dense crowds. A dropped connection in a ride-hailing app means missed location updates, broken booking state, and frustrated users. We needed a communication layer that survives network interruptions.

3. International, Multilingual Users

Users from 180+ countries means the app must work fluently in Arabic (RTL) and English (LTR) — not as an afterthought, but as a first-class concern. Arabic numerals, right-to-left layouts, and culturally appropriate formatting throughout.

4. Two Apps, One Team

Building and maintaining four separate native codebases (Rider iOS, Rider Android, Driver iOS, Driver Android) was not viable. We needed a shared codebase approach that still delivered a native-quality experience on each platform.

How We Solved It

Zone-Based Fixed Fare Engine

We divided Makkah and Madinah into geofenced zones using GeoJSON polygons stored in MongoDB with 2dsphere indexing. A pre-computed fare matrix maps every origin-destination zone pair to a fixed SAR amount, cached in Redis for sub-20ms lookups.

When a passenger enters their destination, the app resolves both coordinates to zones, fetches the fare from Redis, and displays it instantly. Once the passenger confirms, the fare is locked immutably to the booking. No driver or system action can change it.

MQTT for Resilient Real-Time

We replaced the conventional WebSocket approach with MQTT — a protocol designed for unreliable mobile connections. MQTT's QoS Level 1 guarantees at-least-once delivery and maintains persistent sessions through network interruptions. When a driver's phone reconnects after a signal drop, all missed events are delivered automatically.

Drivers publish their location every 3 seconds. The MQTT broker routes updates with QoS 1 to the NestJS API, which updates Redis and pushes the update to the rider's app. The entire chain survives dropped connections on either end.

React Native Shared Codebase

All four app targets (Rider iOS, Rider Android, Driver iOS, Driver Android) are built from a single React Native codebase. Build-time flags and context providers determine which flow the app renders at startup. Shared components — maps, booking cards, fare display, chat — live in a common library.

RTL/LTR support is handled via React Native's built-in I18nManager with locale detection at startup. Arabic and English are both first-class locales, not translations bolted on afterward.

System Architecture

RideOn System Architecture — Client apps, NestJS API Gateway, and Data layer

Booking State Machine

Every booking moves through a defined state machine:

REQUESTED → ACCEPTED → DRIVER EN ROUTE → IN TRIP → COMPLETED

Each state transition triggers an MQTT event that updates both the rider and driver apps in real time. The booking state is persisted in MongoDB with a Redis cache layer for active trips.

Fare Engine Deep Dive

Algorithm:

  1. Resolve pickup GPS coordinate → zone (MongoDB $geoIntersects query)
  2. Resolve destination GPS coordinate → zone
  3. Look up fare:{zoneA}:{zoneB} key in Redis
  4. Return confirmed fare in SAR to the client
async calculateFare(pickup: Coordinates, dropoff: Coordinates): Promise<number> {
  const pickupZone = await this.zoneModel.findOne({
    boundary: { $geoIntersects: { $geometry: { type: 'Point', coordinates: [pickup.lng, pickup.lat] } } }
  });
  const dropZone = await this.zoneModel.findOne({
    boundary: { $geoIntersects: { $geometry: { type: 'Point', coordinates: [dropoff.lng, dropoff.lat] } } }
  });

  const fareKey = `fare:${pickupZone.id}:${dropZone.id}`;
  const cached  = await this.redis.get(fareKey);
  return cached ? parseInt(cached) : await this.computeAndCache(pickupZone.id, dropZone.id);
}

Sample Fare Table (SAR):

| From | To | Fare | |------|----|------| | Masjid Al-Haram Precinct | Mina | 25 SAR | | Masjid Al-Haram Precinct | Aziziyah | 35 SAR | | Arafat | Muzdalifah | 15 SAR | | King Abdulaziz Airport | Masjid Al-Haram Precinct | 55 SAR |

Redis Key Structure

| Key Pattern | Purpose | TTL | |-------------|---------|-----| | session:{userId} | Auth session | 24h | | otp:{phone} | OTP verification | 5 min | | driver:loc:{id} | Driver location | 30s | | fare:{zoneA}:{zoneB} | Fare cache | 1h | | booking:{id}:status | Active booking state | Trip duration |

Project Timeline

| Phase | Scope | |-------|-------| | Discovery & Architecture | Zone mapping, fare matrix design, system architecture | | Core Backend | NestJS API, fare engine, MQTT infrastructure, Redis setup | | Mobile Development | React Native apps, RTL/LTR, maps integration, booking flows | | QA & Load Testing | Performance testing, network degradation simulation, UAT | | Launch & Support | Staged rollout in Makkah then Madinah, ongoing monitoring |

Outcomes

Zero Surge Pricing — Fares are locked at booking confirmation. No passenger has ever paid more than the fare they saw upfront.

Resilient Real-Time Dispatch — MQTT ensures driver location updates are delivered even through network interruptions common near holy sites.

Four App Targets, One Codebase — Approximately 60% reduction in ongoing maintenance overhead compared to maintaining separate native codebases.

Sub-20ms Fare Responses — Redis-backed fare lookups return in under 20ms, enabling instant fare display in the UI.

RTL + LTR Dual Locale — Arabic and English are both fully supported with correct bidirectional layout, numerals, and formatting.

Scalable for Peak Season — Stateless NestJS API, clustered Redis, and MQTT broker designed to handle Hajj-scale load spikes.

Client Testimonial

"The fixed fare feature was our entire value proposition. We needed passengers to trust the platform before they even got in the car — and that meant they had to know their fare before they confirmed. Techvisionar built exactly what we described, and they understood why it mattered. Passengers know their fare before they book, and that builds the kind of trust a new platform needs."

RideOn™ Founding Team, Makkah, Saudi Arabia


Building something like this? Start a conversation →

Building Something Like This?

Tell us about your project and we'll put together a tailored proposal.

Start a Project →