All case studies
Mobility & Trip Management· 9 min read

Building MURI

How I architected a multi-role transportation platform with geospatial routing, real-time trip tracking, and package-based subscription management — deployed and live at muri.sa.

Live PlatformRole: Backend Engineer & Team Lead · ASAS IT

01The Problem

Threeusertypes.Onecoherentsystem.

Transportation platforms look simple on the surface — a passenger books, a driver accepts, the trip happens. The complexity is in the seams: how do you give three completely different user types — clients, drivers, and administrators — a single backend that enforces the right rules for each without tangling the logic?

MURI added a further dimension: subscription packages. Clients don't pay per trip — they buy packages. This means trip availability is gated by subscription state, expiry, and remaining quota — all of which must be checked atomically to avoid race conditions when two requests arrive simultaneously.

And throughout, the system needs to answer geographic questions in real time: which drivers are within range? What regions are serviced? What is the estimated route? A plain latitude/longitude column in PostgreSQL cannot answer these efficiently at scale.

Core requirements

  • Isolated permission scopes for clients, drivers, and administrators
  • Geospatial queries for driver availability and region management
  • Subscription-gated trip booking with atomic quota checks
  • Real-time trip status pushed to both client and driver without polling
  • Full Arabic and English localization across all user-facing content

02Architecture

Fivelayers.Role-awareateverylevel.

The system is organized into modular Django apps — one per role and concern — sharing a single PostGIS-enabled database with a clear async layer for tasks and real-time updates.

Client · Driver · Admin Apps

Role-based entry points with separate permission scopes

Django REST API

Business logic, authentication (Knox), data validation

PostGIS + PostgreSQL

Geospatial routing, region management, trip records

Redis + Celery

Message broker, async task queue, hot-path caching

+ AWS S3

WebSocket Layer

Real-time trip tracking pushed to client and driver apps

AWS S3 (async)

Media storage — driver documents, profile images — handled as Celery tasks, never blocking the request cycle

03Key Decisions

Whatwechoseandwhy.

01

PostGIS over plain lat/lng columns

Storing coordinates as two float columns works until you need to query 'find all drivers within 5km'. That query becomes a full table scan with manual Haversine math. PostGIS gives us native spatial indexes, proximity queries in a single SQL call, and region polygon support — all without a separate geospatial service.

02

Modular app structure by role, not by feature

The alternative — a single 'users' model with a role field — leads to spaghetti permissions. Separating client, driver, and administrator into distinct Django apps meant each had its own serializers, viewsets, and permission classes. Onboarding a new role never touches existing code.

03

WebSocket push for trip tracking

Polling every 2 seconds for driver location means 30 requests per minute per active trip. At modest scale this becomes expensive. WebSocket connections stay open for the duration of the trip, pushing location updates server-side. Driver location is updated via Celery → Redis → WebSocket channel group.

04

Atomic subscription quota checks with Redis locks

When two concurrent requests try to book the last trip in a subscription package, a naive check-then-decrement approach creates a race condition. Redis distributed locks ensure the quota check and decrement happen atomically — one request wins, the other gets a clear 'quota exhausted' response.

04Outcomes

Asystembuilttoscalewiththemarket.

3

User roles in one system

Client · Driver · Admin — fully isolated permissions

PostGIS

Geospatial engine

Region-aware routing with native geo-query performance

<1s

Trip status update delivery

WebSocket push vs. polling

2

Languages supported

Full Arabic and English localization (i18n)

05Challenges & Lessons

Whatmadethishard.

Geospatial complexity

PostGIS documentation is dense. Getting spatial indexes right for proximity queries took iteration — the wrong index type caused slow queries under load that only surfaced in staging.

Real-time consistency

Keeping trip state in sync between client, driver, and admin views required careful ordering of WebSocket events. We built an event log to replay missed updates on reconnection.

Permission surface area

Multi-role systems have a large permission surface. We built a custom permission matrix tested with over 50 test cases covering edge conditions — an admin shouldn't be able to create a trip as a client.

Next

Read the Hayyak case study

How I integrated Opera PMS and dual payment gateways into a multi-tenant hotel system.