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: GeoCoordinate
    • northEast: GeoCoordinate
  • Realizes: REQ-GEO-020 (zone boundary)

Polyline

Encoded route path.

  • Fields:
    • encodedPath: String
    • coordinates: 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: GeoCoordinate
    • destination: GeoCoordinate
    • duration: Duration
    • computedAt: DateTime
  • Realizes: REQ-GEO-011, REQ-GEO-NFR-002

Route

Computed route with polyline, distance, and duration.

  • Fields:
    • origin: GeoCoordinate
    • destination: GeoCoordinate
    • polyline: Polyline
    • distance: Distance
    • duration: Duration
    • computedAt: 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: GeoCoordinate
    • accuracy: LocationAccuracy
    • heading: Decimal optional — min(0), max(360)
    • speed: Decimal optional — min(0)
    • availability: DriverAvailability — default offline
    • recordedAt: DateTime — when the device captured the fix
    • receivedAt: DateTime — when GEO ingested the update
  • Invariants:
    • positionHasTimestamp: recordedAt is defined — enforcement: reject
  • Operations:
    • Update driver location on command UpdateDriverLocation
      • Realizes: REQ-GEO-001, REQ-GEO-002, REQ-GEO-004
      • Preconditions:
        • locationFreshEnough: now() - updateDriverLocation.recordedAt <= 60s
        • locationAccurateEnough: updateDriverLocation.accuracy.horizontalAccuracyMeters <= 100
      • State changes (sets): position, accuracy, heading, speed, recordedAt from the command; receivedAt = now().
      • Postcondition positionStored: state_after.position = updateDriverLocation.position and state_after.receivedAt is defined.
      • Emits: DriverLocationUpdated with driverId, position, accuracy, recordedAt.
    • Mark driver ineligible on stale position on command MarkPositionStale
      • Realizes: REQ-GEO-003, REQ-DRV-034
      • Precondition positionIsStale: now() - DriverPosition.recordedAt > 60s
      • State change: availability = offline.
      • Emits: DriverPositionStale with driverId, lastSeenAt, detectedAt = now().
    • Set driver availability on command SetDriverAvailability
      • Realizes: REQ-DRV-032
      • State change: availability = setDriverAvailability.availability.
      • Emits: DriverAvailabilityChanged with driverId, 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: 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: when status = active, currentMultiplier must be defined — enforcement: reject
    • multiplierWithinCap: when currentMultiplier is defined, currentMultiplier.value <= 5.0 — enforcement: reject
  • Operations:
    • Activate surge in zone on command ActivateSurge — resolves SurgeZone from activateSurge.zoneId.
      • Realizes: REQ-GEO-020
      • Preconditions:
        • zoneInactive: SurgeZone.status = inactive
        • ratioAboveThreshold: activateSurge.demandSupplyRatio > SurgeZone.surgeThreshold
      • State changes: status = active, currentMultiplier = activateSurge.multiplier, demandSupplyRatio = activateSurge.demandSupplyRatio, activatedAt = now().
      • Emits: SurgeActivated with zoneId, multiplier, contributingFactor, demandSupplyRatio, activatedAt.
    • Deactivate surge in zone on command DeactivateSurge — resolves SurgeZone from deactivateSurge.zoneId.
      • Realizes: REQ-GEO-021
      • Preconditions:
        • zoneActive: SurgeZone.status = active
        • ratioStableBelowThreshold: deactivateSurge.demandSupplyRatio <= SurgeZone.surgeThreshold
        • belowThresholdAtLeastFiveMinutes: deactivateSurge.belowThresholdSince <= now() - 5min
      • State changes: status = inactive, currentMultiplier = null, deactivatedAt = now().
      • Emits: SurgeDeactivated with zoneId, previousMultiplier, deactivatedAt.
  • Realizes: REQ-GEO-020, REQ-GEO-021, REQ-GEO-024

State Machines

SurgeZoneLifecycle on SurgeZone

  • Start state: inactive
  • States:
    • inactive — state-scoped invariant noMultiplierWhileInactive: SurgeZone.currentMultiplier is null
    • active — state-scoped invariant multiplierPresentWhileActive: SurgeZone.currentMultiplier is defined
  • Transitions:
    • inactiveactive on command ActivateSurge
    • activeinactive on command DeactivateSurge
  • 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 — issues ActivateSurge or DeactivateSurge based 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 DriverPositionStale to DriverManagement
  • 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 ETAVarianceDetected to RideManagement
  • 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
    }
}