feat: Implement Active Geofencing — Entry, Exit & Dwell Events#219
Open
roncodes wants to merge 1 commit intodev-v0.6.39from
Open
feat: Implement Active Geofencing — Entry, Exit & Dwell Events#219roncodes wants to merge 1 commit intodev-v0.6.39from
roncodes wants to merge 1 commit intodev-v0.6.39from
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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@trackpipeline — which runs on every GPS ping — never checked whether a driver had crossed a zone boundary. There were noGeofenceEntered,GeofenceExited, orGeofenceDwelledevents 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— addstrigger_on_entry,trigger_on_exit,dwell_threshold_minutes,speed_limit_kmhadd_geofence_config_to_service_areas_table— same config columns on service areascreate_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 indexingNew Backend Classes (10 new files)
GeofenceIntersectionService— Spatial intersection engine using MySQLMBRContains(bounding-box index pre-filter) +ST_Contains(exact polygon check). Checks both Zones and Service Areas on every location ping. Compares current position against thedriver_geofence_statestable to detect state transitions (outside→inside = entered, inside→outside = exited).GeofenceEntered/GeofenceExited/GeofenceDwelled— Laravel broadcast events implementingShouldBroadcastwith full industry-standard JSON payloads (driver, vehicle, geofence, location, order context, dwell duration).HandleGeofenceEntered/HandleGeofenceExited/HandleGeofenceDwelled— Queued listeners that write togeofence_events_logand dispatchDriverArrivedAtGeofencenotifications.CheckGeofenceDwell— Delayed queue job dispatched on entry; firesGeofenceDwelledif 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 broadcastingDriverLocationChanged, callsGeofenceIntersectionService::detectCrossings(), upserts state records, dispatches events, and schedules dwell jobs. Wrapped in try/catch so geofence errors never block the location update response.Zone/ServiceAreamodels — Added geofence config fields to$fillableand$casts.EventServiceProvider— Registered all three geofence events with their listeners andSendResourceLifecycleWebhook.FleetOpsServiceProvider— Singleton binding forGeofenceIntersectionService; registeredDriverArrivedAtGeofencenotification.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 anon(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— InjectedgeofenceEventBus; subscribed to geofence universe events; added#flashGeofenceLayerthat 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
php artisan migratedriver_geofence_statesrow created withis_inside = 1geofence_events_logrow created withevent_type = geofence.enteredgeofence.enteredWebSocket event received in browser consolegeofence.exitedevent fired and polygon flashes reddwell_threshold_minutes = 1and wait — confirmgeofence.dwelledevent firesGET /api/v1/geofences/eventsreturns the event logGET /api/v1/geofences/dwell-reportreturns aggregated dwell statsQueue Worker Configuration
Ensure a dedicated
geofencequeue worker is running: