// real-time transit tracking

locate-my-bus

Any GTFS-RT agency — live tracking + trip planning

Onboard any GTFS-compatible transit agency, and a C++ daemon fetches live vehicle positions every 15 seconds, stores them in PostgreSQL, and serves them to a React 18 + TypeScript single-page app. The map view talks to a provider-neutral MapAdapter (Azure Maps today — swap by writing one adapter), pinning a bus draws its trip polyline, ordered stop dots, and a walking path from you to the nearest stop. Pinned bus positions interpolate smoothly between 15-second polls. Includes a live agencies dashboard, a poll-monitor dashboard with feed analytics, and a multi-transfer trip planner.

locate-my-bus map screenshot

Agency onboarding

Provide a GTFS static zip URL and a GTFS-RT feed URL. The server downloads the zip, parses agency.txt and routes.txt, and inserts them into PostgreSQL in a single transaction.

C++ daemon

Reads all onboarded agencies from the DB every 15 seconds. Groups them by unique feed URL, downloads each distinct feed in parallel (bounded by CPU core count), then replaces live vehicle positions in PostgreSQL. Per-poll metrics are recorded for the monitoring dashboard.

PostgreSQL

Stores agencies, routes, shapes, trips, and live positions. ON DELETE CASCADE keeps everything consistent when an agency is removed.

Node.js / Express

Exposes GET /live/:agency_id/:route_id for live positions, GET /routes/:agency_id for route lists, GET /api/trip-plan/:agency_id for trip planning, and a CRUD API for agencies. Provider-agnostic geocoding and walking route endpoints normalize third-party API responses. Write operations require an x-access-key header.

Trip planner

Enter a destination by typing an address or dropping a pin. The server finds optimal transit routes (direct, 1-transfer, or 2-transfer) ranked by walking distance, transfers, and time. Each option shows a step-by-step timeline with departure, boarding, alighting, and arrival times. Walking paths and bus route shapes are drawn on the map. Live bus positions are tracked automatically. Respects GTFS calendar schedules (weekday/weekend/holiday) and tags routes without a live bus as “scheduled.”

React 18 SPA & MapAdapter

Vite-built, code-split per route. The map page talks exclusively to a provider-neutral MapAdapter — the Azure implementation owns the lazy SDK import, CSS, and [lng, lat] quirks. Swap providers (Mapbox, Leaflet, MapLibre…) by writing one new adapter file. Bus markers rotate to match GTFS head_bearing. Pinning a bus draws its trip polyline + ordered stop dots and fetches a walking path from your location to the nearest stop. The pinned bus interpolates between polls over 2 s instead of snapping. Map style, app theme, the running-vs-all routes filter, and the last-picked agency/route persist in localStorage.

Dashboards

/dash/agencies shows real per-agency route count, average latency, error rate, and a Live/Stale tag — all backed by /api/landing. /dash/monitor is fully wired to /api/dashboard/* with daemon uptime, a recent-exec sparkline, per-agency download-latency histograms, and slow-event detection. Both pages share a useAccessKey hook (sessionStorage-backed) and a local-draft Unlock prompt so the input doesn’t fire four authed fetches on every keystroke.

C++17 protobuf libcurl libpqxx PostgreSQL Node.js Express React 18 TypeScript Vite React Router Azure Maps SDK v3 Docker Dev Containers GitHub Actions

$ 01

git clone git@github.com:ranjitp16/locate-my-bus.git && cd locate-my-bus

$ 02

make get-protobuf-headers && make build

Or open in a Dev Container to skip local dependencies entirely.

$ 03

psql -U postgres -d locate_my_bus -f db/schema/init.sql

$ 04

npm run dev

Open http://localhost:3000 and use Manage Agencies to onboard a GTFS agency.

$ 05

make run

Daemon polls all onboarded agencies every 15 s and writes live positions to the DB.

$ 06

http://localhost:3000/view-map

Select an agency and route — buses appear within 15 seconds.