Skip to main content
Ahmed Salama

Transportation & mobility

Al-Ouf Transportation System

The in-house platform of one of Egypt’s largest transport operators, carrying 100,000 to 200,000 daily active users across five live surfaces for major corporates and schools.

Scale
100,000 to 200,000 daily active users
3,000 to 5,000 transportation trips per day
Figure supplied by the site owner

Context

Al-Ouf is one of the largest transportation companies in Egypt, and this is its own platform rather than a ride-booking app it lists on. Al-Ouf is the operator, not the marketplace. Major corporates and schools contract with it to move their employees and students on agreed routes, and Al-Ouf runs the whole of it, in the application and on the ground, across a shared fleet of vehicles and drivers. Its users are drivers, riders, the administrators inside the contracting organisations, and Al-Ouf’s own operations team, working across four client surfaces and the modular backend behind them. The system is in production and carries between 100,000 and 200,000 daily active users.

The problem

Organisations that move people at scale hit a modelling problem generic booking software does not address: a route is a recurring commitment, a trip is one execution of it, and a system that models only one of the two cannot answer which of today's trips is late. The organisations contracting for transport also want structurally different things from it, a standing route or a fixed destination or an individual reservation or a one-off special request, while sharing one fleet, one operations team and one platform. Without live operational state, dispatch falls back to phone calls, which do not scale at 3,000 to 5,000 trips a day. Trip state only becomes real when a driver marks it, and the driver is on a phone, on a road, on an unreliable network.

The solution

The platform unifies transportation rules, routes, drivers, vehicles, riders, corporate clients, schools, reservations, tracking, driver HR workflows and real-time operations into one operating system. Its core is a transportation engine carrying four routing models rather than one: fixed route, fixed destination, reservation and special request, all on the same codebase. The special request is the only one that does not simply dispatch. It clears the contracting organisation first and Al-Ouf second, so an ad-hoc trip is a two-stage approval before it is ever a trip. Five coordinated surfaces sit on top: a driver app that executes trips and reports state and location, a rider app for schedules and trip tracking, an admin dashboard that runs the whole ecosystem, a corporate dashboard for client self-service, and the backend behind them. The two apps are Flutter, the two dashboards are Next.js with TypeScript and TanStack, and the backend is a modular monolith: transportation rules, real-time tracking, notification delivery and one-time passcode handling are separate modules inside one Laravel deployment, each owning its own database, with a queue for work that must not sit on a request and a cache in front of the reads that repeat.

Architecture

The backend is a modular monolith: one Laravel 12 deployment running on Octane on an Amazon EKS cluster, divided internally into modules for transportation rules, real-time tracking, notification delivery and one-time passcode handling, with each module owning its own database rather than sharing one schema. That second half is what makes the first half hold. A module boundary enforced only by folder structure erodes the first time somebody writes a query that joins across it; a boundary enforced at the database cannot be crossed that way, so a module can later be lifted into its own service as a deployment change rather than a data migration. The system is built to become microservices without being run as microservices today, which keeps the operating cost of a distributed system off a platform whose real load arrives in two narrow windows a day. A queue carries deferred work and a cache fronts the reads that repeat. Reaching a person splits three ways, and each way is a different piece of infrastructure. Live state travels over WebSockets through Laravel Reverb, which is what lets a driver marking a trip at the roadside appear on an operations dashboard without anything polling for it. Firebase pushes to a phone whose app is closed, the case Reverb cannot serve because there is no socket to write to. SMS Masr carries whatever has to arrive as text regardless of whether the app is installed at all. Every module stores in PostgreSQL, in its own database. On the client side, the driver and rider apps are Flutter and Dart, and both dashboards are Next.js with TypeScript, using TanStack Query, Table and Form. Every box in the diagram is a component that exists: a diagram is a set of claims, and an unsupported box is the weakest place to start a technical conversation. Writes converge on a single API rather than each surface holding its own logic, because the transportation model is per-organisation and must resolve in one place. Reads split in two: request/response through the API, and a push path where Reverb fans trip and location state out to the dashboards and the rider app. The driver app is both the heaviest writer and the authoritative source of trip state, which is what makes the write path the interesting half of the diagram. Redis fronts the repeated reads and the queue runs on the database rather than a dedicated broker, which is the cheaper choice and the one that puts queue load on the same machine the reads already contend for.

System diagram: Al-Ouf Transportation System topologyWebSocket server pushing live trip and location state to all three watching surfaces, the admin dashboard, the client dashboard and the rider app, so operational state arrives without anything polling for it. A transport rather than a module, which is why no database hangs off it.SERVICELaravel ReverbFlutter app where employees and students see schedules, assigned routes, reservations and notifications, and track their trip live.CLIENTRider AppNext.js dashboard where platform operators run the whole ecosystem: companies, schools, riders, drivers, vehicles, routes, trips, reservations and live operational monitoring.CLIENTAdmin DashboardNext.js dashboard for the contracting organisations, corporates and schools alike: statistics and reporting on their own transport, and adding their people to the contracts and routes they hold.CLIENTClient dashboardThe modular monolith itself, one deployment running on Octane. Single entry point for all four surfaces: accepts trip state and location writes, serves the operational reads and routes work to the modules inside it.SERVICELaravel 12 APIIssues and verifies the one-time passcodes drivers and riders sign in with, handing each one to the SMS gateway for delivery.SERVICEOTP moduleThe module resolving the four routing models (fixed route, fixed destination, reservation, special request) over routes, trips, riders, drivers and vehicles, including the two-stage approval a special request has to clear.SERVICETransportation RulesCarries the work that must not run inside a request, notification fan-out among it. Jobs sit in the database rather than a dedicated broker.QUEUEDatabase queueFronts the reads that repeat, which at peak is most of them, since a whole organisation loads the same schedules in the same narrow window.CACHERedisThe module composing and dispatching notifications off the request path, handing anything bound for SMS or push to its gateway.SERVICENotificationsThe transportation module’s own PostgreSQL database: the domain chain from companies through routes, trips and reservations to tracking history.DATATransport DBThe passcode module’s own PostgreSQL database, holding issued codes and their state.DATAOTP DBCarries push notifications to both mobile apps, drivers and riders alike, covering the case Reverb cannot: a phone with no socket open.EXTERNALFirebaseThird-party SMS gateway that carries the messages leaving the platform as text.EXTERNALSMS MasrThe notification module’s own PostgreSQL database. Separate from the transport database, so a notification cannot be resolved by joining onto a trip.DATANotifications DBFlutter app where drivers execute assigned trips, moving trip state through its lifecycle and reporting location continuously from the road, and receiving push when something changes.DEVICEDriver Applocation + trip stateschedules,reservationsoperations +configurationreporting, rostersign-in passcodespasscode deliveryapply transportationmodelread / writeread / writeread / writerepeated readsdeferred workdispatchpublish state changetrip trackinglive operationslive operationsSMS deliverypush deliverypushpush
Read this diagram as text
Laravel ReverbService
WebSocket server pushing live trip and location state to all three watching surfaces, the admin dashboard, the client dashboard and the rider app, so operational state arrives without anything polling for it. A transport rather than a module, which is why no database hangs off it.
Rider AppClient
Flutter app where employees and students see schedules, assigned routes, reservations and notifications, and track their trip live.
Admin DashboardClient
Next.js dashboard where platform operators run the whole ecosystem: companies, schools, riders, drivers, vehicles, routes, trips, reservations and live operational monitoring.
Client dashboardClient
Next.js dashboard for the contracting organisations, corporates and schools alike: statistics and reporting on their own transport, and adding their people to the contracts and routes they hold.
Laravel 12 APIService
The modular monolith itself, one deployment running on Octane. Single entry point for all four surfaces: accepts trip state and location writes, serves the operational reads and routes work to the modules inside it.
OTP moduleService
Issues and verifies the one-time passcodes drivers and riders sign in with, handing each one to the SMS gateway for delivery.
Transportation RulesService
The module resolving the four routing models (fixed route, fixed destination, reservation, special request) over routes, trips, riders, drivers and vehicles, including the two-stage approval a special request has to clear.
Database queueQueue
Carries the work that must not run inside a request, notification fan-out among it. Jobs sit in the database rather than a dedicated broker.
RedisCache
Fronts the reads that repeat, which at peak is most of them, since a whole organisation loads the same schedules in the same narrow window.
NotificationsService
The module composing and dispatching notifications off the request path, handing anything bound for SMS or push to its gateway.
Transport DBData
The transportation module’s own PostgreSQL database: the domain chain from companies through routes, trips and reservations to tracking history.
OTP DBData
The passcode module’s own PostgreSQL database, holding issued codes and their state.
FirebaseExternal
Carries push notifications to both mobile apps, drivers and riders alike, covering the case Reverb cannot: a phone with no socket open.
SMS MasrExternal
Third-party SMS gateway that carries the messages leaving the platform as text.
Notifications DBData
The notification module’s own PostgreSQL database. Separate from the transport database, so a notification cannot be resolved by joining onto a trip.
Driver AppDevice
Flutter app where drivers execute assigned trips, moving trip state through its lifecycle and reporting location continuously from the road, and receiving push when something changes.

Connections

  • Driver App → Laravel 12 API (location + trip state)
  • Rider App → Laravel 12 API (schedules, reservations)
  • Admin Dashboard → Laravel 12 API (operations + configuration)
  • Client dashboard → Laravel 12 API (reporting, roster)
  • Laravel 12 API → OTP module (sign-in passcodes)
  • OTP module → SMS Masr (passcode delivery)
  • Laravel 12 API → Transportation Rules (apply transportation model)
  • Transportation Rules → Transport DB (read / write)
  • OTP module → OTP DB (read / write)
  • Notifications → Notifications DB (read / write)
  • Laravel 12 API → Redis (repeated reads)
  • Laravel 12 API → Database queue (deferred work)
  • Database queue → Notifications (dispatch)
  • Laravel 12 API → Laravel Reverb (publish state change)
  • Laravel Reverb → Rider App (trip tracking)
  • Laravel Reverb → Admin Dashboard (live operations)
  • Laravel Reverb → Client dashboard (live operations)
  • Notifications → SMS Masr (SMS delivery)
  • Notifications → Firebase (push delivery)
  • Firebase → Rider App (push)
  • Firebase → Driver App (push)

What makes it interesting

The parts a system like this is actually judged on.

  • Routes and trips are separate models rather than one booking object: a route is a recurring commitment, a trip is one execution of it, and keeping them distinct is what lets the system answer questions about today without replaying the schedule.
  • Five surfaces read and write one live operational state at the same time: a driver changing trip status on a phone is a state change an operations team is watching on a dashboard.
  • Four routing models run on one codebase, and they are not variations on a theme. A fixed route is a standing commitment. A fixed destination pins one end of the journey and leaves the other open. A reservation is a rider claiming a seat on a specific day. A special request is an exception that has to be approved twice before it exists as a trip at all. The engine resolves all four over the same routes, trips, riders, drivers and vehicles.
  • A special request crosses an organisational boundary before it crosses an operational one: the contracting organisation approves it, then Al-Ouf accepts or rejects it against the capacity it actually has. Approval is a state in the trip lifecycle rather than a setting somewhere, and a request can die at either end for entirely unrelated reasons, one about entitlement and one about whether a vehicle exists.
  • Trip data is high-cardinality and time-bounded: at 3,000 to 5,000 trips a day a year of operations is roughly 1.1 to 1.8 million trip records, each with associated riders, reservations and location history, while the queries that matter most only ever touch today.
  • Peak concentration is what makes the backend split earn its cost: corporate and school transport spike into the same two narrow windows, and putting notification fan-out behind a queue and repeated schedule reads behind a cache is what stops either from competing with the location writes arriving from every moving vehicle at that exact moment. Octane keeps the framework resident between requests instead of rebuilding it on each one, and because the load arrives as one deployment rather than a fleet, the EKS cluster answers the window by running more copies of the same thing.
  • A database per module is a bet about the future shape of the system rather than a convenience today. It costs the ability to join across modules, which is the very thing that makes a boundary erode, and buys the option to extract a module without first untangling one schema into several. The platform is run as one deployment and designed to stop being one.

Technical decisions

A modular monolith with a database per module, rather than microservices.
Microservices buy independent deployment and independent scaling, and charge a distributed system for it: network calls where method calls used to be, partial failure as a normal condition, and a pipeline per service. A platform whose load arrives in two narrow windows a day gets more out of running more copies of one deployment than out of splitting it into many. The database-per-module rule is what stops that from being a decision nobody can revisit later: the boundary that normally erodes first is a query joining two modules together, and it cannot be written when the tables sit in different databases, so extracting a module becomes a deployment change instead of a data migration.

Engineering challenges

  • Real-time state at scale: continuous location and trip state arrive from every active driver device and fan out to many dashboards watching many trips at once.
  • Four routing models on one platform: fixed route, fixed destination, reservation and special request must coexist without forking the codebase.
  • Mobile/backend synchronisation: the driver app is the authoritative source of trip state but runs on an unreliable network.
  • Peak concentration: corporate and school transport both peak hard at the start and end of the day, so capacity is set by two narrow windows rather than the daily average.
  • Client separation: every contracting organisation shares one fleet, one driver pool and one platform, and none of them may see another’s people, routes or trips.
  • Trip data growth: trip and location history grows continuously while the operationally important queries stay focused on the current day.
  • Production stability: an outage during the morning window strands people.
  • Sensitive data obligations: the platform carries real-time location of identified individuals, including children in school transport, alongside rider personal data and driver HR records.

Integrations

  • Laravel Reverb: WebSocket server carrying live trip and location state to the dashboards and the rider app
  • Firebase: push notification delivery to the mobile apps
  • SMS Masr: SMS gateway carrying sign-in passcodes and any other message leaving the platform as text
  • Mapping and navigation provider: integrated for the map and navigation surfaces; which product, and whether it serves driver navigation, geocoding or map rendering, is not recorded

Technology

  • Laravel 12
  • Laravel Octane
  • Laravel Reverb
  • PostgreSQL
  • Redis
  • Firebase
  • Flutter
  • Dart
  • TypeScript
  • Next.js
  • TanStack Query
  • TanStack Table
  • TanStack Form
  • AWS
  • Amazon EKS
  • SMS Masr
  • Docker

These are the projects my confidentiality agreements allow me to publish, so this is a subset of the work rather than all of it. Every one of them comes from a full-time role, and I was on the project from its start through to its end. Freelance and consulting engagements are not published here.

The write-ups still describe systems rather than individual credit. Where the source material does not establish who did what inside a team, a case study says nothing rather than implying credit it cannot support.

Let’s talk

Have a product, platform or delivery challenge? Let’s talk about turning it into a structured, scalable solution.

Open to technical leadership, product delivery and senior engineering roles, and available for architecture consulting, technical reviews and mentorship. Engagements run as project-based work, contracts, consulting, freelance engagements, remote collaboration and long-term partnerships.

Based in Cairo, Egypt, working remotely with clients across the MENA region and internationally.

Also on LinkedIn (opens in a new tab)