Fleet Management Platform

A logistics company running a fleet-tracking application came to us stuck with an aging, monolithic system that made even small updates risky and slow. We modernized their infrastructure by breaking the application into containerized microservices, which meant deployments no longer meant taking the whole platform down. What used to be a multi-hour update window turned into something the team could push out in minutes, without dispatchers and drivers losing access mid-shift.

The Challenge

The fleet-tracking system had been built years earlier as one large application, and by the time we got involved, the cracks were hard to ignore:

  • Even a minor bug fix required redeploying the entire application, which meant scheduled downtime and advance notice to dispatch teams
  • A bug in one part of the system, like the driver notification module, could bring down unrelated features like live GPS tracking, since everything ran as one unit
  • Developers had to test against the entire codebase for even small changes, which slowed down how fast new features could ship
  • GPS tracking needed extra server capacity during peak hours, but since the app couldn’t scale in parts, the whole thing had to be scaled up — wasting resources on features that didn’t need it

The client didn’t want a full rewrite. The fleet-tracking logic itself worked fine — it was the architecture underneath that was holding them back.

Our Solution

Rather than rebuild from scratch, we took an incremental approach to breaking the monolith apart. First, we mapped out logical boundaries in the existing application — GPS tracking, driver notifications, route history, and reporting could each stand on their own as separate services. We containerized each one using Docker so they could be deployed, updated, and scaled independently.

Migration happened one service at a time, starting with reporting since it was the lowest-risk piece, and working up to GPS tracking last, once we’d confirmed the approach held up in production without issues.

The database ended up being the harder part of the project. The original system had a single shared database that every part of the application read and wrote to directly, so separating services meant untangling which service actually owned which data — without breaking historical reports that dispatch managers pulled from daily. A few edge cases around older trip records took extra work to sort out, since some of that data didn’t cleanly map to a single service.

We also set up per-service monitoring using Prometheus, with alerts routed to the team’s Slack, so if the notification service started failing, it would get flagged within minutes instead of someone noticing only after drivers started calling in.

Results

Deployment time for routine updates dropped from several hours with scheduled downtime to under 15 minutes, with most releases now going out without any downtime at all. A failure in one service, like a delay in the notification module, no longer risked taking down GPS tracking or other features. The team could also scale GPS tracking on its own during peak dispatch hours instead of over-provisioning the entire application, which cut server costs during quieter periods. Overall, the dev team went from shipping updates every couple of weeks to almost twice that pace.

One thing that’s still a work in progress: the reporting service occasionally needs manual reconciliation against older historical data that hadn’t fully migrated over, since some legacy trip records predate the service split. The team is working through backfilling that data gradually rather than migrating it all at once.

Tech stack we used

AI & automation solutions

Frontend: ReactJs

Backend: NodeJs

Mobile: Flutter

Database & infrastructure

Database: MongoDB & Redis

Cloud/Hosting: AWS

Other Tools/Integrations: Flolive