Geospatial risk intelligence for critical infrastructure. Detects land-surface changes from satellite imagery, scores threat severity using terrain and proximity analysis, and delivers actionable risk events to asset operators - queryable via natural language powered by LLM integration (Ollama locally, AWS Bedrock or Azure OpenAI in production).
End-to-end geospatial engineering - satellite data pipelines, spatial analysis, pretrained and custom-trained ML models, LLM-powered natural language queries, and full-stack cloud architecture.
Interactive map displaying assets to be monitored within a specified area of interest.
Processing run management showing pipeline status, change polygon counts, and risk event summaries.
Sentinel-2 imagery showing vegetation state before detected change event.
Sentinel-2 imagery showing vegetation state after detected change event (in this case, the 2018 Camp fire) with detected change polygons.
Detailed risk event displayed on map with explainable score breakdown showing individual factor contributions, in this case including a possible landslide event detected using the custom trained ML model.
Risk event alert with actionable instructions (can be integrated into a site inspection scheduling system).
Ask questions in plain English - the LLM translates them into structured spatial queries against the database.
Query results displayed on the map with result list. Results can be sent to the Risk Events panel for triage.
Scheduling panel with configurable frequency, cloud cover threshold, and job history showing automated processing runs.
This project combines three engineering disciplines into a single integrated platform:
Wildfires, landslides, and other land-surface changes threaten critical infrastructure - power lines, substations, hospitals, schools, and transportation corridors. The organizations responsible for these assets (electric utilities, pipeline operators, transportation agencies, emergency managers) typically learn about threats reactively, after damage has occurred or during costly manual inspections.
This platform turns freely available satellite data into continuous, automated risk monitoring:
The result is a prioritized feed of risk events that tells an asset operator: "This specific vegetation loss, 200 meters upslope of your substation on a 30-degree slope, has a risk score of 82 (Critical) - here's the before/after imagery."
| Layer | Technology | Purpose |
|---|---|---|
| Database | PostgreSQL + PostGIS | Spatial data storage and queries |
| Object Storage | MinIO (local) / S3 (AWS) / Azure Blob Storage (in progress) | Raster imagery and processing artifacts |
| API | ASP.NET Core 8 | REST API with EF Core + NetTopologySuite |
| Raster Pipeline | Python 3.11+ | Geospatial processing (rasterio, geopandas, pystac-client) |
| Web UI | SvelteKit + ArcGIS Maps SDK | Interactive mapping and visualization |
| Background Jobs | Hangfire (local) / EventBridge (AWS) / Azure Functions (in progress) | Scheduled processing and notifications |
| Cloud Deployment | Terraform + AWS (App Runner, ECS Fargate, RDS, S3, CloudFront); Azure in progress | Production cloud infrastructure |
| ML Classification | PyTorch + TorchGeo | Land cover classification (EuroSAT) |
| ML Segmentation | PyTorch + segmentation-models-pytorch | Landslide detection (custom-trained U-Net) |
| LLM Integration | Ollama (local) / AWS Bedrock / Azure OpenAI (in progress) | Natural language spatial queries |
┌─────────────────────────────────────────────────────────────────────────┐
│ Web UI (SvelteKit) │
│ ArcGIS Maps SDK │
└────────────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ API (.NET 8) │
│ Areas of Interest │ Assets │ Processing │ Risk Events │ Query │
│ Hangfire Scheduler │
└───────────┬───────────────────────────────┬───────────────┬─────────────┘
│ │ triggers │ NL queries
▼ ▼ ▼
┌───────────────────────┐ ┌──────────────────────────┐ ┌───────────────┐
│ PostgreSQL + PostGIS │ │ Raster Pipeline (Python)│ │ Ollama │
│ - AOIs & Assets │ │ - STAC Search │ │ (Local LLM) │
│ - Processing Runs │◄───│ - NDVI Change Detection │ └───────────────┘
│ - Change Polygons │ │ - Terrain Analysis │
│ - Risk Events │ │ - ML Land Cover │
│ │ │ - ML Landslide Detection│
└───────────────────────┘ │ - Risk Scoring │
└────────────┬─────────────┘
│
▼
┌──────────────────────────┐
│ Object Storage (MinIO) │
│ - Satellite Imagery │
│ - NDVI Rasters │
│ - DEM Tiles │
│ - ML Models │
└──────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ Web UI (SvelteKit + <<CloudFront>>) │
│ ArcGIS Maps SDK │
└────────────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ API (.NET 8 + <<App Runner>>) │
│ Areas of Interest │ Assets │ Processing │ Risk Events │ Query │
│ <<EventBridge>> Scheduler │
└───────────┬───────────────────────────────┬───────────────┬─────────────┘
│ │ triggers │ NL queries
▼ ▼ ▼
┌───────────────────────┐ ┌──────────────────────────┐ ┌───────────────┐
│ PostgreSQL + PostGIS │ │ Raster Pipeline (Python)│ │ <<Bedrock>> │
│ <<RDS>> │ │ <<ECS Fargate Spot>> │ │ (Cloud LLM) │
│ - AOIs & Assets │◄───│ - STAC Search │ └───────────────┘
│ - Processing Runs │ │ - NDVI Change Detection │
│ - Change Polygons │ │ - Terrain Analysis │
│ - Risk Events │ │ - ML Land Cover │
│ │ │ - ML Landslide Detection│
└───────────────────────┘ │ - Risk Scoring │
└────────────┬─────────────┘
│
▼
┌──────────────────────────┐
│ Object Storage (<<S3>>) │
│ - Satellite Imagery │
│ - NDVI Rasters │
│ - DEM Tiles │
│ - ML Models │
└──────────────────────────┘
The <<marked>> items are the only differences between deployments - cloud managed services replace local equivalents (AWS shown; Azure provider in progress):
| Component | Local | AWS |
|---|---|---|
| Web Hosting | SvelteKit dev server | CloudFront CDN |
| API Hosting | localhost | App Runner (scale-to-zero) |
| Scheduler | Hangfire (in-process) | EventBridge |
| Database | PostgreSQL container | RDS PostgreSQL |
| Pipeline Execution | Local subprocess | ECS Fargate Spot |
| Object Storage | MinIO | S3 |
| LLM Provider | Ollama | Bedrock |
Three DI-swappable provider interfaces (IObjectStorageService, ISchedulerService, IPipelineExecutor) enable the same application code to run against any environment - local services swap for cloud managed services via configuration. A fourth interface (ILlmService) abstracts the LLM provider.
The platform uses a multi-factor risk scoring model (0-100 scale):
| Factor | Weight | Description |
|---|---|---|
| Distance | 28 pts | Proximity of change to asset (<100m = max score) |
| NDVI Drop | 25 pts | Severity of vegetation loss (more negative = higher risk) |
| Area | 15 pts | Size of change polygon |
| Slope + Direction | 20 pts | Terrain steepness; upslope (landslide/debris risk) 1.5-2.5x, downslope (fire risk) 0.7-0.9x |
| Aspect | 5 pts | South-facing slopes = higher fire risk |
| Land Cover | multiplier | ML-classified context: Forest=1.0x, Crop=0.3x, Highway=0.25x (requires [ml] deps) |
| Landslide | multiplier | ML-detected debris on steep terrain: 1.8x base, +0.5x if upslope, capped at 2.5x |
| Asset Criticality | multiplier | Critical assets (hospitals, substations) get 2x weight |
Risk Levels: Critical (75-100), High (50-74), Medium (25-49), Low (0-24)
The platform uses two ML models that integrate into the pipeline as optional dependencies - the pipeline degrades gracefully without them.
Pretrained EuroSAT model (via TorchGeo) classifies the land cover around each change polygon. This provides context for risk scoring: a vegetation loss event in forest land (1.0x) is treated very differently from one on agricultural land (0.3x) where seasonal clearing is routine.
A U-Net segmentation model trained in-house on the Landslide4Sense dataset to detect landslide debris in satellite imagery. Post-fire terrain loses the root systems that stabilize slopes, making debris flow a critical correlated hazard for downstream infrastructure.
Training pipeline (machine-learning/landslide/):
TRAINING.mdInference integration (src/pipeline/georisk/raster/landslide.py):
Model storage: The trained model (94 MB) is stored in the /.cache/georisk/models/ml-models S3/MinIO bucket (not in git). The pipeline auto-downloads it to `on first use. Upload withgeorisk model upload , or train your own following [TRAINING.md`](machine-learning/landslide/TRAINING.md).
The platform supports natural language spatial queries powered by LLM integration. Users type queries like "Show me critical risk events within 500m of hospitals" and the system translates them into structured, type-safe query plans executed against the database.
QueryPlan - no raw SQL is ever generatedQueryExecutorService translates the plan into EF Core LINQ with PostGIS spatial functionsAzure OpenAI support follows the same ILlmService provider pattern. An AzureOpenAiLlmService implementation would use the Azure.AI.OpenAI NuGet package with Managed Identity authentication. Configuration: Llm__Provider=azureopenai with endpoint and deployment name settings. To be implemented alongside Azure deployment support.
geo-change-risk/
├── .github/workflows/ # CI pipelines (GitHub Actions)
├── src/
│ ├── api/ # .NET 8 REST API
│ │ ├── GeoChangeRisk.Api/ # Controllers, services, jobs
│ │ ├── GeoChangeRisk.Data/ # EF Core models, migrations
│ │ ├── GeoChangeRisk.Contracts/ # DTOs and shared types
│ │ └── GeoChangeRisk.Tests/ # xUnit tests (controllers, services, jobs)
│ ├── pipeline/ # Python raster processing
│ │ └── georisk/ # CLI and processing modules
│ └── web-ui/ # SvelteKit frontend
├── areas-of-interest/ # AOI configurations and data scripts
│ └── paradise/ # Paradise, CA (Camp Fire area)
├── infra/ # Infrastructure configuration
│ └── local/ # Docker Compose, env templates
├── deployments/ # Deployment scripts
│ ├── local/ # Local development setup
│ ├── aws/ # AWS deployment (Terraform + deploy script)
│ └── azure/ # Azure deployment (planned)
├── machine-learning/ # ML model training
│ └── landslide/ # U-Net landslide segmentation (training pipeline)
└── docs/ # Documentation
Prerequisites: Docker Desktop, .NET 8 SDK, Python 3.11+, Node.js 18+
# 1. Start infrastructure (generates credentials, starts PostgreSQL + MinIO + Ollama)
.\deployments\local\setup.ps1
# 2. Start API
cd src/api/GeoChangeRisk.Api
dotnet run
# 3. Start Web UI (in another terminal)
cd src/web-ui
npm install && npm run dev
Open http://localhost:5173. See docs/getting-started.md for full instructions including sample data initialization and running change detection.
The architecture is multi-cloud portable via DI-swappable provider interfaces (IObjectStorageService, ISchedulerService, IPipelineExecutor, ILlmService). See docs/multi-cloud-strategy.md for Azure and GCP deployment paths.
Fully implemented and deploys with a single script. See docs/aws-deployment.md for the full guide.
.\deployments\aws\scripts\deploy.ps1
Architecture: App Runner (scale-to-zero API, ~$2/month idle) + ECS Fargate Spot (on-demand pipeline) + RDS PostgreSQL + S3 + CloudFront + EventBridge Scheduler + VPC Endpoints. Estimated ~$47/month total.
Azure deployment will use equivalent managed services (App Service, Azure Functions, Azure Database for PostgreSQL, Blob Storage, Azure OpenAI). The same DI-swappable interfaces that power the AWS deployment will swap in Azure provider implementations with no changes to application code.
Optional read-only PostGIS views (v_areas_of_interest, v_asset_*, v_change_polygons, v_risk_events) can be installed for direct use in ArcGIS Pro. The views are not created automatically - run infra/local/optional/arcgis-views.sql manually after EF Core migrations. See docs/arcgis-pro-setup.md for setup instructions.
Questions, feedback, or want to see a live demo? Reach out at rob@izzystu.com - I'd love to chat.
This project is licensed under the MIT License.