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: location — geometry(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:
LICENSEINSURANCEREGISTRATION
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" }