A full-stack map game where players chase creatures along real road routes.
Route Catch Game combines interactive Leaflet gameplay with OSRM routing, Spring Boot APIs, and PostgreSQL persistence. Players start timed rounds, chase rarity-based creatures, follow animated road routes, and build persisted session history and leaderboard scores. Signed-in players can also keep user-specific stats and join a live presence room to see other online players on the map.
React 19 · Vite 8 · Leaflet · Java 21 · Spring Boot 4 ·
Spring Security · JWT · WebSocket/STOMP · PostgreSQL · Flyway ·
OSRM · Docker Compose
- Real-road creature chasing with OSRM nearest-road and route integration.
- Animated player movement, active chase state, cancellation, and route feedback.
- Common, rare, and legendary creatures with route-based difficulty.
- Timed rounds, score, XP, levels, catch effects, and round summaries.
- Backend-owned creature scoring and persisted game sessions and catches.
- Stats drawer with session history, catch history, and leaderboard.
- JWT authentication with protected current-user APIs.
- Authenticated game sessions linked to users for user-specific stats/history.
- WebSocket/STOMP multiplayer presence for signed-in room members.
- Automatic stale-session expiry and consistent JSON API errors.
- Reproducible PostgreSQL setup and local service scripts.
These screenshots are local demo captures of the current application.
For a concise interview walkthrough, use
docs/DEMO_SCRIPT.md. Capture guidance remains in
docs/screenshots/README.md.
flowchart LR
frontend["React + Leaflet Frontend"]
backend["Spring Boot Backend"]
osrm["OSRM Routing Engine"]
postgres[("PostgreSQL")]
flyway["Flyway Migrations"]
frontend -->|REST/JSON| backend
frontend -->|STOMP over WebSocket /ws| backend
backend -->|Route + nearest requests| osrm
backend -->|JPA transactions| postgres
flyway -->|Schema + seed data| postgres
- The frontend owns live map rendering, route animation, target spawning, catch detection, progression, and game presentation.
- Spring Boot owns routing adapters, JWT auth, backend session lifecycle, catalog-backed catch scoring, user-specific history/stats, leaderboard APIs, and in-memory multiplayer presence.
- OSRM provides nearest-road snapping and driving routes.
- PostgreSQL stores users, the creature catalog, game sessions, and caught-creature snapshots. Flyway creates and seeds the schema.
The browser never calls OSRM or PostgreSQL directly. Spring Boot provides the application boundary for auth, routing, validation, persistence, history, leaderboard operations, and multiplayer presence.
Authentication flow:
register/login -> JWT -> Authorization: Bearer token -> /api/auth/me
Authenticated session creation stores game_sessions.user_id and uses the
user's display name. Guest sessions remain supported with user_id = null.
Multiplayer presence flow:
React STOMP client -> /ws -> /app/rooms/{roomId}/presence
-> /topic/rooms/{roomId}/presence
Presence is in memory for local/demo use. It shows room members on the map but does not synchronize targets, catches, scoring, or routes.
Frontend
- React 19 and Vite 8
- Leaflet and React Leaflet
@stomp/stompjs- JavaScript, CSS, and ESLint
Backend
- Java 21
- Spring Boot 4
- Spring Web MVC, Validation, Data JPA, and Maven
- Spring Security, JWT, WebSocket/STOMP
- Flyway
Infrastructure
- PostgreSQL
- OSRM using the MLD algorithm
- Full-stack integration: coordinated React, Spring Boot, PostgreSQL, and OSRM workflows.
- Routing engine integration: nearest-road snapping, route geometry, distance, duration, and frontend animation.
- REST and realtime API design: layered controllers and services, DTO validation, stable response contracts, history queries, and STOMP presence messaging.
- Persistence and migrations: JPA transactions, relational game records, deterministic Flyway schema creation, and catalog seed data.
- Frontend state management: concurrent local gameplay, backend session synchronization, route request guards, and resilient non-blocking updates.
- Error handling: consistent API errors and graceful frontend fallback when routing, history, or backend synchronization is unavailable.
- Developer tooling: Docker Compose for PostgreSQL, service orchestration, diagnostics, tests, build checks, and focused project documentation.
- Bash and
curl - Java 21
- Node.js
20.19+or22.12+and npm - Docker with Docker Compose for the recommended PostgreSQL setup, or a local PostgreSQL installation
psqlfor manual database setup and inspection- A built OSRM server and prepared MLD dataset
The checked-in OSRM scripts currently use these machine-specific paths:
/home/halfdimension/Projects/practice/osrm-backend/build/osrm-routed
/home/halfdimension/Projects/osrm-data/northern-zone-latest.osrm
Update scripts/run-osrm.sh when OSRM or its dataset is located elsewhere.
The dataset prefix must have at least .ebg, .partition, and .cells
companion files.
Create the frontend environment file:
cp frontend/.env.example frontend/.envDefault value:
VITE_API_BASE_URL=http://localhost:8080The root .env.example contains the matching Docker Compose database defaults:
POSTGRES_DB=route_catch_game
POSTGRES_USER=route_catch_user
POSTGRES_PASSWORD=route_catch_passThe Compose file uses these values as defaults, so copying the root file is not
required. If you customize them through a root .env, update the backend
datasource settings to match.
The backend defaults are in
backend/route-catch-api/src/main/resources/application.properties:
spring.datasource.url=jdbc:postgresql://localhost:5432/route_catch_game
spring.datasource.username=route_catch_user
spring.datasource.password=route_catch_pass
osrm.base-url=http://localhost:5000This is the recommended setup for local development:
docker compose up -d postgresCheck container status and readiness:
docker compose ps
docker compose logs postgresThe route-catch-postgres container exposes PostgreSQL on
localhost:5432 and stores data in the named
route-catch-postgres-data volume.
Stop the container while preserving data:
docker compose downTo fully reset the local database:
docker compose down -v
docker compose up -d postgresdocker compose down -v permanently deletes the named database volume and all
local sessions and catches. Use it only when a clean database is intended.
As an alternative to Docker, create the local role and database once:
sudo -u postgres psqlCREATE USER route_catch_user WITH PASSWORD 'route_catch_pass';
CREATE DATABASE route_catch_game OWNER route_catch_user;
\qOn backend startup, Flyway applies:
V1__create_game_tables.sqlV2__seed_creature_catalog.sqlV3__add_player_name_to_game_sessions.sql
JPA uses ddl-auto=validate, so Flyway remains responsible for schema changes.
PostgreSQL must already be running, either through Docker Compose or a local installation. From the project root:
docker compose up -d postgres
./scripts/run-all.shThis starts:
- OSRM at
http://localhost:5000 - Spring Boot at
http://localhost:8080 - Vite at
http://localhost:5173
Open http://localhost:5173. Press Ctrl+C in the script terminal to stop the
managed OSRM and backend processes along with the frontend.
Frontend and backend are enough to test authentication and multiplayer presence. OSRM is required for route movement, nearest-road snapping, and target chasing.
Check prerequisites and live services with:
./scripts/check-system.shSeparate terminals are useful when inspecting logs.
Terminal 1:
./scripts/run-osrm.shTerminal 2:
./scripts/run-backend.shTerminal 3:
./scripts/run-frontend.shEquivalent direct commands:
cd backend/route-catch-api
./mvnw spring-boot:runcd frontend
npm install
npm run devBackend tests use H2 and do not require the local PostgreSQL instance:
cd backend/route-catch-api
./mvnw clean testFrontend verification:
cd frontend
npm run build
npm run lintShell script syntax:
bash -n scripts/run-all.sh
bash -n scripts/run-osrm.sh
bash -n scripts/run-backend.sh
bash -n scripts/run-frontend.sh
bash -n scripts/check-system.sh- Choose a round duration and start the game.
- Optionally register or sign in. Authenticated sessions are linked to the user; guests still play without an account.
- The frontend creates and starts a persisted backend session.
- Targets spawn, snap to nearby roads, and receive route-based difficulty.
- Click a target marker or Targets row to fetch a route and begin chasing.
- Catch creatures to receive immediate local score, XP, and visual feedback.
- The frontend submits each creature ID to the backend without blocking play.
- The backend validates catalog score, stores the catch, and updates the persisted session totals.
- End the round and open Stats to inspect My Stats, History, and Leaderboard data.
- Signed-in players can join a multiplayer room such as
delhiand see other online room members on the map.
frontend/
src/
api/ Spring Boot API clients
components/ Map, HUD, targets, feedback, Stats, history, leaderboard
config/ API, game, map, routing, and progression settings
data/ Frontend creature presentation and mock player profile
hooks/ Movement, spawning, sessions, catches, progression, presence
styles/ Global application styles
utils/ Rarity and browser sound helpers
backend/route-catch-api/
src/main/java/com/routecatch/api/
auth/ Registration, login, JWT, current user, security config
controller/ Health, route, and nearest endpoints
dto/ Shared routing and error DTOs
exception/ Global JSON error handling
game/ Catalog, sessions, catches, history, and leaderboard
multiplayer/ WebSocket/STOMP room presence
service/ OSRM routing integration
src/main/resources/db/migration/
docs/
scripts/
docker-compose.yml
- Backend cannot start: verify PostgreSQL is running and the configured database, user, and password exist.
- PostgreSQL container cannot start: inspect
docker compose logs postgresand check whether host port5432is already occupied. - Flyway reports schema permission errors: grant the application role
permission on the
publicschema. See Troubleshooting. - Routing returns
502: start OSRM and verify the configured dataset covers the coordinates being requested. - Frontend cannot reach the API or WebSocket: confirm
frontend/.envpoints tohttp://localhost:8080and restart Vite after changing it. - Browser shows method not allowed:
/api/routes,/api/nearest, and catch submission are POST endpoints, not browser-tab GET pages. - A port is busy: find and stop the process using ports
5000,8080,5173, or5432.
See docs/TROUBLESHOOTING.md for commands and detailed fixes.
- OSRM binary and dataset paths in
scripts/run-osrm.share local-machine dependent. - The frontend and runtime scripts are currently focused on local demos.
- No hosted deployment pipeline is configured.
- Live spawning, movement, and catch detection remain frontend-controlled.
- Multiplayer currently covers presence only; shared targets, catches, scoring, and route synchronization are future work.
- User profile editing and avatar storage
- Hosted frontend, backend, database, and routing deployment
- Richer creature catalog, abilities, and collection views
- Route challenges, objectives, and location-based events
- Player analytics, profile statistics, and deeper leaderboards
- Stronger server-authoritative gameplay validation


