You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
2. Handler calls `tracker.ActiveVehicles()`, which reads the in-memory map and returns only vehicles whose `UpdatedAt` is newer than `time.Now().Add(-maxAge)`.
275
-
3.`buildFeed()` constructs a `gtfs.FeedMessage` with a `FULL_DATASET` header and one `VehiclePosition` entity per active vehicle. `TripDescriptor` is omitted when `trip_id`is empty.
275
+
3.`buildFeed()` constructs a `gtfs.FeedMessage` with a `FULL_DATASET` header and one `VehiclePosition` entity per active vehicle. `TripDescriptor`carries `trip_id`, `route_id` and `start_date` as sent, and is omitted when both `trip_id`and `route_id` are empty.
276
276
4. Response is serialized with `proto.Marshal` (protobuf, default) or `protojson.Marshal` (`?format=json`) and written with the appropriate `Content-Type`.
277
277
278
278
### 5.3 Sequence Diagrams
@@ -361,7 +361,9 @@ Authentication is per endpoint, not global:
361
361
```json
362
362
{
363
363
"vehicle_id": "bus-42",
364
-
"trip_id": "route-5",
364
+
"trip_id": "t_5_0830",
365
+
"route_id": "5",
366
+
"start_date": "20260715",
365
367
"latitude": -1.2921,
366
368
"longitude": 36.8219,
367
369
"bearing": 90.0,
@@ -374,7 +376,9 @@ Authentication is per endpoint, not global:
374
376
| Field | Required | Description |
375
377
|-------|----------|-------------|
376
378
|`vehicle_id`| ✅ | Non-empty string identifier for the vehicle. |
377
-
|`trip_id`| ❌ | Optional trip identifier; empty string is allowed and results in no `TripDescriptor` in the feed. |
379
+
|`trip_id`| ❌ | GTFS `trip_id`. Empty when the driver only knows the route; never a route id. Max 100 characters. |
380
+
|`route_id`| ❌ | GTFS `route_id`. Max 100 characters. |
381
+
|`start_date`| ❌ | Service date `YYYYMMDD`; accepted only with `trip_id` or `route_id`. |
378
382
|`latitude`| ✅ | Decimal degrees, range `-90` to `90`. Cannot be `0` when `longitude` is also `0`. |
379
383
|`longitude`| ✅ | Decimal degrees, range `-180` to `180`. |
380
384
|`bearing`| ❌ | Direction of travel in degrees. |
@@ -389,6 +393,11 @@ Authentication is per endpoint, not global:
389
393
-`latitude` must be in the range `-90` to `90`. Error: `latitude must be between -90 and 90`.
390
394
-`longitude` must be in the range `-180` to `180`. Error: `longitude must be between -180 and 180`.
391
395
-`timestamp` must be positive. Error: `timestamp must be positive`.
396
+
-`trip_id` is capped at 100 characters. Error: `trip_id must be at most 100 characters`.
397
+
-`route_id` is capped at 100 characters. Error: `route_id must be at most 100 characters`.
398
+
-`start_date` must match `YYYYMMDD`. Error: `start_date must be YYYYMMDD`.
399
+
-`start_date` must be a real calendar date. Error: `start_date must be a valid YYYYMMDD date`.
400
+
-`start_date` requires `trip_id` or `route_id` to be non-empty. Error: `start_date requires trip_id or route_id`.
392
401
393
402
**Decoding behavior:**
394
403
@@ -408,7 +417,7 @@ The feed is generated on every request entirely from the in-memory Tracker — t
408
417
-**Header:** GTFS-Realtime version `2.0`, incrementality `FULL_DATASET`, current Unix timestamp.
409
418
- One `FeedEntity` per active vehicle (`id = vehicle_id`).
410
419
- Each entity carries a `VehiclePosition` with `Position` (latitude, longitude, bearing, speed), a `VehicleDescriptor` (`id` only), and an epoch `Timestamp` copied from the incoming report.
411
-
- A `TripDescriptor`(`trip_id`) only when `trip_id` is non-empty.
420
+
- A `TripDescriptor`with `trip_id`, `route_id` and `start_date` as reported, only when `trip_id` or `route_id` is non-empty.
412
421
413
422
Consumers can request JSON encoding by appending `?format=json` to the URL. The default response is binary protobuf (`application/x-protobuf`). Any other `format` value falls back to protobuf because only the exact string `json` is checked.
Copy file name to clipboardExpand all lines: README.md
+8-3Lines changed: 8 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -201,7 +201,7 @@ The server produces a standard `FeedMessage` containing `VehiclePosition` entiti
201
201
```protobuf
202
202
vehicle {
203
203
trip {
204
-
trip_id: "route_5_0830"
204
+
trip_id: "t_5_0830"
205
205
route_id: "5"
206
206
start_time: "08:30:00"
207
207
start_date: "20260715"
@@ -248,7 +248,9 @@ Each location report is a single point sent directly from the Android app as it
248
248
```json
249
249
{
250
250
"vehicle_id": "vehicle-042",
251
-
"trip_id": "route_5_0830",
251
+
"trip_id": "t_5_0830",
252
+
"route_id": "5",
253
+
"start_date": "20260715",
252
254
"latitude": -1.2921,
253
255
"longitude": 36.8219,
254
256
"bearing": 180.0,
@@ -260,6 +262,8 @@ Each location report is a single point sent directly from the Android app as it
260
262
261
263
The server updates its in-memory state with the latest position and persists the point to the database. Points older than a configurable staleness threshold (default 5 minutes) are excluded from the GTFS-RT feed.
262
264
265
+
> `trip_id`, `route_id` and `start_date` are all optional. `trip_id` is the GTFS `trip_id` and must be left empty when the driver only knows the route — never send a route id in `trip_id`. `route_id` is the GTFS `route_id`; when `trip_id` is empty it is the only thing a consumer can match on. `start_date` is the service date, `YYYYMMDD`, and is accepted only alongside `trip_id` or `route_id`. The feed's `TripDescriptor` carries exactly the fields that were sent, and is omitted entirely when both `trip_id` and `route_id` are empty.
266
+
263
267
**`POST /api/v1/locations` validation and error contract**
264
268
265
269
The ingest endpoint performs strict request validation before writing data:
@@ -268,6 +272,7 @@ The ingest endpoint performs strict request validation before writing data:
268
272
- The request body must contain exactly one JSON object.
269
273
- Unknown JSON fields are rejected.
270
274
- Standard payload validation still applies (`vehicle_id`, coordinates, timestamp).
275
+
-`trip_id` and `route_id` are capped at 100 characters; `start_date` must be a real `YYYYMMDD` date.
271
276
272
277
Response codes:
273
278
@@ -281,7 +286,7 @@ Examples:
281
286
# Valid request
282
287
curl -i -X POST http://localhost:8080/api/v1/locations \
0 commit comments