Skip to main content

Trips Overview

The Trip system records transport operations: plan a route, start tracking, pause or resume, then complete. Each trip can optionally log GPS data from a linked device.

Status Machine

draft → active ↔ paused → completed
TransitionTriggered bySide effect
draft → active"Start Trip"Sets started_at; saves start_latitude/start_longitude
active → paused"Pause Trip"Saves history_latitude/history_longitude to status history entry
paused → active"Resume Trip"Saves history_latitude/history_longitude to status history entry
active → completed"Complete Trip"Sets ended_at; saves end_latitude/end_longitude
paused → completed"Complete Trip"Sets ended_at; saves end_latitude/end_longitude
completed → *No further transitions allowed

Trip Fields

FieldTypeDescription
idUUIDTrip ID
namestringTrip name
descriptionstring?Optional description
statusstringdraft, active, paused, completed
gps_logging_enabledboolWhether GPS points are linked to this trip
device_idUUID?GPS device for logging
category_idUUID?Transport category
origin_idUUID?Sender location
destination_idUUID?Receiver location
weight_kgfloat?Payload weight in kg (display as tons: ÷ 1000)
tagsstring[]Free-text tags
notesstring?Free-text notes
start_latitudefloat?GPS latitude when trip was started
start_longitudefloat?GPS longitude when trip was started
end_latitudefloat?GPS latitude when trip was completed
end_longitudefloat?GPS longitude when trip was completed
started_attimestamp?Set on first activation
ended_attimestamp?Set on completion

REST Endpoints

MethodPathPermissionDescription
GET/v1/tripstrips:readList trips (paginated, filterable by status)
GET/v1/trips/{id}trips:readGet trip with resolved relations
POST/v1/tripstrips:writeCreate trip
PATCH/v1/trips/{id}trips:writeUpdate trip / trigger status transition
DELETE/v1/trips/{id}trips:deleteDelete trip (draft/completed only)
GET/v1/trips/{id}/gpstrips:readGPS data for trip (paginated)
GET/v1/trips/{id}/exporttrips:readExport trip (?format=pdf, csv, or txt)

GraphQL

  • trips(page, limit, status)PaginatedTrips
  • trip(id)GqlTrip
  • tripGpsData(tripId, page, limit)PaginatedGpsData
  • tripExportData(tripId)GqlTripExport
  • createTrip(input)GqlTrip
  • updateTrip(id, input)GqlTrip
  • deleteTrip(id)Boolean

GqlTrip includes resolved relations: category, origin, destination, device, gpsPointCount, and weightTons (computed as weight_kg / 1000).

Status Update with Coordinates

When changing trip status via updateTrip (GraphQL) or PATCH /v1/trips/{id} (REST with status_action), the following coordinate fields can be passed:

FieldSaved toWhen to use
start_latitude / start_longitudeTrip recordOn start action (origin GPS position)
end_latitude / end_longitudeTrip recordOn complete action (destination GPS position)
history_latitude / history_longitudeStatus history entryOn any status change (current GPS position for map badge)

The coordinate source is typically the current GPS position of the linked device, or the geocoded coordinates of the origin/destination location. The history_* fields fall back to start_* or end_* coordinates if not explicitly provided.

GPS Logging Integration

When gps_logging_enabled = true and the trip is active, every GPS point received for the linked device_id is automatically tagged with trip_id.

Constraint: Only one active trip per device may have gps_logging_enabled = true at a time. Attempting to activate a second one returns 409 Conflict.

Deletion Rules

StatusDeletable
draftYes
activeNo — complete first
pausedNo — complete first
completedYes (NULLs trip_id on linked GPS data)

Trip View Page

The trip detail page (/trips/[id]) provides a read-only overview of a trip with:

  • Route Map — MapRoute visualization of GPS data with start/end markers, auto-fit bounds
  • Live Map — Active trips with GPS logging show a live map with LiveMarker (real-time GPS position), route polyline, start/end markers, and pause badges
  • Pause Badges — Pause markers rendered on the route map at the GPS coordinates where each pause occurred, with a duration badge showing how long the trip was paused
  • Live Tracking — WebSocket-based real-time GPS updates when trip is active with GPS logging
  • Stats Cards — Duration, GPS points count, weight (kg/tons), status duration
  • Route Info — Origin and destination locations
  • Details — Category (with color), device, GPS logging status, tags
  • Timeline — Status change history with timestamps (created, started, paused, resumed, completed)
  • Notes — Read-only trip notes
  • GPS Data Table — Collapsible, paginated table of GPS data points
  • Status Actions — Start/Pause/Resume/Complete buttons (same as overview list)
  • Export — PDF, CSV, and TXT download (see below)

Trip Exports

Export is available from the trip view page via the export button. Supported formats:

FormatContent
PDFFull trip report with route info, stats, timeline/status history, and notes
CSVTabular trip data including GPS points and status history
TXTPlain-text summary of trip details and timeline

All export formats include the status change timeline. Available via REST (GET /v1/trips/{id}/export?format=pdf|csv|txt) or GraphQL (tripExportData(tripId)).

Trip Status History

Every status transition is logged in the TripStatusHistory table.

Fields

FieldTypeDescription
idUUIDPrimary key
trip_idUUIDReference to Trip
old_statusstringPrevious status
new_statusstringNew status
changed_byUUID?User who changed the status
latitudefloat?GPS latitude at the time of status change
longitudefloat?GPS longitude at the time of status change
changed_attimestampWhen the change occurred

Coordinates are populated from history_latitude/history_longitude passed during the update request (falls back to start_latitude or end_latitude if not provided). This is used to display pause badges on the route map.

REST Endpoint

MethodPathPermissionDescription
GET/api/trips/:id/historytrips:readGet status change history

GraphQL

query TripStatusHistory($tripId: ID!) {
tripStatusHistory(tripId: $tripId) {
id tripId oldStatus newStatus changedBy latitude longitude changedAt
}
}

Audit Events

All trip-related mutations are logged as audit events under the modules category:

EventLogged when
trip_createdNew trip created (including from template)
trip_updatedTrip updated (fields or status change)
trip_deletedTrip deleted
location_createdLocation created
location_updatedLocation updated
location_deletedLocation deleted
trip_category_createdCategory created
trip_category_updatedCategory updated
trip_category_deletedCategory deleted
trip_template_createdTemplate created
trip_template_updatedTemplate updated
trip_template_deletedTemplate deleted

Events are logged in both REST and GraphQL handlers using constants from heimdall_audit::events.

Save as Template

On the trip create page (/trips/create), users can:

  1. Load a template from a dropdown to pre-fill form fields
  2. Save the current form as a new template via the "Save as Template" button