Real-time disaster navigation app. Users and emergency services report hazards (floods, blocked roads). Reports are buffered into avoidance polygons and fed into a routing engine that calculates the quickest safe evacuation route. Emergency services can declare high-risk zones and place shelters on the map.
You need two API keys. Both are free tier.
| Service | Where to get it | Limit |
|---|---|---|
| Mapbox | mapbox.com → Account → Tokens | 50k map loads/month |
| OpenRouteService | openrouteservice.org → Dashboard | 2000 directions req/day |
Flood data is pulled from the UK Environment Agency Real-Time Flood Monitoring API — no key required.
Copy .env.example and fill in your keys:
cp .env.example .env.env:
VITE_MAPBOX_TOKEN=pk.eyJ1... # your Mapbox public token
VITE_ORS_API_KEY=5b3ce3597... # your OpenRouteService key
water-watch/
├── index.html # HTML entry point
├── main.py # FastAPI backend (run from root)
├── reports.db # SQLite database (auto-created)
├── .env.example # Token template — copy to .env
├── src/ # React + Vite + TypeScript frontend
│ ├── App.tsx
│ ├── api/ # Axios API clients (reports, flood, dev)
│ ├── components/ # UI components (Map, Header, Panels, Toolbars)
│ ├── data/ # Static shelter data
│ ├── map/ # Mapbox GL JS map manager
│ ├── services/ # Pollers (flood + reports)
│ └── utils/ # Haversine, severity colours, popup renderer
└── vite.config.ts
| Layer | Choice |
|---|---|
| Map Rendering | Mapbox GL JS v3 |
| Routing Engine | OpenRouteService API v2 (avoid_polygons) |
| Polygon Buffering | Turf.js (@turf/buffer, @turf/union) — client-side |
| Spatial Utils | @turf/boolean-point-in-polygon, @turf/helpers |
| Frontend | React 18 + Vite + TypeScript |
| HTTP Client | Axios |
| Backend | FastAPI (Python) — auto-docs at /docs |
| Database | SQLite — zero config, file reports.db |
| Flood Data | UK Environment Agency API — no key needed |
| Testing | Vitest + fast-check (property-based testing) |
npm install
npm run devRuntime:
mapbox-gl— map rendering@turf/buffer— buffer hazard points into avoidance polygons@turf/union— merge overlapping polygons@turf/boolean-point-in-polygon— check if shelters are inside hazard zones@turf/helpers— GeoJSON helpersaxios— HTTP requests to backendreact,react-dom— UI framework
Dev:
vite,@vitejs/plugin-react— build toolingtypescript— type safetyvitest— test runnerfast-check— property-based testing@types/mapbox-gl,@types/react,@types/react-dom— type definitions
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install fastapi uvicorn pydanticRun the server from the project root:
uvicorn main:app --reload --port 8000API docs available at http://localhost:8000/docs.
| Method | Endpoint | Description |
|---|---|---|
GET |
/reports |
List all hazard reports |
POST |
/reports |
Submit a new hazard report |
GET |
/dev/hazards |
List dev-placed hazard points |
POST |
/dev/hazards |
Add a dev hazard point |
DELETE |
/dev/hazards |
Clear all dev hazards |
GET |
/dev/shelters |
List dev-placed shelters |
POST |
/dev/shelters |
Add a dev shelter |
DELETE |
/dev/shelters |
Clear all dev shelters |
Report (user submitted):
id: uuid
hazardType: str # flood | blocked_road | fire | structural
coordinates: [lng, lat]
description: str (optional)
createdAt: datetime
DevHazard (dev/demo tool):
id: uuid
coordinates: [lng, lat]
createdAt: datetime
DevShelter (dev/demo tool):
id: str
name: str
coordinates: [lng, lat]
type: str # shelter | medical
createdAt: datetime
- User taps "Get me out" → browser geolocation gives current lat/lng
- Fetch active reports:
GET /reports - Buffer each report point into an avoidance polygon:
turf.buffer(point, radius) - Merge overlapping polygons with
turf.union - Also include high-risk zones and dev hazards as avoidance areas
- Call ORS Directions with
avoid_polygons(GeoJSON MultiPolygon) - Render returned GeoJSON LineString as a Mapbox GL JS layer
You may have to refresh the page in order for the data to load.
- Mishanil Kazreen (@mishanilkazreen)
- Josh Fox (@Phoenix-Gamer871)
- Hiwa Rasul (@hiwarasul389-alt)
- Fahmi Ahmed (@sfa39)