FluxyChat

Platform

Fleet

HTTP GPS ingest, geofences, trips and delivery dispatch on D1 — not MQTT.

Fleet module

Vehicles POST GPS over HTTP to the Worker (/fleet/*, D1-backed). The room WebSocket fans out server_event fleet.gps_update with enter/exit geofence transitions. There is no native MQTT transport (see What you bring).

Scaffold

npx @fluxy-chat/create-fluxy-chat@latest my-fleet --example fleet-panel

Register a vehicle with a member JWT. The Worker returns apiKey (fleet_…) once — store it on the tracker.

curl -X POST "$WORKER/fleet/vehicles" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{"name":"Van 1","plate":"AB123CD"}'

curl -X POST "$WORKER/fleet/gps" \
  -H "Authorization: Bearer $FLEET_VEHICLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lat":45.46,"lng":9.18,"roomId":"YOUR_ROOM"}'

The ingest accepts OwnTracks location JSON (_type:"location", lat/lon/tst, acc/vel/cog/tid/batt) and arrays of points; lwt and other _types are skipped. With X-Limit-User/X-Limit-Device headers a body without vehicleId is keyed as user:device. Without roomId the fan-out room is fleet:{projectId}.

SDK

import { FluxyChatClient, createWorkerFluxyFleetClient } from "@fluxy-chat/sdk";

const client = new FluxyChatClient({ baseUrl, userId, token }); // member JWT
const fleet = createWorkerFluxyFleetClient(client);

const { vehicle, apiKey } = await fleet.createVehicle({ name: "Van 1", plate: "AB123CD" });
await fleet.ingestGps(
  { _type: "location", lat: 45.46, lon: 9.18, tst: Date.now() / 1000 },
  { vehicleKey: apiKey }, // device auth: works on this route only
);

await fleet.listCurrentPositions(); // online vehicles (offline after 10 min)
await fleet.listGpsHistory(vehicle.id, { from: Date.now() - 3_600_000, limit: 500 });

const fence = await fleet.createGeofence({ name: "Depot", lat: 45.46, lng: 9.18, radiusMeters: 250 });
await fleet.listGeofenceEvents({ vehicleId: vehicle.id }); // enter/exit rows

const trip = await fleet.createTrip({ vehicleId: vehicle.id, pickupLat: 45.4, pickupLng: 9.1, dropoffLat: 45.5, dropoffLng: 9.2 });
await fleet.updateTripStatus(trip.id, "active"); // pending → active → completed|cancelled

await fleet.findNearestDrivers(45.4, 9.1, 3);
await fleet.matchDelivery({ pickupLat: 45.4, pickupLng: 9.1, dropoffLat: 45.5, dropoffLng: 9.2 }); // 404 no_available_drivers

The legacy instance methods on FluxyChatClient (client.createFleetVehicle(), client.listFleetTrips() …) still work for JWT callers; the worker client is the surface with device-key ingest and batch support.

Realtime

useChat({
  roomId,
  onServerEvent: (ev) => {
    if (ev.name === "fleet.gps_update") {
      // ev.data: vehicleId, lat, lng, speed, heading, ts, tid, batt, geofenceEvents
    }
  },
});

Tracking surface

AreaRoutes
IngestPOST /fleet/gps (single or array, vehicle key or JWT)
PositionsGET /fleet/gps/current · GET /fleet/gps/last (alias)
HistoryGET /fleet/gps/history?vehicleId=&from=&to=&limit= · GET /fleet/gps/locations (alias; from/to unix ms, unix seconds or ISO date, default last hour)
VehiclesGET/POST /fleet/vehicles, PATCH /fleet/vehicles/{id}
TripsGET/POST /fleet/trips, PATCH /fleet/trips/{id} (pending → active → completed|cancelled; distances via haversine)
GeofencesGET/POST /fleet/geofences, PATCH/DELETE /fleet/geofences/{id} — enter/exit transitions are latched per vehicle and stored
EventsGET /fleet/geofence-events?vehicleId=&geofenceId=&limit=
DeliveryPOST /fleet/delivery/nearest, POST /fleet/delivery/match

Limits

60 GPS points per vehicle per minute (over that: HTTP 429 quota_exceeded + retryAfterSeconds). A vehicle lists offline after 10 minutes without points. Caps: history 10,000 points, geofence events 500, trips 100.

Readiness

PieceStatus
GPS ingest, positions, history, vehicles, trips, geofences, eventsBeta — Worker + D1, route and SDK tests
Delivery nearest/match (ETA heuristic)Beta (heuristic) — distance over ~30 km/h
Route copilot / delivery window / pricingPreview (heuristic) — hour-of-day traffic table and randomised weather, past-trip averages, live demand ratio. Not live traffic, maps or ML
fleet-panel scaffoldWorking example

What you bring

  • Trackers or a simulator: any device that can POST JSON works; OwnTracks is supported out of the box. If your fleet speaks MQTT, run an MQTT→HTTP bridge — the Worker owns auth, quota, storage and fan-out, not the device session.
  • Maps, geocoding and routing providers for your UI and real ETAs: the copilot/window/pricing endpoints are deliberately heuristic and demo-grade.
  • A member JWT for management calls; vehicle keys come from POST /fleet/vehicles.

Related: API reference — /fleet/* is in the OpenAPI spec; dashboard /fleet; IoT shares the device-key model; JWT auth.

On this page