@fleetbase/fleetops-engine 0.6.69 → 0.6.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RELEASE.md +41 -8
- package/addon/components/admin/telematics-settings.hbs +143 -0
- package/addon/components/admin/telematics-settings.js +145 -0
- package/addon/components/fuel-integration/hub.hbs +1 -1
- package/addon/components/layout/fleet-ops-sidebar.js +37 -17
- package/addon/components/map/leaflet-live-map.hbs +4 -242
- package/addon/components/map/leaflet-live-map.js +2 -1
- package/addon/components/map/marker-card/driver.hbs +57 -0
- package/addon/components/map/marker-card/driver.js +3 -0
- package/addon/components/map/marker-card/vehicle.hbs +78 -0
- package/addon/components/map/marker-card/vehicle.js +3 -0
- package/addon/components/telematic/hub.hbs +1 -1
- package/addon/components/widget/live-fleet.hbs +8 -40
- package/addon/controllers/analytics/reports/index.js +5 -0
- package/addon/controllers/connectivity/devices/index.js +4 -0
- package/addon/controllers/connectivity/fuel-providers/index.js +6 -4
- package/addon/controllers/connectivity/sensors/index.js +4 -0
- package/addon/controllers/connectivity/telematics/index.js +4 -0
- package/addon/controllers/maintenance/equipment/index.js +11 -4
- package/addon/controllers/maintenance/inspection-forms/index.js +2 -2
- package/addon/controllers/maintenance/inspection-submissions/index.js +8 -2
- package/addon/controllers/maintenance/maintenances/index.js +4 -0
- package/addon/controllers/maintenance/parts/index.js +11 -4
- package/addon/controllers/maintenance/schedules/index.js +17 -4
- package/addon/controllers/maintenance/work-orders/index.js +11 -4
- package/addon/controllers/management/contacts/index.js +4 -0
- package/addon/controllers/management/drivers/index.js +4 -0
- package/addon/controllers/management/fleets/index.js +4 -0
- package/addon/controllers/management/fuel-reports/index.js +4 -0
- package/addon/controllers/management/fuel-transactions/index.js +9 -7
- package/addon/controllers/management/issues/index.js +4 -0
- package/addon/controllers/management/places/index.js +4 -0
- package/addon/controllers/management/vehicles/index.js +4 -0
- package/addon/controllers/management/vendors/index.js +4 -0
- package/addon/controllers/operations/orders/index/details.js +30 -1
- package/addon/controllers/operations/orders/index.js +7 -0
- package/addon/controllers/operations/service-rates/index.js +3 -0
- package/addon/controllers/settings/index.js +13 -0
- package/addon/controllers/settings/telematics.js +113 -0
- package/addon/extension.js +38 -6
- package/addon/routes/analytics/index.js +14 -1
- package/addon/routes/analytics/reports/index/details.js +1 -1
- package/addon/routes/analytics/reports/index/edit.js +1 -1
- package/addon/routes/analytics/reports/index/new.js +14 -1
- package/addon/routes/analytics/reports.js +14 -1
- package/addon/routes/connectivity/devices/index/new.js +14 -1
- package/addon/routes/connectivity/devices.js +14 -1
- package/addon/routes/connectivity/events.js +14 -1
- package/addon/routes/connectivity/fuel-providers/details/transactions.js +12 -0
- package/addon/routes/connectivity/fuel-providers/details.js +9 -0
- package/addon/routes/connectivity/fuel-providers/edit.js +9 -0
- package/addon/routes/connectivity/fuel-providers/new.js +14 -1
- package/addon/routes/connectivity/fuel-providers.js +14 -1
- package/addon/routes/connectivity/sensors/index/new.js +14 -1
- package/addon/routes/connectivity/sensors.js +14 -1
- package/addon/routes/connectivity/telematics/new.js +14 -1
- package/addon/routes/connectivity/telematics.js +14 -1
- package/addon/routes/connectivity/tracking.js +14 -1
- package/addon/routes/maintenance/equipment/index/details.js +2 -2
- package/addon/routes/maintenance/equipment/index/edit.js +2 -2
- package/addon/routes/maintenance/equipment/index/new.js +14 -1
- package/addon/routes/maintenance/equipment.js +14 -1
- package/addon/routes/maintenance/index.js +14 -1
- package/addon/routes/maintenance/inspection-forms/index/details.js +10 -1
- package/addon/routes/maintenance/inspection-forms/index/edit.js +10 -1
- package/addon/routes/maintenance/inspection-forms/index/new.js +14 -1
- package/addon/routes/maintenance/inspection-forms.js +14 -1
- package/addon/routes/maintenance/inspection-submissions/index/details.js +10 -1
- package/addon/routes/maintenance/inspection-submissions/index/edit.js +10 -1
- package/addon/routes/maintenance/inspection-submissions/index/new.js +14 -1
- package/addon/routes/maintenance/inspection-submissions.js +14 -1
- package/addon/routes/maintenance/maintenances/index/details.js +2 -2
- package/addon/routes/maintenance/maintenances/index/edit.js +2 -2
- package/addon/routes/maintenance/maintenances/index/new.js +14 -1
- package/addon/routes/maintenance/maintenances.js +14 -1
- package/addon/routes/maintenance/parts/index/details.js +2 -2
- package/addon/routes/maintenance/parts/index/edit.js +2 -2
- package/addon/routes/maintenance/parts/index/new.js +14 -1
- package/addon/routes/maintenance/parts.js +14 -1
- package/addon/routes/maintenance/schedules/index/details.js +2 -2
- package/addon/routes/maintenance/schedules/index/edit.js +2 -2
- package/addon/routes/maintenance/schedules/index/new.js +15 -1
- package/addon/routes/maintenance/schedules.js +15 -1
- package/addon/routes/maintenance/work-orders/index/details.js +2 -2
- package/addon/routes/maintenance/work-orders/index/edit.js +2 -2
- package/addon/routes/maintenance/work-orders/index/new.js +14 -1
- package/addon/routes/maintenance/work-orders.js +14 -1
- package/addon/routes/management/fuel-transactions/index/details.js +9 -0
- package/addon/routes/management/fuel-transactions.js +14 -1
- package/addon/routes/management/index.js +13 -0
- package/addon/routes/management/trailers.js +16 -0
- package/addon/routes/management/vendors/integrated/details.js +14 -1
- package/addon/routes/management/vendors/integrated/edit.js +14 -1
- package/addon/routes/management/vendors/integrated/new.js +14 -1
- package/addon/routes/management/vendors/integrated.js +14 -1
- package/addon/routes/operations/orders.js +40 -1
- package/addon/routes/operations/routes/index/details.js +14 -1
- package/addon/routes/operations/routes/index/new.js +13 -0
- package/addon/routes/operations/routes.js +14 -1
- package/addon/routes/operations/service-rates/index/new.js +11 -0
- package/addon/routes/operations/service-rates.js +14 -1
- package/addon/routes/settings/avatars.js +14 -1
- package/addon/routes/settings/custom-fields.js +14 -1
- package/addon/routes/settings/map.js +14 -1
- package/addon/routes/settings/notifications.js +11 -0
- package/addon/routes/settings/orchestrator.js +1 -1
- package/addon/routes/settings/payments/index.js +1 -1
- package/addon/routes/settings/routing.js +14 -1
- package/addon/routes/settings/scheduling.js +14 -1
- package/addon/routes/settings/telematics.js +21 -0
- package/addon/routes/virtual.js +11 -0
- package/addon/routes.js +1 -0
- package/addon/templates/settings/telematics.hbs +70 -0
- package/app/components/admin/telematics-settings.js +1 -0
- package/app/components/map/marker-card/driver.js +1 -0
- package/app/components/map/marker-card/vehicle.js +1 -0
- package/app/controllers/settings/telematics.js +1 -0
- package/app/routes/settings/telematics.js +1 -0
- package/app/templates/settings/telematics.js +1 -0
- package/composer.json +2 -2
- package/docs/AFAQY.md +1 -1
- package/docs/TELEMATICS_QUEUES.md +1 -1
- package/docs/TELEMETRY_ARCHITECTURE.md +72 -1
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/config/telemetry.php +12 -0
- package/server/migrations/2026_09_23_000001_add_retention_index_to_device_events.php +40 -0
- package/server/migrations/2026_09_23_000002_add_retention_index_to_positions.php +40 -0
- package/server/migrations/2026_09_23_000003_add_retention_index_to_telematic_sync_runs.php +40 -0
- package/server/src/Auth/Schemas/FleetOps.php +104 -5
- package/server/src/Console/Commands/DrainTelematicInbox.php +3 -13
- package/server/src/Console/Commands/ProcessOperationalAlerts.php +3 -3
- package/server/src/Console/Commands/PruneTelematicsData.php +318 -0
- package/server/src/Http/Controllers/Api/v1/OrchestrationController.php +9 -0
- package/server/src/Http/Controllers/FleetOpsController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/CustomerController.php +14 -0
- package/server/src/Http/Controllers/Internal/v1/DeviceController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +22 -0
- package/server/src/Http/Controllers/Internal/v1/FuelProviderConnectionController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/FuelProviderTransactionController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/FuelReportController.php +9 -3
- package/server/src/Http/Controllers/Internal/v1/InspectionFormController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +16 -0
- package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/ManifestController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/MetricsController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +42 -1
- package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +12 -0
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +22 -0
- package/server/src/Http/Controllers/Internal/v1/PaymentController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/RadarController.php +19 -0
- package/server/src/Http/Controllers/Internal/v1/ServiceAreaController.php +9 -3
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +465 -14
- package/server/src/Http/Controllers/Internal/v1/TelematicController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/TrailerController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/VendorController.php +17 -0
- package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +11 -0
- package/server/src/Jobs/DispatchTelematicsRetentionJobs.php +70 -0
- package/server/src/Jobs/PruneTelematicsDataJob.php +74 -0
- package/server/src/Listeners/NotifyDriverOnShiftChange.php +3 -3
- package/server/src/Mail/CustomerCredentialsMail.php +1 -1
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +9 -1
- package/server/src/Providers/FleetOpsServiceProvider.php +3 -0
- package/server/src/Support/Analytics/LiveFleet.php +18 -2
- package/server/src/Support/Authorization.php +103 -0
- package/server/src/Support/Database/TableIndexes.php +66 -0
- package/server/src/Support/OrderTracker.php +2 -2
- package/server/src/Support/Reporting/FleetOpsReportSchema.php +476 -116
- package/server/src/Support/Telematics/Retention/RetentionPolicy.php +300 -0
- package/server/src/Support/Telematics/Retention/TelemetryActivity.php +40 -0
- package/server/src/Support/Telematics/TelematicService.php +12 -2
- package/server/src/Support/Telematics/Telemetry/Ingestor.php +4 -2
- package/server/src/Tracking/TrackingIntelligenceService.php +1 -1
- package/server/src/Tracking/TrackingOptions.php +2 -2
- package/server/src/Traits/AuthorizesMethods.php +37 -0
- package/server/src/routes.php +9 -1
- package/server/tests/AnalyticsRoutesTest.php +29 -2
- package/server/tests/Feature/Http/AfaqyRealtimeIngestionTest.php +16 -1
- package/server/tests/Feature/Http/Api/TelematicsRetentionIndexMigrationTest.php +115 -0
- package/server/tests/Feature/Http/Internal/SettingControllerHelpersTest.php +71 -0
- package/server/tests/Feature/Http/Internal/TelematicsStorageDeadlinesTest.php +119 -0
- package/server/tests/InternalImportExportControllerContractsTest.php +5 -8
- package/server/tests/NavigatorControllerContractsTest.php +36 -4
- package/server/tests/NotificationAndMailContractsTest.php +31 -0
- package/server/tests/ObserverContractsTest.php +1 -1
- package/server/tests/OrchestratorConsumableApiTest.php +42 -0
- package/server/tests/ProviderContractsTest.php +10 -0
- package/server/tests/ReportSchemaContractsTest.php +120 -6
- package/server/tests/SettingControllerContractsTest.php +429 -18
- package/server/tests/SmallControllerContractsTest.php +8 -5
- package/server/tests/Support/PruneTelematicsDataProbe.php +55 -0
- package/server/tests/Unit/Console/Commands/ProcessOperationalAlertsCommandTest.php +2 -2
- package/server/tests/Unit/Console/PruneTelematicsDataCommandTest.php +353 -0
- package/server/tests/Unit/Jobs/DispatchTelematicsRetentionJobsTest.php +114 -0
- package/server/tests/Unit/Jobs/PruneTelematicsDataJobTest.php +60 -0
- package/server/tests/Unit/Orchestration/VroomEngineTransportAndSettingsTest.php +20 -0
- package/server/tests/Unit/Support/Analytics/LiveFleetTest.php +6 -0
- package/server/tests/Unit/Support/AuthorizationTest.php +142 -0
- package/server/tests/Unit/Support/MaintainableAndOperationalAlertsTest.php +12 -1
- package/server/tests/Unit/Support/MoreQuerySeamsTest.php +11 -2
- package/server/tests/Unit/Support/Telematics/Retention/RetentionPolicyTest.php +190 -0
- package/server/tests/Unit/Support/Telematics/Retention/TelemetryActivityTest.php +68 -0
- package/server/tests/Unit/Tracking/TrackingOptionsCompanySettingsTest.php +109 -0
- package/translations/en-us.yaml +48 -0
|
@@ -48,11 +48,82 @@ persistence. The performance requirement did not justify those dependencies.
|
|
|
48
48
|
## Tradeoffs
|
|
49
49
|
|
|
50
50
|
Three shared tables separate run-level diagnostics, high-volume delivery retention,
|
|
51
|
-
and connection-level secrets with different lifetimes. Provider-specific protocol
|
|
51
|
+
and connection-level secrets with different lifetimes (see Retention below). Provider-specific protocol
|
|
52
52
|
classes remain appropriate. Capability opt-in avoids silently changing every
|
|
53
53
|
existing integration's ingestion or webhook behavior. Production throughput and
|
|
54
54
|
real AFAQY payload verification remain separate deployment gates.
|
|
55
55
|
|
|
56
|
+
## Retention
|
|
57
|
+
|
|
58
|
+
Every poll writes one `device_events` row, one `positions` row and a delivery
|
|
59
|
+
envelope per batch for each reporting device. Without a ceiling those tables grow
|
|
60
|
+
until the disk fills, so retention is enforced by `fleetops:prune-telematics-data`
|
|
61
|
+
(scheduled every fifteen minutes, `withoutOverlapping(14)`) using a per-company
|
|
62
|
+
policy resolved by `Support\Telematics\Retention\RetentionPolicy`:
|
|
63
|
+
|
|
64
|
+
| Layer | Source | Where it is edited |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| Package config | `server/config/telemetry.php` | deployment |
|
|
67
|
+
| System policy | setting `fleet-ops.telematics-settings` | Admin console → Fleet-Ops Config → Telematics |
|
|
68
|
+
| Company history preferences | `company.<uuid>.fleet-ops.telematics-settings` | Fleet-Ops → Settings → Telematics |
|
|
69
|
+
|
|
70
|
+
Defaults: device events 30 days, raw payload/meta stripped ("compacted") after
|
|
71
|
+
7 days, positions 90 days, processed deliveries 24 hours, quarantined deliveries
|
|
72
|
+
7 days, sync runs 7 days. Organizations can choose only device event and position
|
|
73
|
+
history retention, or inherit the system defaults. Administrators own raw payload,
|
|
74
|
+
delivery, sync-run retention and telemetry activity logging.
|
|
75
|
+
|
|
76
|
+
`max_event_retention_days` and `max_position_retention_days` constrain every
|
|
77
|
+
organization's history, including inherited defaults. A maximum of `0` allows
|
|
78
|
+
unlimited history; a history preference of `0` keeps records forever only while
|
|
79
|
+
that maximum is unset. Setting a finite maximum replaces saved unlimited or longer
|
|
80
|
+
preferences with that maximum. Missing preferences continue to inherit. Values
|
|
81
|
+
are also clamped to `RetentionPolicy::LIMITS`.
|
|
82
|
+
|
|
83
|
+
Admin storage diagnostics cover the entire system, including organizations the
|
|
84
|
+
administrator does not belong to. System cleanup queues work for every
|
|
85
|
+
organization plus orphaned records, with each organization's effective policy
|
|
86
|
+
applied independently. Storage sizes include table data and indexes; database row
|
|
87
|
+
estimates are labeled. Cleanup is asynchronous, so refreshing usage does not mean
|
|
88
|
+
all queued work has finished.
|
|
89
|
+
|
|
90
|
+
Manual system cleanup requires an asynchronous queue connection and a worker for
|
|
91
|
+
`telematics.telemetry.ingestion_queue`. A synchronous or disabled queue is rejected
|
|
92
|
+
instead of running every organization's cleanup inside the HTTP request.
|
|
93
|
+
|
|
94
|
+
Deploy the frontend and backend together and reload Octane and queue workers after
|
|
95
|
+
updating the backend. In linked development checkouts, Octane's watch paths must
|
|
96
|
+
include `packages/fleetops/server`; watching only the host API directory leaves
|
|
97
|
+
previously loaded controllers and policies running.
|
|
98
|
+
|
|
99
|
+
Rules the sweep follows:
|
|
100
|
+
|
|
101
|
+
- Hard deletes only. The models soft-delete, so `delete()` would grow the table;
|
|
102
|
+
rows already soft-deleted are purged regardless of age.
|
|
103
|
+
- Bounded work: at most `--max-batches` (default 50) statements of `--batch-size`
|
|
104
|
+
(default 1000) rows per table per company per run. A capped run is normal; the
|
|
105
|
+
next tick continues. Operators can catch up faster off-peak with
|
|
106
|
+
`php artisan fleetops:prune-telematics-data --max-batches=500 --no-lock`.
|
|
107
|
+
- Compaction keeps the event (type, severity, location, normalized `data`) and
|
|
108
|
+
nulls `payload` and `meta`, which hold the bulk of each row.
|
|
109
|
+
- `telematic_deliveries` and `telematic_sync_runs` carry no company; they are
|
|
110
|
+
resolved through the company's connections (including trashed ones). In-flight
|
|
111
|
+
sync runs (`fetching`, `ingesting`) are recovered by the drain, never expired.
|
|
112
|
+
- Rows whose company or connection no longer exists are swept with the system
|
|
113
|
+
defaults.
|
|
114
|
+
- Migrations add `(company_uuid, created_at)` on `device_events` and `positions`
|
|
115
|
+
and `(telematic_uuid, updated_at)` on `telematic_sync_runs`; on multi-GB tables
|
|
116
|
+
run them in a maintenance window.
|
|
117
|
+
- Deleting rows frees space inside InnoDB files, not on disk. Run
|
|
118
|
+
`OPTIMIZE TABLE device_events` (requires `innodb_file_per_table`) off-peak to
|
|
119
|
+
return it to the operating system.
|
|
120
|
+
|
|
121
|
+
Two write-amplification fixes accompany the sweep: `device_events.meta` stores only
|
|
122
|
+
the normalized block (the raw unit lives once, in `payload`), and telemetry-driven
|
|
123
|
+
saves run inside `activity()->withoutLogs()` unless the system administrator enables
|
|
124
|
+
"Log telemetry activity". `DrainTelematicInbox` now only recovers deliveries and
|
|
125
|
+
finishes interrupted runs.
|
|
126
|
+
|
|
56
127
|
## Adding an adapter
|
|
57
128
|
|
|
58
129
|
Implement `TelemetryProviderInterface` alongside the existing provider contract.
|
package/extension.json
CHANGED
package/package.json
CHANGED
|
@@ -13,8 +13,20 @@ return [
|
|
|
13
13
|
'batch_size' => env('TELEMATICS_BATCH_SIZE', 100),
|
|
14
14
|
'max_payload_bytes' => 2097152,
|
|
15
15
|
'max_pending_deliveries' => 10000,
|
|
16
|
+
// Administrators control infrastructure retention and activity logging.
|
|
17
|
+
// Companies may choose event/position history retention within the maximums.
|
|
18
|
+
// A maximum of 0 imposes no cap and permits unlimited history (retention 0).
|
|
16
19
|
'processed_retention_hours' => 24,
|
|
17
20
|
'quarantine_retention_days' => 7,
|
|
21
|
+
'sync_run_retention_days' => 7,
|
|
22
|
+
'event_retention_days' => 30,
|
|
23
|
+
'event_compact_after_days' => 7,
|
|
24
|
+
'position_retention_days' => 90,
|
|
25
|
+
'max_event_retention_days' => 0,
|
|
26
|
+
'max_position_retention_days' => 0,
|
|
27
|
+
'log_telemetry_activity' => false,
|
|
28
|
+
'prune_batch_size' => 1000,
|
|
29
|
+
'prune_max_batches' => 50,
|
|
18
30
|
'stale_engine_on_seconds' => 120,
|
|
19
31
|
'stale_engine_off_seconds' => 600,
|
|
20
32
|
];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Fleetbase\FleetOps\Support\Database\TableIndexes;
|
|
4
|
+
use Illuminate\Database\Migrations\Migration;
|
|
5
|
+
use Illuminate\Database\Schema\Blueprint;
|
|
6
|
+
use Illuminate\Support\Facades\Schema;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Supports the bounded retention sweep in fleetops:prune-telematics-data,
|
|
10
|
+
* which ranges over these columns for every company on every run.
|
|
11
|
+
*/
|
|
12
|
+
return new class extends Migration {
|
|
13
|
+
private const TABLE = 'device_events';
|
|
14
|
+
private const INDEX = 'device_events_company_created_at_index';
|
|
15
|
+
private const COLUMNS = ['company_uuid', 'created_at'];
|
|
16
|
+
|
|
17
|
+
public function up(): void
|
|
18
|
+
{
|
|
19
|
+
if (!Schema::hasTable(self::TABLE) || !Schema::hasColumns(self::TABLE, self::COLUMNS)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (TableIndexes::covers(self::TABLE, self::COLUMNS)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Schema::table(self::TABLE, fn (Blueprint $table) => $table->index(self::COLUMNS, self::INDEX));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public function down(): void
|
|
31
|
+
{
|
|
32
|
+
if (!Schema::hasTable(self::TABLE)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if ((TableIndexes::for(self::TABLE)[self::INDEX] ?? null) === self::COLUMNS) {
|
|
37
|
+
Schema::table(self::TABLE, fn (Blueprint $table) => $table->dropIndex(self::INDEX));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Fleetbase\FleetOps\Support\Database\TableIndexes;
|
|
4
|
+
use Illuminate\Database\Migrations\Migration;
|
|
5
|
+
use Illuminate\Database\Schema\Blueprint;
|
|
6
|
+
use Illuminate\Support\Facades\Schema;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Supports the bounded retention sweep in fleetops:prune-telematics-data,
|
|
10
|
+
* which ranges over these columns for every company on every run.
|
|
11
|
+
*/
|
|
12
|
+
return new class extends Migration {
|
|
13
|
+
private const TABLE = 'positions';
|
|
14
|
+
private const INDEX = 'positions_company_created_at_index';
|
|
15
|
+
private const COLUMNS = ['company_uuid', 'created_at'];
|
|
16
|
+
|
|
17
|
+
public function up(): void
|
|
18
|
+
{
|
|
19
|
+
if (!Schema::hasTable(self::TABLE) || !Schema::hasColumns(self::TABLE, self::COLUMNS)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (TableIndexes::covers(self::TABLE, self::COLUMNS)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Schema::table(self::TABLE, fn (Blueprint $table) => $table->index(self::COLUMNS, self::INDEX));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public function down(): void
|
|
31
|
+
{
|
|
32
|
+
if (!Schema::hasTable(self::TABLE)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if ((TableIndexes::for(self::TABLE)[self::INDEX] ?? null) === self::COLUMNS) {
|
|
37
|
+
Schema::table(self::TABLE, fn (Blueprint $table) => $table->dropIndex(self::INDEX));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
use Fleetbase\FleetOps\Support\Database\TableIndexes;
|
|
4
|
+
use Illuminate\Database\Migrations\Migration;
|
|
5
|
+
use Illuminate\Database\Schema\Blueprint;
|
|
6
|
+
use Illuminate\Support\Facades\Schema;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Supports the bounded retention sweep in fleetops:prune-telematics-data,
|
|
10
|
+
* which ranges over these columns for every company on every run.
|
|
11
|
+
*/
|
|
12
|
+
return new class extends Migration {
|
|
13
|
+
private const TABLE = 'telematic_sync_runs';
|
|
14
|
+
private const INDEX = 'telematic_sync_runs_telematic_updated_at_index';
|
|
15
|
+
private const COLUMNS = ['telematic_uuid', 'updated_at'];
|
|
16
|
+
|
|
17
|
+
public function up(): void
|
|
18
|
+
{
|
|
19
|
+
if (!Schema::hasTable(self::TABLE) || !Schema::hasColumns(self::TABLE, self::COLUMNS)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (TableIndexes::covers(self::TABLE, self::COLUMNS)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Schema::table(self::TABLE, fn (Blueprint $table) => $table->index(self::COLUMNS, self::INDEX));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public function down(): void
|
|
31
|
+
{
|
|
32
|
+
if (!Schema::hasTable(self::TABLE)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if ((TableIndexes::for(self::TABLE)[self::INDEX] ?? null) === self::COLUMNS) {
|
|
37
|
+
Schema::table(self::TABLE, fn (Blueprint $table) => $table->dropIndex(self::INDEX));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
@@ -43,7 +43,7 @@ class FleetOps
|
|
|
43
43
|
],
|
|
44
44
|
[
|
|
45
45
|
'name' => 'service-rate',
|
|
46
|
-
'actions' => ['import'],
|
|
46
|
+
'actions' => ['import', 'export'],
|
|
47
47
|
],
|
|
48
48
|
[
|
|
49
49
|
'name' => 'zone',
|
|
@@ -141,6 +141,51 @@ class FleetOps
|
|
|
141
141
|
'name' => 'part',
|
|
142
142
|
'actions' => ['export', 'import'],
|
|
143
143
|
],
|
|
144
|
+
[
|
|
145
|
+
'name' => 'maintenance-schedule',
|
|
146
|
+
'actions' => ['export', 'import'],
|
|
147
|
+
],
|
|
148
|
+
[
|
|
149
|
+
'name' => 'warranty',
|
|
150
|
+
'actions' => [],
|
|
151
|
+
],
|
|
152
|
+
[
|
|
153
|
+
'name' => 'device',
|
|
154
|
+
'actions' => ['export', 'import'],
|
|
155
|
+
],
|
|
156
|
+
[
|
|
157
|
+
'name' => 'sensor',
|
|
158
|
+
'actions' => ['export', 'import'],
|
|
159
|
+
],
|
|
160
|
+
[
|
|
161
|
+
'name' => 'device-event',
|
|
162
|
+
'actions' => ['export'],
|
|
163
|
+
],
|
|
164
|
+
[
|
|
165
|
+
'name' => 'telematic',
|
|
166
|
+
'actions' => ['export', 'import'],
|
|
167
|
+
],
|
|
168
|
+
[
|
|
169
|
+
'name' => 'fuel-provider-connection',
|
|
170
|
+
'actions' => ['sync'],
|
|
171
|
+
],
|
|
172
|
+
[
|
|
173
|
+
'name' => 'fuel-provider-transaction',
|
|
174
|
+
'actions' => ['review'],
|
|
175
|
+
],
|
|
176
|
+
[
|
|
177
|
+
'name' => 'fuel-provider-sync-run',
|
|
178
|
+
'actions' => [],
|
|
179
|
+
],
|
|
180
|
+
[
|
|
181
|
+
'name' => 'purchase-rate',
|
|
182
|
+
'actions' => [],
|
|
183
|
+
],
|
|
184
|
+
[
|
|
185
|
+
'name' => 'analytics', // dashboards, KPI metrics and the live fleet summary
|
|
186
|
+
'actions' => [],
|
|
187
|
+
'remove_actions' => ['create', 'update', 'delete', 'export'],
|
|
188
|
+
],
|
|
144
189
|
[
|
|
145
190
|
'name' => 'custom-field',
|
|
146
191
|
'actions' => [],
|
|
@@ -151,26 +196,41 @@ class FleetOps
|
|
|
151
196
|
],
|
|
152
197
|
[
|
|
153
198
|
'name' => 'navigator-settings', // the navigator mobile app used by drivers
|
|
154
|
-
'
|
|
199
|
+
'actions' => [],
|
|
155
200
|
'remove_actions' => ['delete', 'export', 'list', 'create'],
|
|
156
201
|
],
|
|
157
202
|
[
|
|
158
203
|
'name' => 'payments',
|
|
159
|
-
'
|
|
204
|
+
'actions' => ['onboard'],
|
|
160
205
|
'remove_actions' => ['delete', 'export', 'list', 'create'],
|
|
161
206
|
],
|
|
162
207
|
[
|
|
163
208
|
'name' => 'notification-settings',
|
|
164
|
-
'
|
|
209
|
+
'actions' => [],
|
|
165
210
|
'remove_actions' => ['export', 'create'],
|
|
166
211
|
],
|
|
167
212
|
[
|
|
168
213
|
'name' => 'routing-settings',
|
|
169
|
-
'
|
|
214
|
+
'actions' => [],
|
|
170
215
|
'remove_actions' => ['export', 'create'],
|
|
171
216
|
],
|
|
172
217
|
[
|
|
173
218
|
'name' => 'map-settings',
|
|
219
|
+
'actions' => [],
|
|
220
|
+
'remove_actions' => ['export', 'create'],
|
|
221
|
+
],
|
|
222
|
+
[
|
|
223
|
+
'name' => 'scheduling-settings',
|
|
224
|
+
'actions' => [],
|
|
225
|
+
'remove_actions' => ['delete', 'export', 'create'],
|
|
226
|
+
],
|
|
227
|
+
[
|
|
228
|
+
'name' => 'tracking-settings',
|
|
229
|
+
'actions' => [],
|
|
230
|
+
'remove_actions' => ['delete', 'export', 'create'],
|
|
231
|
+
],
|
|
232
|
+
[
|
|
233
|
+
'name' => 'telematics-settings', // organization device event and position history preferences
|
|
174
234
|
'action' => [],
|
|
175
235
|
'remove_actions' => ['export', 'create'],
|
|
176
236
|
],
|
|
@@ -187,6 +247,9 @@ class FleetOps
|
|
|
187
247
|
'see extension',
|
|
188
248
|
'* order',
|
|
189
249
|
'* route',
|
|
250
|
+
'see analytics',
|
|
251
|
+
'list analytics',
|
|
252
|
+
'view analytics',
|
|
190
253
|
'see order-config',
|
|
191
254
|
'list order-config',
|
|
192
255
|
'view order-config',
|
|
@@ -230,6 +293,12 @@ class FleetOps
|
|
|
230
293
|
'* driver',
|
|
231
294
|
'* vehicle',
|
|
232
295
|
'* trailer',
|
|
296
|
+
'* device',
|
|
297
|
+
'* sensor',
|
|
298
|
+
'* telematic',
|
|
299
|
+
'see device-event',
|
|
300
|
+
'list device-event',
|
|
301
|
+
'view device-event',
|
|
233
302
|
],
|
|
234
303
|
],
|
|
235
304
|
[
|
|
@@ -277,6 +346,7 @@ class FleetOps
|
|
|
277
346
|
'permissions' => [
|
|
278
347
|
'see extension',
|
|
279
348
|
'* service-rate',
|
|
349
|
+
'* purchase-rate',
|
|
280
350
|
'see order',
|
|
281
351
|
'list order',
|
|
282
352
|
'see service-area',
|
|
@@ -309,6 +379,8 @@ class FleetOps
|
|
|
309
379
|
'* inspection-submission',
|
|
310
380
|
'* equipment',
|
|
311
381
|
'* part',
|
|
382
|
+
'* maintenance-schedule',
|
|
383
|
+
'* warranty',
|
|
312
384
|
'* trailer',
|
|
313
385
|
'see vehicle',
|
|
314
386
|
'list vehicle',
|
|
@@ -336,6 +408,18 @@ class FleetOps
|
|
|
336
408
|
'* inspection-submission',
|
|
337
409
|
'* equipment',
|
|
338
410
|
'* part',
|
|
411
|
+
'* maintenance-schedule',
|
|
412
|
+
'* warranty',
|
|
413
|
+
'* device',
|
|
414
|
+
'* sensor',
|
|
415
|
+
'* device-event',
|
|
416
|
+
'* telematic',
|
|
417
|
+
'* fuel-provider-connection',
|
|
418
|
+
'* fuel-provider-transaction',
|
|
419
|
+
'* fuel-provider-sync-run',
|
|
420
|
+
'see analytics',
|
|
421
|
+
'list analytics',
|
|
422
|
+
'view analytics',
|
|
339
423
|
'* trailer',
|
|
340
424
|
],
|
|
341
425
|
],
|
|
@@ -353,6 +437,14 @@ class FleetOps
|
|
|
353
437
|
'list vehicle',
|
|
354
438
|
],
|
|
355
439
|
],
|
|
440
|
+
[
|
|
441
|
+
'name' => 'TelematicsSettingsManager',
|
|
442
|
+
'description' => 'Policy for managing organization telematics history preferences.',
|
|
443
|
+
'permissions' => [
|
|
444
|
+
'see extension',
|
|
445
|
+
'* telematics-settings',
|
|
446
|
+
],
|
|
447
|
+
],
|
|
356
448
|
[
|
|
357
449
|
'name' => 'DriverOperations',
|
|
358
450
|
'description' => 'Policy for drivers to manage their assigned tasks and access necessary information.',
|
|
@@ -453,6 +545,13 @@ class FleetOps
|
|
|
453
545
|
'NavigatorSettingsManager',
|
|
454
546
|
],
|
|
455
547
|
],
|
|
548
|
+
[
|
|
549
|
+
'name' => 'Telematics Settings Manager',
|
|
550
|
+
'description' => 'Role responsible for managing organization telematics history preferences.',
|
|
551
|
+
'policies' => [
|
|
552
|
+
'TelematicsSettingsManager',
|
|
553
|
+
],
|
|
554
|
+
],
|
|
456
555
|
[
|
|
457
556
|
'name' => 'Driver',
|
|
458
557
|
'description' => 'Role for drivers with the necessary access to manage their daily tasks, including order management, and vehicle assignment.',
|
|
@@ -16,7 +16,7 @@ use Illuminate\Support\Facades\Log;
|
|
|
16
16
|
class DrainTelematicInbox extends Command
|
|
17
17
|
{
|
|
18
18
|
protected $signature = 'fleetops:drain-telematic-inbox';
|
|
19
|
-
protected $description = 'Recover pending telematic deliveries and
|
|
19
|
+
protected $description = 'Recover pending telematic deliveries and finish interrupted sync runs.';
|
|
20
20
|
|
|
21
21
|
public function handle(): int
|
|
22
22
|
{
|
|
@@ -58,24 +58,14 @@ class DrainTelematicInbox extends Command
|
|
|
58
58
|
try {
|
|
59
59
|
Queue::dispatch((new ProcessTelematicDelivery($row->uuid))->onQueue($optionsByConnection[$row->telematic_uuid]['ingestion_queue'] ?? 'default'));
|
|
60
60
|
} catch (\Throwable) {
|
|
61
|
-
// A broker outage must not prevent
|
|
61
|
+
// A broker outage must not prevent run recovery; retry the next minute.
|
|
62
62
|
break;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
//
|
|
66
|
-
foreach (['processed' => now()->subHours(config('telematics.telemetry.processed_retention_hours', 24)), 'quarantined' => now()->subDays(config('telematics.telemetry.quarantine_retention_days', 7))] as $status => $cutoff) {
|
|
67
|
-
for ($batch = 0; $batch < 20; $batch++) {
|
|
68
|
-
$ids = DB::table('telematic_deliveries')->where('status', $status)->where('updated_at', '<', $cutoff)->limit(1000)->pluck('uuid');
|
|
69
|
-
if ($ids->isEmpty()) {
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
DB::table('telematic_deliveries')->whereIn('uuid', $ids)->delete();
|
|
73
|
-
}
|
|
74
|
-
}
|
|
65
|
+
// Retention for deliveries and sync runs is applied by fleetops:prune-telematics-data.
|
|
75
66
|
DB::table('telematic_sync_runs')->where('status', 'fetching')->where('updated_at', '<', now()->subMinutes(5))
|
|
76
67
|
->update(['status' => 'incomplete', 'error' => 'Worker interrupted; next scheduled sweep will recover.']);
|
|
77
68
|
DB::table('telematic_sync_runs')->where('status', 'ingesting')->get(['uuid'])->each(fn ($run) => Inbox::finishRun($run->uuid));
|
|
78
|
-
DB::table('telematic_sync_runs')->where('updated_at', '<', now()->subDays(7))->delete();
|
|
79
69
|
|
|
80
70
|
return self::SUCCESS;
|
|
81
71
|
}
|
|
@@ -60,7 +60,7 @@ class ProcessOperationalAlerts extends Command
|
|
|
60
60
|
|
|
61
61
|
foreach ($orders as $order) {
|
|
62
62
|
session(['company' => $order->company_uuid]);
|
|
63
|
-
$settings = $this->alertSettings();
|
|
63
|
+
$settings = $this->alertSettings($order);
|
|
64
64
|
|
|
65
65
|
if ($this->processLateDeparture($order, $settings, $dryRun)) {
|
|
66
66
|
$triggered++;
|
|
@@ -256,9 +256,9 @@ class ProcessOperationalAlerts extends Command
|
|
|
256
256
|
->min() ?? 0;
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
protected function alertSettings(): array
|
|
259
|
+
protected function alertSettings(Order $order): array
|
|
260
260
|
{
|
|
261
|
-
$settings = Setting::
|
|
261
|
+
$settings = Setting::lookupForCompany($order->company_uuid, 'tracking', []);
|
|
262
262
|
$alerts = data_get($settings, 'alerts', []);
|
|
263
263
|
|
|
264
264
|
return [
|