Architecting Real-Time Fleet & Driver GPS Tracking with React Native, WebSockets & Supabase RLS
For nearly two years, I served as the sole engineer for Direct Transport Solutions in Australia, designing and shipping their core logistics ecosystem: an internal Admin Dispatch Portal, a Customer Portal, and an iOS/Android Driver App in React Native. Here is how the real-time GPS tracking and multi-tenant security architecture works in production.
Full-Stack Product Engineer · Full-Stack Engineer @ Callture
Key architectural takeaways (TL;DR)
- Built and maintained the complete logistics platform for Direct Transport Solutions (Australia) as the sole engineer: Admin Portal, Customer Portal, and React Native Driver App.
- Separating ephemeral live telemetry (WebSockets / Realtime broadcast) from durable route history (batched PostgreSQL writes) cuts database write load by over 85% while keeping map markers smooth.
- Supabase Row-Level Security (RLS) enforces strict multi-tenant isolation so customers only see live GPS coordinates for their own active deliveries.
1. Designing Three Apps as One Cohesive System
Logistics software fails when the driver mobile app, dispatcher dashboard, and customer tracking portal drift out of sync. Because I owned all three surfaces, we structured them around shared TypeScript domain types and a single PostgreSQL + Supabase backend.
When a dispatcher assigns a manifest in the web portal, the React Native driver app receives a push notification and real-time job state transition immediately. Starting a delivery switches the mobile app into active telemetry mode, streaming coordinates to both internal dispatchers and the end customer's live tracking link.
| Platform Surface | Primary Users | Real-Time Channel | Access Control (RLS) |
|---|---|---|---|
| Driver Mobile App (React Native) | Fleet Drivers | Background GPS publisher + job state sync | Authenticated driver (`driver_id = auth.uid()`) |
| Admin Dispatch Portal (Web) | Operations & Dispatchers | Fleet-wide WebSocket multiplex + exceptions | Role-based (`role IN ('admin', 'dispatcher')`) |
| Customer Portal (Web) | B2B Shippers & Recipients | Scoped shipment channel per active order | Tenant-isolated (`company_id = current_tenant()`) |
2. Battery-Conscious Background GPS Telemetry in React Native
Polling GPS every second at maximum accuracy drains a driver's phone battery before noon and floods the backend with redundant coordinates when the truck is stopped at a warehouse dock.
Instead, we use distance-filter triggers (e.g., emit only when the vehicle moves ≥ 25 meters or heading changes by ≥ 15 degrees) combined with an offline SQLite ring buffer. If a driver passes through a highway dead zone in regional Australia, coordinates queue locally with their true capture timestamps and flush in order as soon as cellular signal returns.
export interface TelemetryPing {
jobId: string;
driverId: string;
lat: number;
lng: number;
speedKmh: number;
heading: number;
capturedAt: string;
}
export class TelemetryDispatcher {
private buffer: TelemetryPing[] = [];
private flushing = false;
enqueue(ping: TelemetryPing, isOnline: boolean) {
this.buffer.push(ping);
if (isOnline && !this.flushing) {
void this.flush();
}
}
async flush() {
if (this.buffer.length === 0) return;
this.flushing = true;
const batch = this.buffer.splice(0, 25);
try {
await fetch("/api/telemetry/batch", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ pings: batch }),
});
} catch {
// Prepend back to buffer on network drop so route history has zero gaps
this.buffer.unshift(...batch);
} finally {
this.flushing = false;
}
}
}3. Splitting Ephemeral WebSocket Broadcasts from Durable Storage
A classic scaling mistake is inserting a PostgreSQL row on every single 3-second GPS tick and relying on database change-data-capture (CDC) to push updates to connected browsers. With 100 active trucks, that's 2,000+ row inserts per minute plus WAL replication overhead.
We split the pipeline into two paths: (1) an ephemeral WebSocket broadcast channel that streams live coordinates directly to subscribed map clients with sub-200ms latency, and (2) a debounced persistence worker that writes canonical breadcrumb checkpoints and `last_known_location` updates to PostgreSQL every 30–60 seconds or on status transitions (Picked Up, In Transit, Proof of Delivery).
4. Enforcing Multi-Tenant Isolation with PostgreSQL & Supabase RLS
In B2B logistics, Customer A must never be able to query Customer B's shipments, pricing, or driver locations — even if someone inspects network requests and swaps a shipment UUID.
Rather than relying solely on application-layer `WHERE` clauses that a developer might forget on a new endpoint, we enforce security directly in PostgreSQL using Row-Level Security (RLS) policies indexed on `company_id` and `driver_id`.
ALTER TABLE public.shipments ENABLE ROW LEVEL SECURITY;
-- 1. Drivers can read and update status only for shipments assigned to them
CREATE POLICY "drivers_assigned_shipments"
ON public.shipments
FOR SELECT
TO authenticated
USING (driver_id = auth.uid());
-- 2. Customers can view only their own organization's shipments
CREATE POLICY "customers_tenant_isolation"
ON public.shipments
FOR SELECT
TO authenticated
USING (
company_id IN (
SELECT company_id FROM public.company_members
WHERE user_id = auth.uid()
)
);