deckgl_tracksolid/db/migrations/002_trips_viz_view.sql
David Kiania 47c86c9d7a Add deckgl trips visualization stack
Initial implementation of the public trips dashboard:

- db/migrations/001..005: read-only viz_anon role + thin trips_viz_v1
  view + three SECURITY DEFINER RPCs (trips_for_day, trips_for_range,
  list_cost_centres). Builds path on demand from position_history;
  coalesces missing cost_centre to 'Unassigned'. Smoke-tested against
  staging: 982 trips / 13 cost centres for 2026-04-29.

- compose/: PostgREST v12 service + trips_web Caddy service. CORS
  allow-listed to the web FQDN; viz_anon role is the only authorization.

- web/: Vite + React + TS SPA. deck.gl TripsLayer animated over
  PathLayer (whole route in low opacity), Mapbox GL dark base map,
  Zustand store, TanStack Query for fetching. Sidebar = date controls
  + cost-centre multi-select + vehicle drilldown. Timebar = scrubber
  with 1x/10x/60x/600x speeds. tsc + vite build clean.

- README + design doc updated to match the verified schema (path lives
  in tracksolid.position_history, vehicle key is imei, no down-sampling
  needed at observed volume).
2026-05-01 01:13:57 +03:00

25 lines
853 B
SQL

-- 002_trips_viz_view.sql
-- Thin metadata view: one row per trip, joined to its device's cost_centre.
-- No path here — path is built per-trip inside the RPCs (003/004) so a
-- naive SELECT * never triggers an ST_MakeLine across the whole hypertable.
--
-- 'Unassigned' bucket: NULL or whitespace-only cost_centre is coalesced.
CREATE OR REPLACE VIEW public.trips_viz_v1 AS
SELECT
t.id AS trip_id,
t.imei,
d.vehicle_name,
d.vehicle_number,
COALESCE(NULLIF(TRIM(d.cost_centre), ''), 'Unassigned') AS cost_centre,
t.start_time,
t.end_time,
t.distance_km,
t.avg_speed_kmh,
t.max_speed_kmh
FROM tracksolid.trips t
JOIN tracksolid.devices d ON d.imei = t.imei
WHERE t.start_time IS NOT NULL
AND t.end_time IS NOT NULL;
GRANT SELECT ON public.trips_viz_v1 TO viz_anon;