A web application visualizing Zurich's public transport network with approximated vehicle positions, interactive mapping, and route planning.
Features: Interactive transit line visualization | Nearby departures | Approximated vehicle positions | Connection planning
Tech: Next.js 16 · React 19 · FastAPI · PostgreSQL · MapLibre GL · GTFS · Docker · Kubernetes
- Prereqs: Docker + Docker Compose.
- Data: place GTFS static files under
backend/staticData/gtfs_fp2025_20251203(directory withstops.txt,trips.txt,stop_times.txt,routes.txt,agency.txt,shapes.txt, plusstops_zurich.txtfor filtering androutes_zurich.txtfor colors, these two files should be in /staticData). - Build backend image (installs DB deps):
docker compose build backend - Start PostgreSQL:
docker compose up -d postgres - Reset schema (optional, wipes data):
docker compose exec -T postgres psql -U postgres -d postgres -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" - Apply schema:
docker compose exec -T postgres psql -U postgres -d postgres < backend/db/gtfs_postgres.sql - Load GTFS into PostgreSQL (uses Zurich color mapping, falls back to red/black when missing):
- Directory input:
docker compose run --rm backend python load_gtfs.py --gtfs-path staticData/gtfs_fp2025_20251203 - Zip input:
docker compose run --rm -v "$PWD/path/to/gtfs.zip:/data/gtfs.zip" backend python load_gtfs.py --gtfs-path /data/gtfs.zip
- Directory input:
- Run services:
docker compose up(backend onhttp://localhost:8080, database can be accessed athttp://localhost:8081) - Sample endpoints:
GET /gtfs/routesGET /gtfs/stops(optionalq,limit,offset)GET /gtfs/stops/{stop_id}GET /gtfs/trip/{trip_id}/stops
- Prereqs: Docker + Docker Compose.
- Clone repo and ensure GTFS static files are present at
backend/staticData/gtfs_fp2025_20251203(directory withstops.txt,trips.txt,stop_times.txt,routes.txt,agency.txt,shapes.txt, andstops_zurich.txt), unzipped. - Build backend (installs DB deps and copies code):
docker compose build backend - Start PostgreSQL:
docker compose up -d postgres - (Optional) Reset + apply schema:
docker compose exec -T postgres psql -U postgres -d postgres -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" docker compose exec -T postgres psql -U postgres -d postgres < backend/db/gtfs_postgres.sql
- Load GTFS into PostgreSQL (directory input): this can take quite some time (took ~10 minutes on an M1 Pro)
docker compose run --rm backend python load_gtfs.py --gtfs-path staticData/gtfs_fp2025_20251203
- Bring up backend/frontend:
docker compose up(backend athttp://localhost:8080, frontend athttp://localhost:3000) - Smoke test:
curl http://localhost:8080/gtfs/routesorcurl http://localhost:8080/gtfs/stops/<stop_id>
- Apply schema (one-time or after reset):
docker compose exec -T postgres psql -U postgres -d postgres < backend/db/gtfs_postgres.sql - Run weekly GTFS fetch + load (downloads feed, processes, loads DB):
docker compose run --rm backend python weekly_run.py - If you only need static GTFS loaded from existing files:
docker compose run --rm backend python load_gtfs_to_db.py --gtfs-path staticData/GTFS
GET /gtfs/routes- All transit routes with colorsGET /gtfs/stops?q=<query>- Search stations (autocomplete)GET /gtfs/stops/{stop_id}- Single station detailsGET /gtfs/realtime/positions- Cached vehicle positionsGET /gtfs/realtime/positions/stream- SSE stream of live positionsGET /gtfs/realtime/vehicles- Vehicle summaries with delaysPOST /gtfs/user-location- Nearby departures by geolocationGET /connections?from=X&to=Y- Route planning (proxies Swiss Transport API)
Frontend: Next.js app with MapLibre GL for interactive maps, React Context for state management
Backend: FastAPI approximating vehicle positions based on schedules, real-time delay data, and route geometries. Route geometries are served from a static WGS84 GeoJSON file for frontend rendering.
Database: PostgreSQL storing GTFS data (filtered Zurich stops, routes, trips, stop_times, shapes)
Deployment: Docker containers orchestrated by Kubernetes with Helm charts, automated CI/CD via GitLab
The technical report is available in report/.
Compile:
cd report/
pdflatex report.tex
bibtex report
pdflatex report.tex
pdflatex report.tex- Basil Feitknecht (bfeitknecht@ethz.ch)
- Benjamin Birtha (bbirtha@ethz.ch)
- Noah Mäschli (nmaeschli@ethz.ch)
- Yaroslav Plyusnin (yplyusnin@ethz.ch)
ETH Zürich – Fundamentals of Web Engineering, 2025