feat: add GPS trip detection, history panel, and playback (#23)

Auto-detect trips from GPS data (5-min idle threshold), pre-compute
OSRM routes on trip completion, add trip history side panel with
toggleable trips, and animated trip playback with speed controls.

- Add GpsTrip model with TripStatus enum and migration
- Trip detection in syncPositions cron (start on movement, end on idle)
- Trip finalization with OSRM route matching and stats computation
- API endpoints: list/detail/active/merge/backfill trips
- Stats tab overhaul: trip list panel + map with colored polylines
- Trip playback: animated marker, progressive trail, 1x-16x speed
- Live map shows active trip trail instead of full day history
- Historical backfill from existing GPS location data

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-08 18:08:48 +01:00
parent cb4a070ad9
commit cc3375ef85
7 changed files with 1746 additions and 93 deletions

View File

@@ -0,0 +1,34 @@
-- CreateEnum
CREATE TYPE "TripStatus" AS ENUM ('ACTIVE', 'COMPLETED', 'PROCESSING', 'FAILED');
-- CreateTable
CREATE TABLE "gps_trips" (
"id" TEXT NOT NULL,
"deviceId" TEXT NOT NULL,
"status" "TripStatus" NOT NULL DEFAULT 'ACTIVE',
"startTime" TIMESTAMP(3) NOT NULL,
"endTime" TIMESTAMP(3),
"startLatitude" DOUBLE PRECISION NOT NULL,
"startLongitude" DOUBLE PRECISION NOT NULL,
"endLatitude" DOUBLE PRECISION,
"endLongitude" DOUBLE PRECISION,
"distanceMiles" DOUBLE PRECISION,
"durationSeconds" INTEGER,
"topSpeedMph" DOUBLE PRECISION,
"averageSpeedMph" DOUBLE PRECISION,
"pointCount" INTEGER NOT NULL DEFAULT 0,
"matchedRoute" JSONB,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "gps_trips_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "gps_trips_deviceId_startTime_idx" ON "gps_trips"("deviceId", "startTime");
-- CreateIndex
CREATE INDEX "gps_trips_status_idx" ON "gps_trips"("status");
-- AddForeignKey
ALTER TABLE "gps_trips" ADD CONSTRAINT "gps_trips_deviceId_fkey" FOREIGN KEY ("deviceId") REFERENCES "gps_devices"("id") ON DELETE CASCADE ON UPDATE CASCADE;