A full-stack web app that finds optimal bus routes between any two zip codes in Maastricht, with real-time directions and an interactive map.
Backend (Java / Spring Boot)
- Implemented A* pathfinding over a live transit graph built from GTFS data (bus stops, trips, shapes, timetables)
- Graph nodes are bus stops loaded from a MySQL database; edges represent bus trips (with scheduled departure/arrival times) and walking segments
- Walking distances are fetched from the Google Maps Distance Matrix API for accuracy
- Route response includes an ordered list of lat/lng coordinates (for map rendering) and human-readable turn-by-turn directions
Frontend (React + Vite)
- Split-panel UI: search form with zip code autocomplete on the left, Google Maps polyline route on the right
- Markers distinguish the origin (green) and destination (amber) stops
- Directions panel shows timestamped stops, transfers, and walking segments
| Layer | Stack |
|---|---|
| Backend | Java 21, Spring Boot, MySQL |
| Algorithm | A* search (custom implementation) |
| External APIs | Google Maps Distance Matrix, Google Maps JS API |
| Frontend | React 18, Vite, @react-google-maps/api |
| Infrastructure | Docker Compose, Nginx reverse proxy |
- User enters origin/destination zip codes and departure time
- Backend resolves zip codes to lat/lng coordinates from the database
- A* runs over the transit graph, respecting bus timetables — it only boards a trip if the bus hasn't left yet
- The algorithm chooses the path that minimises total travel time (waiting + riding + walking)
- Route shapes are retrieved from the database and returned as a polyline to the frontend
Requires Docker and a Google Maps API key.
# 1. Create a .env file in the project root
cat > .env <<EOF
DB_PASSWORD=yourpassword
GOOGLE_MAPS_API_KEY=your_key_here
EOF
# 2. Add your Google Maps key to the frontend env
echo "VITE_GOOGLE_MAPS_API_KEY=your_key_here" > frontend/.env
# 3. Build the frontend and start all services
cd frontend && npm install && npm run build && cd ..
docker compose up --buildOpen http://localhost and search between any two Maastricht zip codes (e.g. 6211SM → 6229EG).