Analyse wildfire perimeters on an interactive map, run geodesic proximity checks, and drill into incident context - built for the Geospatial Insight technical assessment.
This solution follows the brief’s technical constraints:
| Layer | Requirement | Implementation |
|---|---|---|
| Frontend | Angular (latest) & OpenLayers | Angular 21 SPA; OpenLayers map, layers, and interactions |
| Backend | Python (FastAPI/Flask) or Node.js (TypeScript) | Node.js with TypeScript and Express — typed handlers end-to-end with the Angular client |
| Database | PostgreSQL + PostGIS | PostgreSQL 16 with PostGIS for storage and metre-based spatial predicates |
| DevOps | Fully Dockerized; **docker-compose** for local run |
docker-compose.yml orchestrates db, api, and frontend |
Reviewers should be able to run Compose and see the application without undocumented steps.
| Step | Action |
|---|---|
| 1 | Clone the repository and open the **fire-intelligence-dashboard** directory (Compose lives here). |
| 2 | Copy **.env.example** → **.env** (defaults are fine for local development). |
| 3 | Place **wildfire_data_spain.json** in **data/** (GeoJSON used by the ingest script). |
| 4 | Start the stack: **docker-compose up** — use **docker-compose up --build** the first time or after Dockerfile changes. Services: PostGIS, API on port 3000, Angular dev server on port 4200. |
| 5 | In a second terminal, ingest geometries: **docker-compose exec api npm run ingest** |
| 6 | Open **http://localhost:4200** for the dashboard. Health check: **http://localhost:3000/api/health**. |
Optional Makefile shortcuts (POSIX make; Git Bash on Windows)
make up # docker-compose up --build
make down # docker-compose down -v
make ingest # docker-compose exec api npm run ingest
make logs # docker-compose logs -f apiPrerequisites: Docker Desktop (or Docker Engine + Compose plugin), Git. Node.js locally is optional when everything runs in containers.
This section explains why the app is structured and presented this way - not only which libraries were used.
Backend and persistence
- Node.js + TypeScript + Express were chosen over Python to keep one strongly typed language alongside Angular, shared mental models for DTOs validation (Zod), and a straightforward REST surface under
**/api** that maps cleanly to GeoJSON consumers. - PostGIS holds authoritative geometries (
4326storage). Proximity is evaluated with**geography** types and**ST_DWithin** so distances are true metres on the spheroid, satisfying the brief’s projection accuracy requirement rather than approximating in planar Web Mercator degrees.
Map UX (Spain sample data)
- The default view centres on Spain, matching the provided GeoJSON extent so evaluators land on meaningful ground truth immediately.
- OpenLayers separates concerns into sources and layers: base map, fire polygons, a dedicated proximity buffer circle, and a highlight layer for query results — easy to toggle styles and clear between clicks.
Proximity interaction (Part B)
- Translucent buffer: A circle geometry is drawn at the click location using the same radius (default 1 km) sent to the API so the on-screen disc matches the backend search radius.
- Clear-on-new-click: Each map click clears the previous buffer and proximity highlights before issuing a new request, so only one active analysis context is shown at a time.
- Semantic styling: Perimeters returned by
**POST /check-proximity** are styled red on a dedicated highlight layer; the buffer ring uses a cool translucent blue so “search area” and “hit geometry” read distinctly at a glance.
Information density
- A right-hand sidebar shows rich fire metadata when a perimeter is selected; an empty state guides users toward map clicks - prioritising map-first workflows before detailed panels.
- FWI / area filters, layer toggles, and timeline-style exploration support analyst-style narrowing beyond the minimum task; they reuse the same GeoJSON pipeline so complexity stays in filters rather than duplicate endpoints.
Engineering hygiene
- Modular Angular structure (feature pages, services, typed HTTP) and parameterised SQL on the server aim for review-friendly code and safe spatial queries under load (rate limiting on proximity).
| Area | Improvement |
|---|---|
| Hardening | Contract tests for core map/proximity flows, performance budgets on large FeatureCollections |
| Product | Authentication, roles, audit trails for operational use |
| Realtime | Push or poll for newly ingested fires; operational alerting |
| Temporal | Deeper timeline/compare tooling and export (video/GIF, reporting bundles) |
| Scale | Partitioning large national datasets, caching heavy aggregates, read replicas |
| Ops | Staging deploys, observability dashboards, chaos testing on DB failover |
The brief requires POST proximity search in metres, accounting for projections.
- Input: The client sends latitude, longitude, and optionally
**radius_m** (integer metres). The default radius is 1000 (1 km) when omitted - aligned with Part A (3). - Coordinates: Map clicks are transformed from display CRS (EPSG:3857) to EPSG:4326 before calling the API so stored geometries and query points share the same geographic CRS.
- Database: PostGIS
**ST_DWithin(geom::geography, point::geography, radius_m)** restricts to perimeters within the geodesic distance.**ST_Distance** orders results; each feature carries**distance_m**for UI sorting and labels. - Output: Matching perimeter geometries are returned as GeoJSON features for highlighting on the map.
Reference material
- Dashboard statistics and health indicators
- FWI / minimum-area filters and operational layer toggles
- Optional timeline / compare visuals where implemented
- Dockerised ingest pipeline for the supplied GeoJSON
Base path: /api
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/api/health |
Liveness and database connectivity |
GET |
/api/stats |
Aggregate dashboard statistics |
GET |
/api/fire-polygons |
GeoJSON FeatureCollection (filters optional) |
GET |
/api/fire/:id |
Single fire feature |
POST |
/api/check-proximity |
Perimeters within **radius_m** metres of **{ lat, lon }** (default 1000) |
| Resource | Link |
|---|---|
| License | LICENSE (MIT) |
| Contributing | CONTRIBUTING.md |
| Security | SECURITY.md |
| Code of Conduct | CODE_OF_CONDUCT.md |
| Changelog | CHANGELOG.md |
| Architecture (extended) | docs/architecture.md |
Configuration via environment variables, constrained CORS for dev/prod, rate limiting on expensive proximity traffic, parameterised SQL, and hardened Compose defaults where applicable.
FireWatch · Geospatial Insight technical assessment submission