| title | TerraWatch |
|---|---|
| emoji | 🌍 |
| colorFrom | green |
| colorTo | blue |
| sdk | docker |
| app_port | 7860 |
| pinned | false |
| license | mit |
| short_description | Soil health monitoring & disaster risk assessment tool |
Global Real-Time Soil Health Monitoring & Natural Disaster Risk Analysis Platform
TerraWatch is a full-stack geospatial platform that combines soil health analysis with multi-hazard disaster risk assessment. Click any point on the globe to get soil quality scores, erosion estimates, landslide/flood/wildfire/liquefaction risk levels, crop recommendations, and emergency preparedness plans — all computed from live data pulled from USGS, Open-Meteo, and ISRIC SoilGrids. No API keys needed.
Live Demo: huggingface.co/spaces/teaphile/terrawatch
Verified status: 162 backend tests pass,
ruff check backend/app/is clean, and the frontend passesnpm run lint,npm run typecheckandnpm run build. The API and the bundled production build are exercised together: the FastAPI app servesfrontend/distwhen it exists, so a single container is enough.
- Features
- Architecture
- Tech Stack
- Getting Started
- Docker Deployment
- API Reference
- Frontend Components
- Analytical Models
- Data Sources
- Environment Variables
- Project Structure
- Testing
- License
- Soil property prediction — pH, organic carbon (g/kg), nitrogen (mg/kg), texture class (USDA textural triangle), cation exchange capacity (CEC), bulk density (g/cm³), and volumetric moisture content at multiple depths.
- Health index scoring — Composite score from 0 to 100 derived from weighted soil parameters. Grades: A (80–100), B+ (65–79), B (50–64), C (35–49), D (< 35). Each parameter (pH, organic carbon, nitrogen, moisture, CEC, bulk density) is normalized on optimal agronomic ranges before aggregation.
- RUSLE erosion modeling — Full implementation of the Revised Universal Soil Loss Equation:
A = R × K × LS × C × P. Computes rainfall erosivity (R), soil erodibility (K, based on texture/organic content), slope length-steepness (LS), cover management (C, derived from NDVI/land cover), and support practice (P). Outputs annual soil loss in tons/ha/yr with five risk tiers (Very Low through Very High). - Carbon sequestration estimates — Current organic carbon stock (tons/ha), maximum sequestration potential based on soil type/climate zone, and estimated improvement rate (tons/ha/yr) under recommended management practices.
- Multi-depth soil moisture — Volumetric water content at 0–1 cm, 1–3 cm, 3–9 cm, 9–27 cm, and 27–81 cm depths from Open-Meteo's soil moisture model.
- Landslide susceptibility — 10-factor weighted model incorporating slope angle, soil saturation, clay content, seismic activity, rainfall intensity, land cover, drainage density, soil depth, previous event history, and proximity to fault lines. Regional adjustments applied for known geological zones. Output: susceptibility class (Low/Moderate/High/Very High/Critical) with a 0–1 probability score.
- Flood risk — Analyzes terrain elevation relative to nearest water body, slope gradient, soil infiltration capacity (based on texture), cumulative rainfall in last 24/48/72 hours, upstream drainage area, and land cover imperviousness. Provides return period estimate, expected inundation depth (meters), and risk level.
- Wildfire risk — Fuel moisture deficit from temperature, humidity and wind speed. Factors in vegetation dryness index (NDVI-derived), drought conditions, historical fire frequency, and Fosberg Fire Weather Index. Outputs risk level with estimated spread potential (low/moderate/rapid/extreme).
- Liquefaction potential — Evaluates susceptibility based on soil grain size distribution, groundwater depth, sand/silt layer presence, and seismic demand (PGA from recent earthquakes). Includes probability of occurrence given a M7.0 event at various distances.
- Composite risk score — Combined multi-hazard score computed as
0.6 × max(individual_risks) + 0.4 × mean(individual_risks). Prevents masking of a single extreme hazard while still reflecting overall exposure. Mapped to five levels: Low, Moderate, High, Very High, Critical.
- Dark/light basemaps — CARTO Dark Matter (default) and CARTO Voyager (light) tile layers, plus terrain overlay toggle.
- Real-time earthquake markers — Circle markers with radius proportional to magnitude and color coded by significance (green → yellow → orange → red → darkred). Pulse-glow animation on new events.
- Click-to-analyze — Click any point on the map to kick off soil analysis + risk assessment for those coordinates. Results stream into the sidebar panels.
- Animated fly-to — When coordinates are entered via the header search bar, the map smoothly pans and zooms to the location.
- Layer controls — Toggle visibility for earthquakes, soil health overlay, risk zones, and terrain. Each layer has a legend color chip.
- Dynamic legend — Shows earthquake magnitude scale, risk level colors, and soil health grading scale. Includes a soil health section (Good 70+ / Fair 50–70 / Poor < 50).
- Responsive controls — Map controls reposition for mobile (zoom bottom-left, layers top-right). Coordinate chip shown on mobile at bottom center.
- USGS earthquake feed — Background task fetches M2.5+ events from the USGS FDSN API every
EARTHQUAKE_FETCH_INTERVALseconds (default 300, configurable). Events displayed as soon as they arrive. - WebSocket alert stream — Backend monitors incoming earthquake data and pushes alerts for M4.0+ events over a WebSocket connection at
/ws/alerts. Frontend receives them instantly and appends to the alert feed. - Open-Meteo integration — Current weather conditions (temperature, humidity, precipitation, wind), archive-based climate normals, recent rainfall totals, and soil-moisture profiles. Each dataset has its own cache TTL, and every fallback is labelled with its
source. - ISRIC SoilGrids — Soil property data (pH, organic carbon, CEC, texture fractions, bulk density, nitrogen) at queried coordinates, combined into a 0–30 cm thickness-weighted mean.
- Full weather panel showing current conditions with WMO weather code icons, six primary metrics (temperature, humidity, precipitation, rain, wind speed, wind direction), climate averages for the current month, and charts for weather conditions + environmental radar.
- Crop suitability — 12-crop database (wheat, rice, maize, soybean, cotton, potato, tomato, sugarcane, coffee, tea, barley, millet) each scored against soil pH range, organic carbon, nitrogen, moisture, and texture suitability. Outputs a 0–100 suitability score per crop.
- Fertilizer guidance — Nutrient status assessment (nitrogen, phosphorus, potassium) classified as deficient/adequate/high, with specific application rates (kg/ha) for conventional fertilizers and organic alternatives (compost, manure, bone meal, etc.).
- Irrigation scheduling — Computes available water holding capacity from soil texture and organic content. Recommends irrigation method (drip, sprinkler, furrow, flood), frequency (days), depth per application (mm), and urgency level.
- Disaster preparedness — Location-specific emergency plans based on active risk levels. Includes evacuation zone recommendations, structural reinforcement priorities, early warning system suggestions, and emergency supply checklists.
- Environmental restoration — Suggests native plant species for erosion control based on climate zone, carbon improvement strategies (cover cropping, no-till, biochar application), and wetland/riparian buffer recommendations.
- CSV — Soil analysis results in spreadsheet-compatible format with all properties, scores, and metadata.
- GeoJSON — Soil and risk data formatted for direct import into QGIS, ArcGIS, or any GIS platform. Includes point geometry with properties.
- Full JSON Report — Comprehensive export with soil analysis, risk assessment, weather data, recommendations, and metadata in a single structured document.
- Mobile — Bottom navigation bar with slide-up drawer for sidebar content. Touch-friendly tap targets (min 44px). Map controls repositioned. Search overlay.
- Tablet — Side panel with adaptive width. Scrollable content areas.
- Desktop — Full sidebar, overlay panels, and keyboard shortcuts. Focus-visible rings on all interactive elements.
- Print styles — Clean output with hidden navigation elements.
graph TB
subgraph Client["Browser"]
UI["React 18 SPA<br/>(TypeScript + Vite)"]
Map["Leaflet Map"]
Charts["Recharts<br/>17 chart components"]
WS_Client["WebSocket Client"]
end
subgraph Server["FastAPI Backend"]
API["REST API<br/>/api/v1/*"]
WS_Server["WebSocket<br/>/ws/alerts"]
MW["Middleware<br/>CORS · Rate Limit · Auth"]
Services["Service Layer<br/>soil · disaster · weather<br/>recommendation · alert · cache<br/>gis · satellite"]
Models["Analytical Models<br/>erosion · landslide · flood<br/>fire · liquefaction · soil"]
BG["Background Tasks<br/>earthquake fetch · alert generation"]
end
subgraph Data["Data Layer"]
Cache["In-Memory TTL Cache<br/>(cachetools)"]
DB[(SQLite<br/>aiosqlite)]
end
subgraph External["External APIs (no auth)"]
USGS["USGS Earthquake<br/>earthquake.usgs.gov"]
OM["Open-Meteo<br/>api.open-meteo.com"]
ISRIC["ISRIC SoilGrids<br/>rest.isric.org"]
end
UI -->|HTTP| API
WS_Client -->|WebSocket| WS_Server
API --> MW --> Services
Services --> Models
Services --> Cache
Services --> DB
BG --> Services
Services -->|httpx async| USGS
Services -->|httpx async| OM
Services -->|httpx async| ISRIC
WS_Server --> Services
style Client fill:#1a1a2e,stroke:#30363d,color:#e6edf3
style Server fill:#161b22,stroke:#30363d,color:#e6edf3
style Data fill:#21262d,stroke:#30363d,color:#e6edf3
style External fill:#161b22,stroke:#30363d,color:#e6edf3
Request flow for a map click:
- User clicks a location on the Leaflet map → browser sends
GET /api/v1/soil/analyze?lat=28.6&lon=77.2andGET /api/v1/risk/all?lat=28.6&lon=77.2in parallel. - Soil service checks TTL cache → on miss, fetches soil properties from ISRIC SoilGrids and weather/moisture from Open-Meteo concurrently via
httpx.AsyncClient. - Raw data is processed through analytical models (erosion, health index, carbon sequestration).
- Risk service queries recent seismic events (USGS), current weather (Open-Meteo), and soil conditions to compute landslide, flood, wildfire, and liquefaction probabilities.
- Both responses are returned as JSON → React renders soil panel, risk summary, charts, and map overlays.
| Component | Package | Version |
|---|---|---|
| Web framework | FastAPI | >= 0.110.0 |
| ASGI server | uvicorn | >= 0.27.0 |
| Validation | pydantic v2, pydantic-settings | >= 2.6.0, >= 2.1.0 |
| ORM | SQLAlchemy 2.0 (async) | >= 2.0.25 |
| Database driver | aiosqlite | >= 0.19.0 |
| HTTP client | httpx (async) | >= 0.26.0 |
| WebSocket | websockets | >= 12.0 |
| ML / Numerics | numpy, scikit-learn, joblib | >= 1.26, >= 1.4, >= 1.3 |
| Cache / numerics | cachetools, numpy | >= 5.3, >= 1.26 |
| Testing | pytest, pytest-asyncio, anyio | >= 8.0, >= 0.23, >= 4.0 |
| Linting | ruff | >= 0.6 |
| Runtime | Python 3.11+ (Docker: python:3.11-slim) |
| Component | Package | Version |
|---|---|---|
| UI library | React | ^18.3 |
| Language | TypeScript | ^5.9 |
| Build tool | Vite | ^7.3 |
| Styling | Tailwind CSS | ^3.4 |
| Maps | leaflet + react-leaflet | ^1.9.4 / ^4.2.1 |
| Charts | Recharts | ^2.15 |
| Icons | lucide-react | ^0.344+ |
| Linting | ESLint 10 + typescript-eslint | ^10 / ^8 |
| Runtime | Node.js 20+ (Docker: node:20-alpine) |
- Python 3.11 or newer
- Node.js 18+ and npm
- Git
git clone https://github.com/teaphile/TerraWatch.git
cd TerraWatchcd backend
# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate # Linux / macOS
# venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
# Start the server (with hot reload for development)
uvicorn app.main:app --reload --port 8000The API is now running at http://localhost:8000. Interactive docs are at:
- Swagger UI:
http://localhost:8000/docs - ReDoc:
http://localhost:8000/redoc
No .env file or API keys are required — the app works out of the box with free, keyless public APIs.
cd frontend
# Install dependencies (lockfile is committed)
npm ci
# Start the Vite dev server
npm run devThe frontend runs at http://localhost:5173. Vite proxies /api and /ws to http://localhost:8000 (override with VITE_API_TARGET), so both servers work together seamlessly.
Navigate to http://localhost:5173. Click anywhere on the map to analyze soil and disaster risk at that location.
cd terrawatch
docker compose up --buildThis starts two containers on your local machine:
| Service | Port | Description |
|---|---|---|
backend |
8000 | FastAPI API server with health checks |
frontend |
80 | nginx serving the built React SPA |
The backend uses a named Docker volume (backend-data) to persist the SQLite database across container restarts.
The root Dockerfile creates a unified container that builds the React frontend, bundles it with the backend, and serves everything on a single port:
docker build -t terrawatch .
docker run -p 7860:7860 terrawatchThis is the configuration used for the live demo. The container runs as a non-root user for security.
All endpoints are prefixed with /api/v1. Query parameters lat (latitude, -90 to 90) and lon (longitude, -180 to 180) are required for location-based endpoints.
| Method | Endpoint | Parameters | Description |
|---|---|---|---|
| GET | /api/v1/soil/analyze |
lat, lon |
Full soil analysis — properties, health index, erosion risk, carbon sequestration, moisture profile |
| GET | /api/v1/soil/moisture |
lat, lon |
Soil moisture data at multiple depths |
| Method | Endpoint | Parameters | Description |
|---|---|---|---|
| GET | /api/v1/risk/all |
lat, lon |
Complete multi-hazard risk assessment (landslide, flood, wildfire, liquefaction, composite) |
| GET | /api/v1/risk/landslide |
lat, lon |
Landslide susceptibility only |
| GET | /api/v1/risk/flood |
lat, lon |
Flood risk only |
| GET | /api/v1/risk/earthquake/recent |
days (default 7) |
Recent earthquake events from USGS |
| Method | Endpoint | Parameters | Description |
|---|---|---|---|
| GET | /api/v1/recommendations/agriculture |
lat, lon |
Crop suitability, fertilizer, irrigation scheduling, soil amendments |
| GET | /api/v1/recommendations/disaster |
lat, lon |
Location-specific disaster preparedness plans |
| GET | /api/v1/recommendations/environmental |
lat, lon |
Restoration strategies, native species, carbon improvement |
| Method | Endpoint | Parameters | Description |
|---|---|---|---|
| GET | /api/v1/alerts/active |
— | All currently active alerts |
| GET | /api/v1/alerts/history |
— | Historical alert log |
| DELETE | /api/v1/alerts/{alert_id} |
alert_id (path) |
Dismiss or delete a specific alert |
| Method | Endpoint | Parameters | Description |
|---|---|---|---|
| GET | /api/v1/export/soil/csv |
lat, lon |
Soil analysis as CSV download |
| GET | /api/v1/export/soil/geojson |
lat, lon |
Soil data as GeoJSON (for QGIS, ArcGIS) |
| GET | /api/v1/export/risk/geojson |
lat, lon |
Risk assessment as GeoJSON |
| GET | /api/v1/export/report |
lat, lon |
Full JSON report (soil + risk + weather + recommendations) |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/info |
API status, version, and endpoint directory |
| GET | /api/v1/health |
Health check (includes cache stats, alert counts, uptime) |
| GET | /api/v1/timeseries/soil-moisture |
Historical soil moisture (lat, lon, days default 30) |
| POST | /api/v1/area/analyze |
Analyze a polygon area (GeoJSON body with coordinates array) |
| Protocol | Endpoint | Description |
|---|---|---|
| WS | /ws/alerts |
Real-time alert stream. Pushes JSON alert objects for M4.0+ earthquakes and other triggered hazards. |
The React app is organized into four component groups:
| Component | Responsibility |
|---|---|
MapView |
Main Leaflet map container. Dark/light tile layers, click-to-analyze handler, earthquake markers with magnitude-scaled sizing, risk overlay circles, animated fly-to on coordinate search, mobile coordinate chip. |
LayerControl |
Toggleable checkboxes for earthquakes, soil health, risk zones, and terrain layers. |
Legend |
Color-coded scales for earthquake magnitude, risk levels, and soil health grades. |
| Component | Responsibility |
|---|---|
RiskSummary |
Overlay panel showing composite risk score, individual hazard levels, active alerts count, and current weather conditions. Desktop: fixed top-right with scrolling. Mobile: integrated in sidebar. |
AlertFeed |
Live-updating list of alerts from WebSocket stream. Shows severity badge, title, description, timestamp, and distance from selected location. |
EarthquakeList |
Paginated list of recent seismic events (up to 50) with magnitude, depth, location, time ago, and felt reports. Includes stats summary bar (total count, max magnitude, avg depth, felt events) and a toggle to switch between list view and charts view (magnitude distribution, depth vs magnitude scatter, timeline). |
Charts |
17 chart components built with Recharts — see table below. |
WeatherDashboard |
Weather panel with WMO weather code icons, 6-metric grid, climate normals, and two integrated charts. |
| Chart | Type | Data Visualized |
|---|---|---|
SoilPropertyChart |
Bar | pH, organic carbon, nitrogen, CEC, bulk density |
MoistureDepthChart |
Area | Moisture content at 5 depths (0–81 cm) |
ErosionFactorChart |
Radar | RUSLE factors R, K, LS, C, P |
CarbonChart |
Composed (bar + line) | Current carbon stock vs potential, improvement rate |
HealthGaugeChart |
Radial bar | Soil health index (0–100) with grade label |
RiskComparisonChart |
Bar (horizontal) | Side-by-side comparison of all hazard risk levels |
FloodReturnChart |
Line | Flood probability vs return period |
RiskRadarChart |
Radar | All risk types on a single radar polygon |
SoilNutrientChart |
Bar (grouped) | NPK status — current level vs optimal range |
HealthBreakdownChart |
Pie | Contribution of each parameter to the health index |
EarthquakeMagDistChart |
Bar | Frequency distribution of earthquake magnitudes |
EarthquakeDepthMagChart |
Scatter | Depth vs magnitude scatter plot |
EarthquakeTimelineChart |
Line | Earthquake events over time |
WeatherConditionsChart |
Bar | Temperature, humidity, precipitation, wind speed |
CompositeRiskGauge |
Radial bar (dual) | Composite score + max individual risk |
SoilCompositionChart |
Pie | Sand, silt, clay percentages |
EnvironmentalRadarChart |
Radar | Multi-axis environmental conditions |
| Component | Responsibility |
|---|---|
SoilAnalysis |
Full soil analysis panel — property table, health grade, erosion details, carbon sequestration, integrated charts. |
RiskAnalysis |
Risk assessment panel — individual hazard breakdowns with probabilities, contributing factors, and risk comparison charts. |
Recommendations |
Tabbed interface for agriculture (crops, fertilizer, irrigation), disaster preparedness, and environmental restoration recommendations. |
ExportPanel |
Download buttons for CSV, GeoJSON, and full JSON report. Shows preview of export data. |
| Component | Responsibility |
|---|---|
Header |
App title, live UTC clock (1-second interval), coordinate search input (parses lat, lon), geolocation button (browser Geolocation API). |
Sidebar |
Desktop: slide-out panel. Mobile: bottom nav bar + slide-up drawer. Tabs: Dashboard, Soil, Risk, Recommendations, Earthquakes, Weather, Export. Fade-in transitions on content swap. |
Loading |
Spinner with contextual message. |
ErrorBoundary |
React error boundary with fallback UI and retry button. |
Located in backend/app/models/:
| Model | File | Method |
|---|---|---|
| Soil Property Prediction | soil_model.py |
Uses ISRIC SoilGrids API as primary data source (250m resolution global soil data). When ISRIC is unavailable, falls back to analytical estimation using pedotransfer-style heuristics based on latitude, climate, and terrain variables. Note: No trained ML model is currently deployed — the Random Forest + XGBoost ensemble architecture exists but requires training data. Confidence scores reflect data source quality. |
| RUSLE Erosion | erosion_model.py |
Computes A = R × K × LS × C × P where R is derived from annual precipitation pattern, K from soil texture triangle + organic carbon, LS from slope/length (Wischmeier & Smith), C from NDVI-derived cover, and P from land use/practice assumptions. |
| Landslide Susceptibility | landslide_model.py |
Weighted linear combination of 10 factors with sigmoid transformation to 0–1 probability. Weights calibrated against landslide inventory data. Regional multipliers for Himalayan, Andean, Alpine, and Pacific Rim zones. |
| Flood Risk | flood_model.py |
Multi-factor scoring: elevation deficit, slope, infiltration capacity (from soil texture), rainfall accumulation (24/48/72h), drainage area, imperviousness. Return period estimated via log-normal fit. |
| Wildfire Risk | fire_model.py |
Fosberg Fire Weather Index for current conditions. Fuel moisture content from temperature/humidity. Vegetation dryness from NDVI. Historical fire frequency weighting. Spread potential from wind speed + slope + fuel connectivity. |
| Liquefaction | liquefaction_model.py |
Susceptibility from grain size (sand/silt fraction), groundwater depth, and soil age. Probability given M7.0 event using Seed & Idriss (1971) simplified procedure adapted for available soil data. |
All primary data sources are free and require no API keys or registration.
| Source | URL | Data Used | Update Frequency |
|---|---|---|---|
| USGS Earthquake Hazards | earthquake.usgs.gov/fdsnws/event/1 |
Real-time seismic events (magnitude, location, depth, felt reports, tsunami flag) | Every 5 min (configurable) |
| Open-Meteo | api.open-meteo.com/v1, archive-api.open-meteo.com |
Current weather, recent precipitation, soil moisture at four depths, DEM elevation, and archive-based climate normals | 15 min – 7 days (per data type) |
| ISRIC SoilGrids | rest.isric.org/soilgrids/v2.0 |
Soil properties at 250m resolution — pH (H2O), organic carbon, CEC, texture fractions (sand/silt/clay), bulk density, total nitrogen | On demand, cached 1 hour |
| NASA FIRMS | firms.modaps.eosdis.nasa.gov |
Active fire/hotspot detection (public 24 h feeds, or a MAP_KEY for area queries) | 1 hour (cached) |
When an upstream API is unreachable the API degrades to real bundled data rather than invented numbers:
| File | Content | Source / licence |
|---|---|---|
backend/app/data/static/elevation_grid.npz |
Global 10 arc-minute topography, 1081 × 2161 int16, north-first |
ETOPO1 resampled by g2e/etopo10 (public domain) |
backend/app/data/static/koppen_grid.npz |
Köppen-Geiger climate class per 0.5° cell | Beck et al. (2018) via koppen-climate-lookup (ISC package; classification after Beck et al., CC BY 4.0) |
backend/app/data/static/climate_class_normals.json |
Representative annual temperature, precipitation, humidity and wind for each climate class | Derived from the climate-class literature; used only as a fallback |
Data is fetched via httpx.AsyncClient with connection pooling. Responses are cached in-memory using cachetools.TTLCache (default TTL: 1 hour, max entries: 1000) to minimize redundant API calls.
All configuration is managed via environment variables (loaded from .env file via pydantic-settings). The app runs with sensible defaults — no configuration is required for development.
| Variable | Default | Description |
|---|---|---|
APP_NAME |
TerraWatch |
Application name (shown in API info) |
APP_VERSION |
2.0.0 |
Version string |
DEBUG |
False |
Enable debug mode (verbose logging, auto-reload) |
LOG_LEVEL |
INFO |
Log level: DEBUG, INFO, WARNING, ERROR |
HOST |
0.0.0.0 |
Server bind address |
PORT |
8000 |
Server bind port (overridden to 7860 on HF Spaces) |
DATABASE_URL |
sqlite+aiosqlite:///./terrawatch.db |
Async database connection string |
CORS_ORIGINS |
localhost:3000/5173/4173, 127.0.0.1:5173/4173, *.hf.space |
Comma-separated allowed origins (* wildcards supported in hostnames) |
API_AUTH_ENABLED |
False |
Require an API key on protected routes |
API_SECRET_KEY |
(empty) | API key checked when API_AUTH_ENABLED=true |
FIRMS_MAP_KEY |
(empty) | NASA FIRMS key for area fire queries (public 24 h feeds work without it) |
OPEN_METEO_ENABLED |
True |
Enable Open-Meteo weather integration |
USGS_API_ENABLED |
True |
Enable USGS earthquake background feed |
CACHE_PERSIST |
True |
Persist the L2 cache in SQLite across restarts |
CACHE_MAX_SIZE |
1000 |
Maximum in-memory entries per cache tier |
RATE_LIMIT_PER_MINUTE |
100 |
API rate limit per client IP |
EARTHQUAKE_FETCH_INTERVAL |
300 |
Seconds between USGS earthquake polls |
HTTP_CONNECT_TIMEOUT |
5 |
Upstream connection timeout (seconds) |
HTTP_READ_TIMEOUT |
12 |
Upstream read timeout (seconds) |
terrawatch/
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI entry point, router registration, lifespan events
│ │ ├── config.py # Pydantic settings (env var loading)
│ │ ├── database.py # SQLAlchemy async engine, session factory, models
│ │ ├── api/
│ │ │ ├── routes/
│ │ │ │ ├── soil.py # /soil/analyze, /soil/moisture
│ │ │ │ ├── risk.py # /risk/all, /risk/landslide, /risk/flood, /risk/earthquake/recent
│ │ │ │ ├── recommendations.py # /recommendations/agriculture, /disaster, /environmental
│ │ │ │ ├── alerts.py # /alerts/active, /alerts/history, /alerts/{id}
│ │ │ │ ├── export.py # /export/soil/csv, /soil/geojson, /risk/geojson, /report
│ │ │ │ └── websocket.py # /ws/alerts WebSocket endpoint
│ │ │ └── middleware/
│ │ │ ├── auth.py # Optional API key authentication
│ │ │ └── rate_limit.py # Per-IP rate limiting
│ │ ├── models/ # Analytical / predictive models
│ │ │ ├── soil_model.py # Soil property prediction & health scoring
│ │ │ ├── erosion_model.py # RUSLE erosion computation
│ │ │ ├── landslide_model.py # Landslide susceptibility (10-factor)
│ │ │ ├── flood_model.py # Flood risk analysis
│ │ │ ├── fire_model.py # Wildfire risk assessment
│ │ │ └── liquefaction_model.py # Liquefaction potential
│ │ ├── services/ # Business logic layer
│ │ │ ├── soil_service.py # Orchestrates soil data fetching + model execution
│ │ │ ├── disaster_service.py # Coordinates all risk models
│ │ │ ├── weather_service.py # Open-Meteo API integration
│ │ │ ├── recommendation_service.py # Crop, fertilizer, irrigation, disaster prep logic
│ │ │ ├── alert_service.py # Alert creation, management, WebSocket broadcasting
│ │ │ ├── cache_service.py # TTL cache wrapper
│ │ │ ├── gis_service.py # Geospatial utilities (distance, area, elevation)
│ │ │ └── satellite_service.py # NDVI estimation, satellite data processing
│ │ ├── data/
│ │ │ ├── ingestion/ # External API fetchers
│ │ │ │ ├── earthquake_fetcher.py # USGS FDSN API client
│ │ │ │ ├── weather_fetcher.py # Open-Meteo API client
│ │ │ │ ├── soil_fetcher.py # ISRIC SoilGrids API client
│ │ │ │ └── fire_fetcher.py # NASA FIRMS API client
│ │ │ └── processing/ # Data transformation pipelines
│ │ └── utils/
│ │ ├── geo_utils.py # Haversine distance, bearing, bounding box
│ │ ├── math_utils.py # Statistical functions, interpolation
│ │ └── validators.py # Pydantic request/response schemas
│ ├── tests/
│ │ ├── test_soil.py # Soil analysis unit tests
│ │ ├── test_risk.py # Risk assessment tests
│ │ ├── test_api.py # API endpoint integration tests
│ │ └── test_gis.py # Geospatial utility tests
│ ├── ml/
│ │ ├── training/ # Model training scripts
│ │ ├── datasets/ # Training data
│ │ └── saved_models/ # Serialized model artifacts
│ ├── Dockerfile # Standalone backend container
│ └── requirements.txt # Python dependencies
├── frontend/
│ ├── src/
│ │ ├── index.tsx # React DOM entry point
│ │ ├── App.tsx # Root component, state management, routing
│ │ ├── components/
│ │ │ ├── Map/ # MapView, LayerControl, Legend
│ │ │ ├── Dashboard/ # RiskSummary, AlertFeed, Charts (×17), EarthquakeList, WeatherDashboard
│ │ │ ├── Analysis/ # SoilAnalysis, RiskAnalysis, Recommendations, ExportPanel
│ │ │ └── Common/ # Header, Sidebar, Loading, ErrorBoundary
│ │ ├── services/
│ │ │ ├── api.ts # REST API client (fetch wrapper with error handling)
│ │ │ └── websocket.ts # WebSocket client (auto-reconnect)
│ │ ├── types/
│ │ │ └── index.ts # TypeScript interfaces for all data models
│ │ └── styles/
│ │ └── globals.css # CSS custom properties, Tailwind directives, responsive utilities
│ ├── public/ # Static assets
│ ├── index.html # HTML template
│ ├── package.json # npm dependencies and scripts
│ ├── vite.config.ts # Vite config (proxy, aliases, build settings)
│ ├── tailwind.config.js # Tailwind theme (dark mode, custom colors)
│ ├── tsconfig.json # TypeScript compiler config
│ ├── postcss.config.js # PostCSS plugins
│ ├── nginx.conf # Production nginx config (SPA fallback, API proxy)
│ └── Dockerfile # Multi-stage frontend container (build → nginx)
├── docs/
│ └── screenshots/ # UI screenshots
├── docker-compose.yml # Multi-container orchestration
├── Dockerfile # Single-container build (Hugging Face Spaces)
├── LICENSE # MIT License
└── README.md
TerraWatch is designed to be transparent about the source and quality of every data point it returns. Every API response includes a data_quality object that tracks:
sources— Which external APIs provided data for this responsewarnings— Any fallback/estimation caveatsis_fully_real_data— Boolean flag:trueonly when ALL data comes from real APIs
| Data Type | Primary Source | Fallback | How to Tell |
|---|---|---|---|
| Soil properties | ISRIC SoilGrids API (250 m, 0–30 cm weighted mean) | Analytical pedotransfer estimation | soil_data_source field |
| Weather | Open-Meteo API (real-time) | Köppen-Geiger climate-class climatology (0.5°) | source field = "open-meteo" vs "estimated" |
| Soil moisture | Open-Meteo soil model | DB cache (< 24h) → climate-based estimation | source field |
| Elevation | Open-Meteo Elevation API | Bundled ETOPO1 10 arc-minute grid | elevation_source in metadata |
| Slope | 4-point elevation gradient | Heuristic from elevation | slope_source in metadata |
| NDVI | — (no live feed configured) | Land-cover class + climate adjustment | source field = "estimated" |
| Earthquakes | USGS real-time feed | None (real data only) | Always real |
| Active fires | NASA FIRMS | Empty list (requires MAP_KEY) | source field |
Recent overhaul (v2): Many of the original limitations below have been addressed. Items marked ✅ are fixed; items marked
⚠️ still apply.
- ✅ ML training infrastructure — A training script (
backend/ml/train_soil_model.py) now exists to train the RF+XGBoost ensemble from ISRIC SoilGrids data. Until a trained model is deployed, the improved analytical fallback is used (with honest confidence scores and_validation_statusflag). - ✅ Elevation & slope — Elevation comes from the Open-Meteo Elevation API, falling back to a real ETOPO1 10 arc-minute grid. Slope is computed from a 5-point elevation gradient.
⚠️ Risk models are unvalidated — Landslide, flood, fire, and liquefaction models use expert-weighted analytical methods. They now carry a_validation_status: "unvalidated_analytical_model"field. Validation against historical event inventories is planned.⚠️ No ground truth comparison — Accuracy metrics are not yet computed, though test suites now verify directional correctness and plausible ranges.- ✅ NDVI estimation improved — Fallback NDVI now uses land-cover type and climate normals instead of a crude latitude heuristic.
- ✅ Cache persists across restarts — A two-tier L1 (memory) + L2 (SQLite) cache is now used. Set
CACHE_PERSIST=falseto disable disk persistence. - ✅ Weather fallback uses real climatology — When Open-Meteo is unavailable, the bundled Köppen-Geiger class grid provides realistic temperature, precipitation, humidity and wind estimates instead of synthetic 5° values.
- ✅ Soil moisture caching — Successful API fetches are persisted to SQLite; stale cache (< 24h) is used before falling back to climate-based estimation.
- ✅ Security hardened — API-key auth is opt-in (
API_AUTH_ENABLED), no secret is ever generated automatically, CORS defaults to explicit origins plushttps://*.hf.space, and all route inputs are validated with PydanticQueryconstraints. - ✅ WebSocket broadcast race condition fixed — Connection set is copied before iteration.
⚠️ Build-tool advisories —npm auditreports advisories in the Tailwind CSS 3 CLI dependency chain (braces,micromatch,chokidar). They affect only the local build/watch tooling; the production image is nginx serving static files and ships nonode_modules. Clearing them requires the Tailwind 4 migration.
Query /api/v1/data-quality?lat={lat}&lon={lon} to get a real-time report on which data sources are live vs. using fallbacks for any location.
cd backend
# Install test dependencies (if not already installed)
pip install pytest pytest-asyncio anyio httpx
# Run all tests
python -m pytest tests/ -v
# Run specific test modules
python -m pytest tests/test_soil.py -v # Soil analysis tests
python -m pytest tests/test_risk.py -v # Risk assessment tests
python -m pytest tests/test_api.py -v # API integration tests
python -m pytest tests/test_gis.py -v # Geospatial utility tests
python -m pytest tests/test_weather_fallback.py -v # Climate normals fallback
python -m pytest tests/test_graceful_degradation.py -v # API failure scenarios
python -m pytest tests/test_risk_validation.py -v # Risk model directional checks
python -m pytest tests/test_soil_model_accuracy.py -v # Soil prediction accuracyTests cover soil property prediction, risk model computations, API endpoint responses, geospatial utility functions, weather fallback quality, graceful degradation under API failures, and soil model accuracy against known reference locations.
This project is licensed under the MIT License. See LICENSE for the full text.
Copyright (c) 2026 TerraWatch