Skip to content

feat: Implement Active Geofencing — Entry, Exit & Dwell Events#219

Open
roncodes wants to merge 1 commit intodev-v0.6.39from
feature/active-geofencing
Open

feat: Implement Active Geofencing — Entry, Exit & Dwell Events#219
roncodes wants to merge 1 commit intodev-v0.6.39from
feature/active-geofencing

Conversation

@roncodes
Copy link
Copy Markdown
Member

@roncodes roncodes commented Apr 6, 2026

Overview

This PR implements full, industry-standard active geofencing capabilities for FleetOps, transforming Zones and Service Areas from passive visual/pricing constructs into live geofence triggers that fire real-time events, webhooks, and notifications whenever a driver crosses a boundary.


Problem Statement

Prior to this change, FleetOps Zones and Service Areas existed only as visual polygons on the live map and pricing boundaries evaluated at order quote time. The DriverController@track pipeline — which runs on every GPS ping — never checked whether a driver had crossed a zone boundary. There were no GeofenceEntered, GeofenceExited, or GeofenceDwelled events anywhere in the codebase. This is a significant gap compared to industry peers (Samsara, Motive, Verizon Connect, Onfleet, Geotab).


What This PR Delivers

Database Migrations (4 new)

  • add_geofence_config_to_zones_table — adds trigger_on_entry, trigger_on_exit, dwell_threshold_minutes, speed_limit_kmh
  • add_geofence_config_to_service_areas_table — same config columns on service areas
  • create_driver_geofence_states_table — per-driver/geofence state machine (is_inside, entered_at, exited_at, dwell_job_id)
  • create_geofence_events_log_table — persistent audit log with full spatial + temporal indexing

New Backend Classes (10 new files)

  • GeofenceIntersectionService — Spatial intersection engine using MySQL MBRContains (bounding-box index pre-filter) + ST_Contains (exact polygon check). Checks both Zones and Service Areas on every location ping. Compares current position against the driver_geofence_states table to detect state transitions (outside→inside = entered, inside→outside = exited).
  • GeofenceEntered / GeofenceExited / GeofenceDwelled — Laravel broadcast events implementing ShouldBroadcast with full industry-standard JSON payloads (driver, vehicle, geofence, location, order context, dwell duration).
  • HandleGeofenceEntered / HandleGeofenceExited / HandleGeofenceDwelled — Queued listeners that write to geofence_events_log and dispatch DriverArrivedAtGeofence notifications.
  • CheckGeofenceDwell — Delayed queue job dispatched on entry; fires GeofenceDwelled if the driver is still inside after the configured threshold.
  • DriverArrivedAtGeofence — Multi-channel notification (database, broadcast, mail).
  • GeofenceController — REST API: GET /geofences/events, /inventory, /dwell-report, /driver/{uuid}/history.
  • GeofenceEventLog — Eloquent model for the events log table.

Modified Backend Files (5 files)

  • DriverController@track — After broadcasting DriverLocationChanged, calls GeofenceIntersectionService::detectCrossings(), upserts state records, dispatches events, and schedules dwell jobs. Wrapped in try/catch so geofence errors never block the location update response.
  • Zone / ServiceArea models — Added geofence config fields to $fillable and $casts.
  • EventServiceProvider — Registered all three geofence events with their listeners and SendResourceLifecycleWebhook.
  • FleetOpsServiceProvider — Singleton binding for GeofenceIntersectionService; registered DriverArrivedAtGeofence notification.
  • routes.php — Added /geofences/* API route group.

New Frontend Files (3 new files)

  • addon/services/geofence-event-bus.js — Singleton Ember service that subscribes to the company-level SocketCluster channel, maintains a live event feed, and emits on the universe event bus. Exposes an on(eventType, handler) / off() pub-sub API.
  • addon/components/map/toolbar/geofence-events-panel.js/.hbs — Live map toolbar panel showing a real-time stream of geofence events with colour-coded entry/exit/dwell badges.

Modified Frontend Files (3 files)

  • addon/components/zone/form.hbs — Added Geofence Triggers ContentPanel with entry/exit toggle switches, dwell threshold input, and speed limit input.
  • addon/components/service-area/form.hbs — Same Geofence Triggers panel.
  • addon/components/map/leaflet-live-map.js — Injected geofenceEventBus; subscribed to geofence universe events; added #flashGeofenceLayer that flashes the matching polygon green/red on the live map for 2 seconds on entry/exit.

Webhook Payload Example

{
  "event": "geofence.entered",
  "occurred_at": "2026-04-05T10:23:45Z",
  "driver": { "uuid": "drv_abc123", "name": "Jane Smith", "public_id": "DRV-0001" },
  "vehicle": { "uuid": "veh_xyz789", "plate": "SG1234A" },
  "geofence": { "uuid": "zon_def456", "name": "Warehouse A", "type": "zone" },
  "location": { "latitude": 1.3521, "longitude": 103.8198, "speed_kmh": 12.4 },
  "order": { "uuid": "ord_ghi012", "id": "ORD-0042" },
  "dwell_duration_minutes": null
}

Testing Checklist

  • Run migrations: php artisan migrate
  • Verify spatial indexes on zones and service_areas tables
  • Enable entry/exit triggers on a Zone via the updated zone form
  • Simulate a driver location ping inside the zone boundary
  • Confirm driver_geofence_states row created with is_inside = 1
  • Confirm geofence_events_log row created with event_type = geofence.entered
  • Confirm geofence.entered WebSocket event received in browser console
  • Confirm zone polygon flashes green on the live map
  • Simulate a second ping outside the zone boundary
  • Confirm geofence.exited event fired and polygon flashes red
  • Set dwell_threshold_minutes = 1 and wait — confirm geofence.dwelled event fires
  • Check GET /api/v1/geofences/events returns the event log
  • Check GET /api/v1/geofences/dwell-report returns aggregated dwell stats
  • Verify webhook delivery via the Fleetbase webhook log

Queue Worker Configuration

Ensure a dedicated geofence queue worker is running:

php artisan queue:work --queue=geofence,default --tries=3 --backoff=5

This commit introduces full, industry-standard active geofencing capabilities
to FleetOps, transforming Zones and Service Areas from passive visual/pricing
constructs into live geofence triggers.

## Database Migrations (4 new)
- add_geofence_config_to_zones_table: trigger_on_entry, trigger_on_exit,
  dwell_threshold_minutes, speed_limit_kmh columns
- add_geofence_config_to_service_areas_table: same config columns
- create_driver_geofence_states_table: per-driver/geofence state machine
  (is_inside, entered_at, exited_at, dwell_job_id)
- create_geofence_events_log_table: persistent audit log with full indexing

## New Backend Classes
- GeofenceIntersectionService: spatial intersection engine using MySQL
  MBRContains (index-assisted bounding box pre-filter) + ST_Contains
  (exact polygon check) with per-driver state tracking
- GeofenceEntered / GeofenceExited / GeofenceDwelled: Laravel broadcast
  events with full industry-standard JSON webhook payloads
- HandleGeofenceEntered / HandleGeofenceExited / HandleGeofenceDwelled:
  queued listeners that write to the event log and send notifications
- CheckGeofenceDwell: delayed queue job that fires GeofenceDwelled if
  the driver is still inside after the configured threshold
- DriverArrivedAtGeofence: multi-channel notification (database, broadcast,
  mail) for geofence arrival alerts
- GeofenceController: REST API for event log, real-time inventory,
  dwell report, and per-driver history
- GeofenceEventLog: Eloquent model for the events log table

## Modified Backend Files
- DriverController@track: integrated GeofenceIntersectionService after
  every location ping; dispatches events and schedules dwell jobs
- Zone / ServiceArea models: added geofence config fields to fillable/casts
- EventServiceProvider: registered all three geofence event-listener pairs
- FleetOpsServiceProvider: singleton binding for GeofenceIntersectionService,
  registered DriverArrivedAtGeofence notification
- routes.php: added /geofences/* API route group

## New Frontend Files
- addon/services/geofence-event-bus.js: singleton service that subscribes
  to the company WebSocket channel and maintains a live event feed;
  exposes on/off pub-sub API and emits on the universe event bus
- addon/components/map/toolbar/geofence-events-panel.js/.hbs: live map
  toolbar panel showing a real-time stream of geofence events with
  colour-coded entry/exit/dwell badges

## Modified Frontend Files
- addon/components/zone/form.hbs: added Geofence Triggers ContentPanel
  with entry/exit toggles, dwell threshold, and speed limit inputs
- addon/components/service-area/form.hbs: same Geofence Triggers panel
- addon/components/map/leaflet-live-map.js: injected geofenceEventBus,
  subscribed to geofence.entered/exited universe events, added
  #handleGeofenceEntered / #handleGeofenceExited private methods that
  flash the matching polygon layer green/red on the live map
@roncodes roncodes changed the base branch from main to dev-v0.6.39 April 6, 2026 09:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant