Bounded Context: Geolocation & Routing (GEO)
Responsibility: Real-time driver positioning, ETA computation, route calculation, surge-zone detection and pricing, ETA variance monitoring during a ride.
Context Map
| Relation | Other Bounded Context | Position | Pattern | Description |
|---|---|---|---|---|
| GEO → RideManagement | Ride Management (RIDE) | upstream | Open Host Service (OHS) | GEO exposes nearby-driver queries, ETA, route, and surge-zone info for matching and offer-time fare estimates. RIDE is the dominant consumer. |
| GEO → RideManagement | Ride Management (RIDE) | upstream | Published Language | GEO publishes SurgeActivated, SurgeDeactivated, ETAVarianceDetected, RouteRecalculated events — RIDE subscribes to refresh fare estimates, alert riders, and re-route in flight. |
| GEO → DriverManagement | Driver Management (DRV) | upstream | Anti-Corruption Layer (ACL) | GEO publishes DriverPositionStale when a position is older than 60s; DRV consumes it through an ACL and triggers GoOffline with reason stalePosition. |
| GEO → TrafficDataProvider | external infrastructure | downstream | Conformist (infrastructure) | GEO depends on an external traffic API for traffic-aware ETA and recalculation. Wrapped behind the TrafficDataProvider infrastructure-service. |
| GEO → MappingProvider | external infrastructure | downstream | Conformist (infrastructure) | GEO depends on an external maps/geocoding API for route polylines. Wrapped behind the MappingProvider infrastructure-service. |
Enums
SurgeZoneStatus
- Values:
inactive,active. - Realizes: REQ-GEO-020, REQ-GEO-021.
DriverAvailability
- Values:
online,offline,onTrip. - Realizes: REQ-DRV-032 (cross-context — GEO is the projection, DRV is the canonical lifecycle).
Value Types
GeoCoordinate
A point on Earth.
- Fields:
latitude: Decimal —min(-90),max(90)longitude: Decimal —min(-180),max(180)
- Realizes: (foundational type, no direct requirement)
BoundingBox
Rectangular geographic area.
- Fields:
southWest:GeoCoordinatenorthEast:GeoCoordinate
- Realizes: REQ-GEO-020 (zone boundary)
Polyline
Encoded route path.
- Fields:
encodedPath: Stringcoordinates:list<GeoCoordinate>
- Realizes: REQ-GEO-012
Distance, Duration
These value types are co-owned in the Shared Kernel — see the Shared Kernel page for their fields and invariants. They are referenced unqualified throughout this context.
ETA
Estimated time of arrival between two points.
- Fields:
origin:GeoCoordinatedestination:GeoCoordinateduration:DurationcomputedAt: DateTime
- Realizes: REQ-GEO-011, REQ-GEO-NFR-002
Route
Computed route with polyline, distance, and duration.
- Fields:
origin:GeoCoordinatedestination:GeoCoordinatepolyline:Polylinedistance:Distanceduration:DurationcomputedAt: DateTime
- Realizes: REQ-GEO-012
SurgeMultiplier
Pricing multiplier during high demand.
- Fields:
value: Decimal —min(1.0),max(5.0)
- Invariants:
surgeMultiplierCap:value <= 5.0— enforcement: reject. The platform-wide cap is enforced at the value-type level so no construction path can exceed it. Per-market lower caps are applied at construction time before the value is created.
- Realizes: REQ-GEO-022
LocationAccuracy
- Fields:
horizontalAccuracyMeters: Decimal —min(0)
- Realizes: REQ-GEO-004
Entities
DriverPosition
Real-time geographic position of a driver — continuously updated projection of incoming location updates.
- Identifier:
driverId : UUID - Fields:
position:GeoCoordinateaccuracy:LocationAccuracyheading: Decimal optional —min(0),max(360)speed: Decimal optional —min(0)availability:DriverAvailability— defaultofflinerecordedAt: DateTime — when the device captured the fixreceivedAt: DateTime — when GEO ingested the update
- Invariants:
positionHasTimestamp:recordedAtis defined — enforcement: reject
- Operations:
Update driver locationon commandUpdateDriverLocation- Realizes: REQ-GEO-001, REQ-GEO-002, REQ-GEO-004
- Preconditions:
locationFreshEnough:now() - updateDriverLocation.recordedAt <= 60slocationAccurateEnough:updateDriverLocation.accuracy.horizontalAccuracyMeters <= 100
- State changes (
sets):position,accuracy,heading,speed,recordedAtfrom the command;receivedAt = now(). - Postcondition
positionStored:state_after.position = updateDriverLocation.positionandstate_after.receivedAt is defined. - Emits:
DriverLocationUpdatedwithdriverId,position,accuracy,recordedAt.
Mark driver ineligible on stale positionon commandMarkPositionStale- Realizes: REQ-GEO-003, REQ-DRV-034
- Precondition
positionIsStale:now() - DriverPosition.recordedAt > 60s - State change:
availability = offline. - Emits:
DriverPositionStalewithdriverId,lastSeenAt,detectedAt = now().
Set driver availabilityon commandSetDriverAvailability- Realizes: REQ-DRV-032
- State change:
availability = setDriverAvailability.availability. - Emits:
DriverAvailabilityChangedwithdriverId,availability,changedAt = now().
- Realizes: REQ-GEO-001, REQ-GEO-002, REQ-DRV-032
SurgeZone
Geographic zone where demand/supply imbalance triggers surge.
- Identifier:
zoneId : UUID - Fields:
name: String —maxLength(200)boundary:BoundingBoxstatus:SurgeZoneStatus— defaultinactivecurrentMultiplier:SurgeMultiplieroptionaldemandSupplyRatio: Decimal optional —min(0)surgeThreshold: Decimal —min(0), default2.0activatedAt: DateTime optionaldeactivatedAt: DateTime optional
- Invariants:
activeZoneHasMultiplier: whenstatus = active,currentMultipliermust be defined — enforcement: rejectmultiplierWithinCap: whencurrentMultiplieris defined,currentMultiplier.value <= 5.0— enforcement: reject
- Operations:
Activate surge in zoneon commandActivateSurge— resolvesSurgeZonefromactivateSurge.zoneId.- Realizes: REQ-GEO-020
- Preconditions:
zoneInactive:SurgeZone.status = inactiveratioAboveThreshold:activateSurge.demandSupplyRatio > SurgeZone.surgeThreshold
- State changes:
status = active,currentMultiplier = activateSurge.multiplier,demandSupplyRatio = activateSurge.demandSupplyRatio,activatedAt = now(). - Emits:
SurgeActivatedwithzoneId,multiplier,contributingFactor,demandSupplyRatio,activatedAt.
Deactivate surge in zoneon commandDeactivateSurge— resolvesSurgeZonefromdeactivateSurge.zoneId.- Realizes: REQ-GEO-021
- Preconditions:
zoneActive:SurgeZone.status = activeratioStableBelowThreshold:deactivateSurge.demandSupplyRatio <= SurgeZone.surgeThresholdbelowThresholdAtLeastFiveMinutes:deactivateSurge.belowThresholdSince <= now() - 5min
- State changes:
status = inactive,currentMultiplier = null,deactivatedAt = now(). - Emits:
SurgeDeactivatedwithzoneId,previousMultiplier,deactivatedAt.
- Realizes: REQ-GEO-020, REQ-GEO-021, REQ-GEO-024
State Machines
SurgeZoneLifecycle on SurgeZone
- Start state:
inactive - States:
inactive— state-scoped invariantnoMultiplierWhileInactive:SurgeZone.currentMultiplier is nullactive— state-scoped invariantmultiplierPresentWhileActive:SurgeZone.currentMultiplier is defined
- Transitions:
inactive→activeon commandActivateSurgeactive→inactiveon commandDeactivateSurge
- Final states: none — surge zones cycle indefinitely.
The state-scoped invariants are conjoined with the entity-level invariants. Together they guarantee that a multiplier is present if and only if the zone is active, and that it never exceeds the platform cap.
Domain Services
ProximityService
Spatial queries over real-time driver positions.
- Operations:
findNearbyDrivers(pickup: GeoCoordinate, radiusMeters: Decimal, maxResults: Integer) : list<DriverPosition>— returns online, match-eligible drivers within the radius, ordered by ETA to pickup.
- Realizes: REQ-GEO-010, REQ-GEO-NFR-001, REQ-GEO-NFR-003
RoutingService
Route and ETA computation, traffic-aware.
- Operations:
computeETA(origin: GeoCoordinate, destination: GeoCoordinate) : ETA— uses current traffic.computeRoute(origin: GeoCoordinate, destination: GeoCoordinate) : Route— optimal polyline with distance and duration.recalculateRoute(rideId: uuid, currentPosition: GeoCoordinate, destination: GeoCoordinate) : Route— issued when traffic changes significantly mid-ride.
- Realizes: REQ-GEO-011, REQ-GEO-012, REQ-GEO-013, REQ-GEO-015, REQ-GEO-NFR-002
SurgeDetectionService
Monitors demand/supply ratio per zone and triggers activation/deactivation.
- Operations:
evaluateZone(zoneId: uuid, requestCount: Integer, availableDriverCount: Integer) : void— issuesActivateSurgeorDeactivateSurgebased on ratio vs threshold.computeMultiplier(demandSupplyRatio: Decimal) : SurgeMultiplier— derives the multiplier, capped at 5.0x by the value type itself.
- Realizes: REQ-GEO-020, REQ-GEO-021, REQ-GEO-022
ETAVarianceMonitor
Detects unusual ETA growth during a ride.
- Operations:
checkVariance(rideId: uuid, previousEta: ETA, currentEta: ETA) : Boolean— true when remaining ETA grew more than 5 minutes from the previous published value.
- Realizes: REQ-GEO-014
Infrastructure Services
TrafficDataProvider
External traffic data API — infrastructure boundary.
- Operations:
getCurrentTraffic(origin: GeoCoordinate, destination: GeoCoordinate) : void— wraps an external API (Google Maps, HERE, Mapbox).
MappingProvider
External maps and geocoding API — infrastructure boundary.
- Operations:
computeRoute(origin: GeoCoordinate, destination: GeoCoordinate) : Route— wraps an external maps API.
Commands
| Command | Fields | Realizes |
|---|---|---|
UpdateDriverLocation |
driverId, position, accuracy, heading?, speed?, recordedAt, correlationId |
REQ-GEO-001, REQ-GEO-002, REQ-GEO-004 |
MarkPositionStale |
driverId, correlationId |
REQ-GEO-003 |
SetDriverAvailability |
driverId, availability, correlationId |
REQ-DRV-032 |
ActivateSurge |
zoneId, multiplier, demandSupplyRatio, contributingFactor, correlationId |
REQ-GEO-020 |
DeactivateSurge |
zoneId, previousMultiplier, demandSupplyRatio, belowThresholdSince, correlationId |
REQ-GEO-021 |
Events
Internal events
| Event | Fields | Realizes |
|---|---|---|
DriverLocationUpdated |
driverId, position, accuracy, recordedAt |
REQ-GEO-001 |
DriverPositionStale |
driverId, lastSeenAt, detectedAt |
REQ-GEO-003, REQ-DRV-034 |
DriverAvailabilityChanged |
driverId, availability, changedAt |
(supporting event) |
SurgeActivated |
zoneId, multiplier, contributingFactor, demandSupplyRatio, activatedAt |
REQ-GEO-020, REQ-GEO-023 |
SurgeDeactivated |
zoneId, previousMultiplier, deactivatedAt |
REQ-GEO-021 |
ETAVarianceDetected |
rideId, previousDuration, newDuration, growthSeconds, detectedAt |
REQ-GEO-014 |
RouteRecalculated |
rideId, newRoute, recalculatedAt |
REQ-GEO-015 |
External-bound events (Published Language)
SurgeActivated, SurgeDeactivated, ETAVarianceDetected, RouteRecalculated cross the boundary to Ride Management through the published-language pattern. DriverPositionStale crosses to Driver Management through an Anti-Corruption Layer that translates it into a GoOffline(reason=stalePosition) command.
Reactions
notifyDriverManagementOnStale
“Notify Driver Management when a driver position goes stale.”
- Trigger: event
DriverPositionStale - Effect: publish
DriverPositionStaletoDriverManagement - Realizes: REQ-GEO-003, REQ-DRV-034
emitVarianceAlertOnDriftingEta
“Raise variance alert when remaining ETA grows more than 5 minutes.”
- Trigger: event
ETAVarianceDetected - Guard:
event.growthSeconds > 300 - Effect: publish
ETAVarianceDetectedtoRideManagement - Realizes: REQ-GEO-014
Traceability Matrix
| Requirement | Realized by |
|---|---|
REQ-GEO-001 |
DriverPosition, command UpdateDriverLocation, op Update driver location, event DriverLocationUpdated |
REQ-GEO-002 |
DriverPosition, op Update driver location (precondition locationFreshEnough) |
REQ-GEO-003 |
DriverPosition, op Mark driver ineligible on stale position, event DriverPositionStale, reaction notifyDriverManagementOnStale |
REQ-GEO-004 |
LocationAccuracy, op Update driver location (precondition locationAccurateEnough) |
REQ-GEO-010 |
BoundingBox, ProximityService.findNearbyDrivers |
REQ-GEO-011 |
ETA, Duration, RoutingService.computeETA, TrafficDataProvider |
REQ-GEO-012 |
Route, Polyline, Distance, Duration, RoutingService.computeRoute, MappingProvider |
REQ-GEO-013 |
RoutingService.computeETA (refresh cadence enforced by RIDE consumer) |
REQ-GEO-014 |
ETAVarianceMonitor.checkVariance, event ETAVarianceDetected, reaction emitVarianceAlertOnDriftingEta |
REQ-GEO-015 |
RoutingService.recalculateRoute, TrafficDataProvider, event RouteRecalculated |
REQ-GEO-020 |
SurgeMultiplier, SurgeZone, SurgeDetectionService.evaluateZone, command ActivateSurge, op Activate surge in zone, event SurgeActivated |
REQ-GEO-021 |
SurgeZone, SurgeDetectionService.evaluateZone, command DeactivateSurge, op Deactivate surge in zone, event SurgeDeactivated |
REQ-GEO-022 |
SurgeMultiplier (invariant surgeMultiplierCap, max 5.0), SurgeZone (invariant multiplierWithinCap), SurgeDetectionService.computeMultiplier |
REQ-GEO-023 |
event SurgeActivated (Published Language consumed by RIDE for fare-estimate display) |
REQ-GEO-024 |
SurgeZone (no operation re-applies multiplier after a fare commit; enforced as cross-context agreement at the RIDE boundary) |
REQ-GEO-NFR-001 |
ProximityService.findNearbyDrivers (latency budget) |
REQ-GEO-NFR-002 |
ETA, RoutingService.computeETA (latency budget) |
REQ-GEO-NFR-003 |
ProximityService (throughput budget) |
REQ-GEO-NFR-004 |
(operational policy — implementation concern: granular retention ≤ 90 days) |
Concrete syntax (.domain DSL)
The full .domain source that this page narrates. Entity declarations, value types, commands, events, invariants, preconditions, postconditions, services, state machine, and reactions appear in parse order.
context GeolocationRouting :: "Real-time positioning, proximity queries, ETA, routing, surge zones" {
requirements-source "geolocation-routing.sysreq"
enum SurgeZoneStatus { inactive, active }
enum DriverAvailability { online, offline, onTrip }
// -----------------------------------------------------------------
// Value types
// -----------------------------------------------------------------
value GeoCoordinate :: "A point on Earth" {
fields {
latitude : decimal min(-90) max(90)
longitude : decimal min(-180) max(180)
}
}
value BoundingBox :: "Rectangular geographic area" {
fields { southWest : GeoCoordinate; northEast : GeoCoordinate }
}
value Polyline :: "Encoded route path" {
fields { encodedPath : string; coordinates : list<GeoCoordinate> }
}
// Distance and Duration are co-owned in the Shared context (see shared.domain).
value ETA :: "Estimated time of arrival between two points" {
satisfies [REQ-GEO-011, REQ-GEO-NFR-002]
fields {
origin : GeoCoordinate
destination : GeoCoordinate
duration : Duration
computedAt : datetime
}
}
value Route :: "Computed route with polyline, distance, duration" {
satisfies [REQ-GEO-012]
fields {
origin : GeoCoordinate
destination : GeoCoordinate
polyline : Polyline
distance : Distance
duration : Duration
computedAt : datetime
}
}
value SurgeMultiplier :: "Pricing multiplier during high demand" {
satisfies [REQ-GEO-022, REQ-NFR-051]
fields { value : decimal min(1.0) max(5.0) }
invariants {
surgeMultiplierCap :: "Surge multiplier never exceeds 5.0x" enforcement reject {
value <= 5.0
}
}
}
value LocationAccuracy { fields { horizontalAccuracyMeters : decimal min(0) } }
// -----------------------------------------------------------------
// Entities
// -----------------------------------------------------------------
entity DriverPosition :: "Real-time geographic position of a driver" {
satisfies [REQ-GEO-001, REQ-GEO-002, REQ-DRV-032]
identifier driverId : UUID
fields {
position : GeoCoordinate
accuracy : LocationAccuracy
heading : decimal optional min(0) max(360)
speed : decimal optional min(0)
availability : DriverAvailability default("offline")
recordedAt : datetime
receivedAt : datetime
}
invariants {
positionHasTimestamp :: "Every position has a recording timestamp" enforcement reject {
recordedAt is defined
}
}
operations {
"Update driver location" on UpdateDriverLocation {
satisfies [REQ-GEO-001, REQ-GEO-002, REQ-GEO-004]
precondition locationFreshEnough :: "Discard updates older than 60 seconds" {
now() - updateDriverLocation.recordedAt <= 60s
}
precondition locationAccurateEnough :: "Discard updates with accuracy worse than 100m (REQ-GEO-004)" {
updateDriverLocation.accuracy.horizontalAccuracyMeters <= 100
}
sets DriverPosition {
position = updateDriverLocation.position
accuracy = updateDriverLocation.accuracy
heading = updateDriverLocation.heading
speed = updateDriverLocation.speed
recordedAt = updateDriverLocation.recordedAt
receivedAt = now()
}
postcondition positionStored :: "Projection reflects update with arrival time" {
state_after.position = updateDriverLocation.position
state_after.receivedAt is defined
}
emits DriverLocationUpdated {
driverId = DriverPosition.driverId
position = DriverPosition.position
accuracy = DriverPosition.accuracy
recordedAt = DriverPosition.recordedAt
}
}
"Mark driver ineligible on stale position" on MarkPositionStale {
satisfies [REQ-GEO-003, REQ-DRV-034]
precondition positionIsStale :: "Last update older than 60s" {
now() - DriverPosition.recordedAt > 60s
}
sets DriverPosition { availability = offline }
emits DriverPositionStale {
driverId = DriverPosition.driverId
lastSeenAt = DriverPosition.recordedAt
detectedAt = now()
}
}
"Set driver availability" on SetDriverAvailability {
satisfies [REQ-DRV-032]
sets DriverPosition { availability = setDriverAvailability.availability }
emits DriverAvailabilityChanged {
driverId = DriverPosition.driverId
availability = DriverPosition.availability
changedAt = now()
}
}
}
}
entity SurgeZone :: "Geographic zone where demand/supply imbalance triggers surge" {
satisfies [REQ-GEO-020, REQ-GEO-021, REQ-GEO-024]
identifier zoneId : UUID
fields {
name : string maxLength(200)
boundary : BoundingBox
status : SurgeZoneStatus default("inactive")
currentMultiplier : SurgeMultiplier optional
demandSupplyRatio : decimal optional min(0)
surgeThreshold : decimal min(0) default("2.0")
activatedAt : datetime optional
deactivatedAt : datetime optional
}
invariants {
activeZoneHasMultiplier :: "Active zone must have a multiplier" enforcement reject {
if status = active { currentMultiplier is defined }
}
multiplierWithinCap :: "Multiplier never exceeds platform 5.0x cap" enforcement reject {
if currentMultiplier is defined { currentMultiplier.value <= 5.0 }
}
}
operations {
"Activate surge in zone" on ActivateSurge {
satisfies [REQ-GEO-020]
resolves SurgeZone from activateSurge.zoneId
precondition zoneInactive { SurgeZone.status = inactive }
precondition ratioAboveThreshold {
activateSurge.demandSupplyRatio > SurgeZone.surgeThreshold
}
sets SurgeZone {
status = active
currentMultiplier = activateSurge.multiplier
demandSupplyRatio = activateSurge.demandSupplyRatio
activatedAt = now()
}
emits SurgeActivated {
zoneId = SurgeZone.zoneId
multiplier = SurgeZone.currentMultiplier
contributingFactor = activateSurge.contributingFactor
demandSupplyRatio = SurgeZone.demandSupplyRatio
activatedAt = SurgeZone.activatedAt
}
}
"Deactivate surge in zone" on DeactivateSurge {
satisfies [REQ-GEO-021]
resolves SurgeZone from deactivateSurge.zoneId
precondition zoneActive { SurgeZone.status = active }
precondition ratioStableBelowThreshold {
deactivateSurge.demandSupplyRatio <= SurgeZone.surgeThreshold
}
precondition belowThresholdAtLeastFiveMinutes {
deactivateSurge.belowThresholdSince <= now() - 5min
}
sets SurgeZone {
status = inactive
currentMultiplier = null
deactivatedAt = now()
}
emits SurgeDeactivated {
zoneId = SurgeZone.zoneId
previousMultiplier = deactivateSurge.previousMultiplier
deactivatedAt = SurgeZone.deactivatedAt
}
}
}
}
statemachine SurgeZoneLifecycle on SurgeZone {
start inactive
state inactive {
invariant noMultiplierWhileInactive { SurgeZone.currentMultiplier is null }
}
state active {
invariant multiplierPresentWhileActive { SurgeZone.currentMultiplier is defined }
}
transition inactive -> active on ActivateSurge
transition active -> inactive on DeactivateSurge
}
// -----------------------------------------------------------------
// Domain services
// -----------------------------------------------------------------
service ProximityService :: "Spatial queries over real-time driver positions" {
satisfies [REQ-GEO-010, REQ-GEO-NFR-001, REQ-GEO-NFR-003]
operations {
findNearbyDrivers(pickup: GeoCoordinate, radius: Distance, maxResults: int) : list<DriverPosition>
:: "Online, eligible drivers within radius, ordered by ETA to pickup"
}
}
service RoutingService :: "Route and ETA computation" {
satisfies [REQ-GEO-011, REQ-GEO-012, REQ-GEO-013, REQ-GEO-015, REQ-GEO-NFR-002]
operations {
computeETA(origin: GeoCoordinate, destination: GeoCoordinate) : ETA
computeRoute(origin: GeoCoordinate, destination: GeoCoordinate) : Route
recalculateRoute(rideId: uuid, currentPosition: GeoCoordinate, destination: GeoCoordinate) : Route
}
}
service SurgeDetectionService :: "Monitors demand/supply ratio per zone" {
satisfies [REQ-GEO-020, REQ-GEO-021, REQ-GEO-022]
operations {
evaluateZone(zoneId: uuid, requestCount: int, availableDriverCount: int) : void
computeMultiplier(demandSupplyRatio: decimal) : SurgeMultiplier
}
}
service ETAVarianceMonitor :: "Detects unusual ETA growth during a ride" {
satisfies [REQ-GEO-014]
operations {
checkVariance(rideId: uuid, previousEta: ETA, currentEta: ETA) : boolean
}
}
// -----------------------------------------------------------------
// Infrastructure services (anti-corruption layer to external providers)
// -----------------------------------------------------------------
infrastructure-service TrafficDataProvider :: "External traffic data API" {
operations {
getCurrentTraffic(origin: GeoCoordinate, destination: GeoCoordinate) : void
}
}
infrastructure-service MappingProvider :: "External maps and geocoding API" {
operations {
computeRoute(origin: GeoCoordinate, destination: GeoCoordinate) : Route
}
}
// -----------------------------------------------------------------
// Commands
// -----------------------------------------------------------------
command UpdateDriverLocation {
fields {
driverId : uuid
position : GeoCoordinate
accuracy : LocationAccuracy
heading : decimal optional
speed : decimal optional
recordedAt : datetime
correlationId : uuid
}
}
command MarkPositionStale {
fields { driverId : uuid; correlationId : uuid }
}
command SetDriverAvailability {
fields { driverId : uuid; availability : DriverAvailability; correlationId : uuid }
}
command ActivateSurge {
fields {
zoneId : uuid
multiplier : SurgeMultiplier
demandSupplyRatio : decimal
contributingFactor : string
correlationId : uuid
}
}
command DeactivateSurge {
fields {
zoneId : uuid
previousMultiplier : SurgeMultiplier
demandSupplyRatio : decimal
belowThresholdSince : datetime
correlationId : uuid
}
}
// -----------------------------------------------------------------
// Events
// -----------------------------------------------------------------
event DriverLocationUpdated {
satisfies [REQ-GEO-001]
fields { driverId : uuid; position : GeoCoordinate; accuracy : LocationAccuracy; recordedAt : datetime }
}
event DriverPositionStale {
satisfies [REQ-GEO-003, REQ-DRV-034]
fields { driverId : uuid; lastSeenAt : datetime; detectedAt : datetime }
}
event DriverAvailabilityChanged {
fields { driverId : uuid; availability : DriverAvailability; changedAt : datetime }
}
event SurgeActivated {
satisfies [REQ-GEO-020, REQ-GEO-023]
fields {
zoneId : uuid
multiplier : SurgeMultiplier
contributingFactor : string
demandSupplyRatio : decimal
activatedAt : datetime
}
}
event SurgeDeactivated {
satisfies [REQ-GEO-021]
fields { zoneId : uuid; previousMultiplier : SurgeMultiplier; deactivatedAt : datetime }
}
event ETAVarianceDetected {
satisfies [REQ-GEO-014]
fields { rideId : uuid; previousDuration : Duration; newDuration : Duration; growthSeconds : int; detectedAt : datetime }
}
event RouteRecalculated {
satisfies [REQ-GEO-015]
fields { rideId : uuid; newRoute : Route; recalculatedAt : datetime }
}
// -----------------------------------------------------------------
// Reactions
// -----------------------------------------------------------------
reaction notifyDriverManagementOnStale :: "Notify Driver Management when a driver position goes stale" {
satisfies [REQ-GEO-003, REQ-DRV-034]
trigger DriverPositionStale
effect publish DriverPositionStale to DriverManagement
}
reaction emitVarianceAlertOnDriftingEta :: "Raise variance alert when remaining ETA grows >5 min" {
satisfies [REQ-GEO-014]
trigger ETAVarianceDetected
guard event.growthSeconds > 300
effect publish ETAVarianceDetected to RideManagement
}
}