react interface to tracksolid to track drivers by dept
Find a file
David Kiania b0db22c669 feat(db): surface upstream trips enrichment columns in PostgREST RPCs
Adds migrations 006/007/008 that wrap tracksolid.v_trips_enriched
(introduced upstream in tracksolid_timescale_grafana_prod migration 09)
and DROP+CREATE the trips_for_day / trips_for_range RPCs to return the
new metadata columns: vehicle_plate, start_address, end_address,
driving_time_s, idle_time_s, fuel_consumed_l, and daily_seq.

Path/timestamps logic is unchanged — position_history is still scanned
to produce the per-vertex timestamps_rel that drive deck.gl TripsLayer
animation. route_geom can't replace this since it carries no per-vertex
time, but the GIST index on it is available for future area filters.

Day filter switches from start_time::date to v.trip_date_eat (the
Africa/Nairobi local date already computed by v_trips_enriched), which
fixes the latent bug where trips spanning midnight UTC could be
misbucketed.

Frontend Trip type still receives all original fields in compatible
positions; the new fields are additive and ignored by the existing
TripsLayer code.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 11:09:55 +03:00
compose Add deckgl trips visualization stack 2026-05-01 01:13:57 +03:00
db/migrations feat(db): surface upstream trips enrichment columns in PostgREST RPCs 2026-05-02 11:09:55 +03:00
web Add deckgl trips visualization stack 2026-05-01 01:13:57 +03:00
.gitignore Add deckgl trips visualization stack 2026-05-01 01:13:57 +03:00
README.md Add deckgl trips visualization stack 2026-05-01 01:13:57 +03:00
trips_deckgl_tracksolid.md Add deckgl trips visualization stack 2026-05-01 01:13:57 +03:00

deckgl_tracksolid

Public dashboard that animates a day's vehicle trips from tracksolid_db, colored and filtered by cost_centre. Stack: deck.gl TripsLayer over Mapbox GL, fed by PostgREST in front of TimescaleDB.

React + deck.gl SPA  →  PostgREST  →  tracksolid_db (Timescale)
   (web/)              (compose/)        public.trips_viz_v1
                                         public.trips_for_day(date, text[])
                                         public.trips_for_range(date, date, text[])
                                         public.list_cost_centres()

The full design lives in trips_deckgl_tracksolid.md — read that first.

Layout

Path Purpose
db/migrations/ Five SQL files. Idempotent. Apply in order. Add only public.* objects.
compose/ docker-compose.yaml for the PostgREST API + the built web container.
web/ Vite + React + TS SPA. Renders TripsLayer + PathLayer over Mapbox.
trips_deckgl_tracksolid.md Design doc / plan.

First-time setup

  1. Apply migrations to tracksolid_db:
    psql "$ADMIN_DSN" \
      -f db/migrations/001_viz_anon_role.sql \
      -f db/migrations/002_trips_viz_view.sql \
      -f db/migrations/003_trips_for_day_rpc.sql \
      -f db/migrations/004_trips_for_range_rpc.sql \
      -f db/migrations/005_list_cost_centres_rpc.sql
    
  2. Set the viz_anon login password out of band (do not commit):
    ALTER ROLE viz_anon LOGIN PASSWORD '<generate one>';
    
  3. Configure env:
    cp compose/.env.example compose/.env
    # fill in VIZ_DATA_PASSWORD, VITE_MAPBOX_TOKEN, …
    cp web/.env.example web/.env.local
    # fill in VITE_API_URL (e.g. http://localhost:3000) and VITE_MAPBOX_TOKEN
    

Local development

# 1. Start PostgREST against the staging DB
cd compose && docker compose up postgrest

# 2. Run the web app against it
cd web && pnpm install && pnpm dev
# → http://localhost:5173

The web app reads VITE_API_URL (default http://localhost:3000) and VITE_MAPBOX_TOKEN. Without a Mapbox token the deck.gl layers still render on a black background — fine for testing data, ugly for demos.

Production deployment (Coolify)

Two services live alongside the existing Dekart stack:

  • postgrest — read-only API at api.trips.rahamafresh.com. CORS allow-listed to the web FQDN.
  • trips_web — Caddy serving the built SPA at trips.rahamafresh.com.

Both inherit env vars from the Coolify resource panel — see compose/.env.example for the canonical list.

Security boundary

The viz_anon role has no grants on tracksolid.* — verified in setup. It can only call the four RPCs in public, which run SECURITY DEFINER and only expose the columns listed in trips_viz_v1. Direct queries against any tracksolid table return permission denied for schema tracksolid.

If the public dashboard ever needs to be locked down, add Traefik basic-auth in Coolify (same pattern Dekart uses) — no app-level changes needed.