GbgGridlock is a real-time analytics dashboard for visualizing transit pain points in Gothenburg's Västtrafik network.
backend/– FastAPI aggregation API with integrated polling worker for dashboard consumptionfrontend/– React dashboard UI (wall of shame, route deep dive, health indicator)backend/alembic/– Alembic migrations for TimescaleDB schema lifecycle
# Preferred on normal hosts
docker compose up -d db
# If running inside a nested container where compose fails on timescaledb-tune,
# use this instead:
docker run -d --name gbggridlock-db \
-e POSTGRES_USER=gbg -e POSTGRES_PASSWORD=gbg -e POSTGRES_DB=gbggridlock \
-e NO_TS_TUNE=true \
-p 5432:5432 \
timescale/timescaledb:latest-pg16
cd backend && uv run alembic upgrade headIf Docker itself fails with unshare: operation not permitted, the host/container runtime is blocking required kernel features. In that case, run the DB step on a machine/runner with privileged Docker support.
cd backend
cp .env.example .env
# Edit .env to set VT_CLIENT_ID, VT_CLIENT_SECRET, VT_AUTH_KEY
# Set ENABLE_WORKER=true to enable polling
pip install -e .
uvicorn gbg_gridlock_api.main:app --reload --port 8000cd frontend
npm install
npm run devOpen http://localhost:5173.
For production deployment to Railway with automatic migrations and integrated worker:
- See detailed instructions in
RAILWAY_DEPLOYMENT.md - The backend now includes the integrated polling worker (controlled by
ENABLE_WORKERenv var) - Migrations run automatically before service startup via
railway.toml - TimescaleDB is provided natively by Railway
Quick Railway setup:
- Connect your repo to Railway
- Add TimescaleDB service
- Set
VT_CLIENT_IDandVT_CLIENT_SECRET(ENABLE_WORKERdefaults totrue) - Deploy automatically runs migrations and starts the API
The frontend is intentionally hardcoded so it can be shipped as static assets on GitHub Pages (GitHub's CDN-backed hosting). The included workflow .github/workflows/frontend-pages.yml builds frontend/ and deploys frontend/dist on pushes to main.
Add these GitHub repository secrets before enabling deployment:
VITE_POSTHOG_KEY– your PostHog project key.VITE_POSTHOG_HOST– optional PostHog host (defaults tohttps://eu.i.posthog.com).
After the workflow runs, your dashboard is served from:
https://<org-or-user>.github.io/<repo>/
For local frontend development without analytics, no secrets are required.
When you change code in a component, run that component's checks before opening a PR:
- Backend changes:
cd backend && python3 -m pytest tests/ -v - Frontend changes (required):
cd frontend && npm run buildcd frontend && npx playwright install chromium(first run only)cd frontend && npx playwright install-deps chromium(CI/container environments)cd frontend && npm run test:e2e
The frontend smoke test runs against the built preview app, so running only npm run build is not sufficient when UI code changes.
- The backend includes an integrated polling worker that uses OAuth2 client credentials and caches tokens until near expiry.
- Polling is every 5 minutes (300 seconds) with an
asyncio.Semaphore(5)concurrency guard. - Stop-area polling targets are maintained in
backend/src/gbg_gridlock_api/monitored_stops.py.