Building a Real-Time Tracking Platform
Designing and evolving a backend platform capable of processing continuous GPS data while supporting real-time business logic, reporting, and notifications.
Before building, I needed to understand the system.
The platform processes continuous GPS data from vehicles and turns that stream into information the rest of the product can use: tracking, events, reports, notifications, and real-time updates.
When the new version of the platform started, the first challenge was not implementation. It was understanding how the existing product worked, how its modules were related, and what the new version would need to accomplish.
I spent the initial stage understanding the system functionally, testing its modules and relationships before working deeply with the code.
The challenge was not receiving GPS data. It was turning a continuous stream into a reliable product.
The previous version of the platform had a simpler processing model. The new version needed to support significantly more business logic while keeping the system responsive as the volume of tracking data grew.
A single tracking could trigger validation, calculations, event detection, persistence, state updates, reports, and real-time notifications.
That meant architectural decisions could not be made around one isolated operation. They had to consider the complete processing flow and how each component affected the rest of the system.
Tracking data arrives continuously rather than as isolated requests.
Processing evolved from basic tracking delivery to event detection, calculations, and business rules.
Reports, notifications, and updates needed to be available without relying on overnight processing.
The architecture needed to support new functionality without making every change increasingly expensive.
I helped turn the new backend into the foundation for the next version of the platform.
I joined the initial development of the new version and worked mainly on the .NET backend, from service structure and data modeling to business logic and high-throughput processing.
Rather than reproducing the previous system exactly, I worked with the team to understand what the new platform needed and adapted the architecture and implementation to those requirements.
Created and structured .NET services according to the responsibilities and requirements of each part of the platform.
Designed data models and relationships, including the use of PostgreSQL, MongoDB, and Redis for different system needs.
Developed and evolved the processing flow responsible for validation, calculations, event detection, persistence, and downstream actions.
Worked with gRPC, RabbitMQ, and real-time communication to connect processing services with the rest of the platform.
Investigated processing time, database workload, memory usage, expensive operations, and resource consumption as the platform grew.
Participated in decisions about service responsibilities, architecture, implementation approaches, and how new functionality should fit into the system.
Different responsibilities required different tools.
The platform was designed as a group of services with different responsibilities. The goal was not to introduce technology for its own sake, but to use each component where it made sense for the problem being solved.
Store processed information and maintain the state required by the platform.
Send relevant updates to the web and mobile applications.
Used for relational and persistent information where relationships and structured data were important.
Used for tracking-oriented information where a document model suited the access patterns.
Used where fast access to frequently needed state could reduce unnecessary work against persistent storage.
Architecture was shaped by the problem, not by the technology.
The goal was not to introduce technology for its own sake. Each architectural decision had to respond to a real requirement, workload, or future need of the platform.
Services were structured around responsibilities and requirements, rather than splitting the platform into services simply for the sake of having more microservices.
PostgreSQL, MongoDB, and Redis were used for different types of data and access needs instead of forcing every workload into the same storage model.
RabbitMQ was used where work could be decoupled from the main processing flow, allowing services to communicate without making every operation depend on a synchronous response.
gRPC was used for internal communication where structured and efficient service-to-service calls were appropriate.
Not every problem needed a sophisticated solution. The approach was to introduce complexity where it provided a clear benefit, while keeping simpler parts of the system simple.
High throughput makes small inefficiencies expensive.
As the amount of tracking data increased, performance could not be treated as a single metric. Processing time, database workload, memory consumption, and expensive operations all affected the system's ability to keep up with the incoming workload.
The objective was not simply to make individual operations faster. It was to reduce unnecessary work across the complete processing flow while preserving the same business result.
Understand the complete processing flow and where each operation fits into the system.
Look at processing time, resource consumption, database activity, allocations, and memory behavior.
Identify where the actual cost was coming from instead of optimizing based on assumptions.
Separate expensive calculations, database operations, transformations, and memory-heavy paths.
Reduce unnecessary database queries, expensive operations, object sizes, and repeated work where appropriate.
Verify that the optimized flow continued producing the same business result under realistic workloads.
tracking events processed per second
with less unnecessary work and resource consumption
reducing pressure on processing, databases, and infrastructure
The new platform became the foundation for the next stage of the product.
The new version was launched and progressively adopted across Mexico, Colombia, and the United States. The platform supported the migration of users from the previous version while introducing capabilities that were not available in the original system.
The result was not only a newer backend. It was a platform capable of processing tracking data in real time, generating reports, detecting events, and triggering notifications as part of the normal processing flow.
Tracking information, events, reports, and notifications became part of a real-time processing model.
The new platform was deployed for operations in Mexico, Colombia, and the United States.
The backend evolved to handle workloads reaching approximately 7,000–8,000 tracking events per second.
Processing and memory optimizations reduced unnecessary resource consumption and the infrastructure required to support the platform.
The platform introduced functionality such as route tracking, real-time reports, configurable notifications, trips, and additional operational features.
The architecture provided a foundation where new business requirements could be incorporated without rebuilding the platform around every change.
The hardest part was not building the system. It was understanding it well enough to make it evolve.
Working on a system that processes continuous data at high volume changed the way I think about backend engineering. Performance, architecture, data, and business logic cannot be treated as isolated concerns when they are part of the same processing flow.
I also learned that understanding the existing system is not time spent before development. It is part of development itself. The better I understand the problem and its context, the more confident I can be about the solution and the trade-offs behind it.