Skip to content

Location Strategy

Driver positions are tracked in two stores that serve different purposes. Understanding when each is queried prevents confusion.


Two-store model

Driver sends location update │ ├─→ Redis Geo (drivers:locations) │ • Ephemeral, in-memory │ • Updated every few seconds │ • Used for: ride matching, nearby search │ └─→ PostgreSQL / PostGIS (driver_location table) • Persistent, indexed • Updated on each HTTP POST to /driver/location • Used for: historical queries, audit


Redis Geo — primary path

Key: drivers:locations

Operations: - GEOADD — stores Point(lon, lat) with member = driverId - GEORADIUS — returns drivers within radius with distance and coordinates - GEOREM — removes driver when they go offline

Used by: - RideMatchingService — during the 3–10 km expanding search - GET /redis/nearby — customer nearby search (primary, fast path) - POST /redis/driver/location — driver location update (always writes here)

Performance: Redis Geo queries run in O(N+log M) time entirely in memory. The nearby search in ride matching consistently runs at p(95) < 150ms at moderate fleet sizes.


PostGIS — persistence path

Table: driver_location (one row per driver, upserted on each update)

Column: locationgeometry(Point, 4326) — JTS Point with SRID 4326 (WGS84 lon/lat)

Used by: - POST /driver/location (WebSocket @MessageMapping or HTTP) — writes to PostGIS - GET /api/drivers/nearby — PostGIS spatial query (fallback / historical path)

Index: A GIST index on driver_location.location is required for ST_DWithin performance. This should be added via a Flyway migration before production deployment.


Coordinate convention

lon before lat in JTS

JTS geometry uses Coordinate(x, y) = Coordinate(lon, lat). All Point objects are constructed as createPoint(new Coordinate(lon, lat)). All API DTOs use { lat, lon } fields in the natural human order.


Location streaming during an active ride

When a driver calls POST /redis/driver/location and there is an active IN_PROGRESS ride assigned to them, the server automatically pushes the location to the customer:

POST /redis/driver/location { lat, lon } → RedisGeoService.updateDriverLocation() → RideRepository.findByDriverIdAndStatus(driverId, IN_PROGRESS) → if present: DriverNotificationService.notifyCustomerDriverLocation() → /topic/customer/{customerId}/driver-location { lat, lon }

No additional subscription or opt-in is required from the customer — they receive updates automatically once the ride is IN_PROGRESS.


Driver going online — document enforcement

Before GeoService.updateDriverOnlineStatus() sets onlineStatus = ONLINE, it checks that the driver has at least one APPROVED document of each required type:

  • LICENSE
  • INSURANCE
  • REGISTRATION

If any is missing or not yet approved, the request fails with 409 Conflict:

json { "error": "Cannot go ONLINE: missing approved document of type LICENSE" }