Skip to content
MSP
Fire hotspots clustering over an abstract peatland map, flowing into two pipelines labelled alert in hours and burned area in days
  • Solution Architecture
  • solution-design
  • aws
  • cloud-native-geospatial
  • postgis

Designing a Peatland Fire Detection System for Central Kalimantan on AWS and Open-Source GIS

Mahardi Setyoso Pratomo12 min readEnglish

An end-to-end design for detecting peatland fires in Central Kalimantan with free satellite data, open-source GIS and AWS, and why each component was chosen.

What problem does this system solve?

It turns free satellite fire data into field tasks fast enough to matter, and keeps a history of what burned. This is a design exercise for a fictional provincial agency in Central Kalimantan, built only on public data, open-source GIS and AWS. No real client, no real budget.

The starting point I assumed is common in disaster operations: staff look at hotspot maps by hand, decide where to send fire brigades by experience, and map the burned area after the season, if at all. Three things are missing:

  • Speed and consistency. Whether a hotspot gets attention depends on who is on shift.
  • Prioritisation. Brigades are few, hotspots are many, and nothing ranks them.
  • Memory. Detections, field checks and burned areas are not stored in one place, so next season starts from zero.

The system has three kinds of users: an operations room that triages alerts, field teams that check and report, and leaders who need a weekly picture by district.

Why Central Kalimantan?

Because its fires are mostly peat fires, which are hard to put out once they spread. In the 1990s the Mega Rice Project dug more than 4,500 km of canals to drain peat for a planned million hectares of rice fields. The drained peat stayed dry and flammable. In 2019, fires burned across nearly 270,000 hectares of land in the province, much of it on former project areas.

Peat fires smoulder below the surface and can burn for weeks. That shapes the whole design: the value of the system is in the first hours, before a surface fire becomes a peat fire.

What does the system have to do?

Five functions, and a short list of qualities that apply to all of them.

Need What the system does
Early warning Pulls new hotspots several times a day and turns them into ranked fire clusters
Prioritisation Scores each cluster with transparent rules and caps the daily list at what brigades can check
Field validation Sends tasks to a mobile app that works offline, with photos, GPS and a short form
Burned area Maps burned area from optical imagery after fire events and stores it as polygons
Reporting A dashboard by district, peat status and period, plus the status of the last pipeline run
Quality Design rule
Auditability Status changes are appended, never overwritten; every polygon records its source scene and parameters
Reliability A failed run is retried and visible on the dashboard; a missed run must never look like "no fires"
Security Role-based access; field data and internal notes are not public
Interoperability Other agencies read the data through open standards (OGC services), not exports by email
Cost Pay for compute when pipelines run; no software licences

Stated assumptions: field capacity is the scarcest resource, connectivity in the field is unreliable, and the agency prefers data stored in Indonesia.

Why two pipelines with two rhythms?

Because fire has two questions with very different deadlines. "Where is it burning now?" needs an answer in hours. "What burned, and how much?" can wait for a clear satellite image days later. Forcing both into one schedule makes one of them wrong: either the alert is too slow or the mapping job runs on cloudy images for nothing.

Alert pipeline Burned area pipeline
Question Where is it burning now? What burned, and how much?
Data NASA FIRMS hotspots (VIIRS and MODIS) Copernicus Sentinel-2 L2A
Trigger Schedule, every hour Schedule, weekly, and on demand after an event
Output Ranked fire clusters and field tasks Burned area polygons with area in hectares
Compute Seconds, small tables Minutes, large rasters
Failure mode to avoid Silence that looks like "no fires" Cloud and haze mistaken for unburned land
Two pipelines: FIRMS hotspots flow hourly into ranked clusters and field tasks, Sentinel-2 imagery flows weekly into burned area polygons, both into one PostGIS databaseOpen full size
Figure 1. One database, two rhythms: alerts in hours, burned area in days.

FIRMS publishes global active fire data within three hours of the satellite pass. Polling every hour means a new detection waits at most an hour on our side, which keeps the agency's own delay smaller than the satellite's.

What does the architecture look like end to end?

Seven layers, from public data sources to the people who act on them. Everything runs in one AWS region, Asia Pacific (Jakarta), except the open imagery archive, which the pipeline reads in place.

Architecture: FIRMS and Sentinel-2 into Lambda and AWS Batch, S3 and PostGIS on RDS, GeoServer, then a MapLibre web map, Superset dashboard and QField appOpen full size
Figure 2. Sources on the left, people on the right; PostGIS is the single source of truth in the middle.
Layer Component Role
Sources NASA FIRMS API, Sentinel-2 L2A COGs on the AWS Registry of Open Data, district and peat boundary polygons Free inputs
Ingestion Amazon EventBridge Scheduler, AWS Lambda Fetch new hotspots every hour
Processing AWS Step Functions, AWS Batch on Fargate (Python, GDAL, rasterio) Cluster and score hotspots; compute burned area
Storage Amazon S3 with lifecycle rules Clipped imagery, outputs, run logs
Database Amazon RDS for PostgreSQL with PostGIS Clusters, polygons, tasks, status history
Serving GeoServer on Amazon ECS (Fargate) WMS, WFS and vector tiles for every client
Apps MapLibre web map, Apache Superset dashboard, QField and QGIS Operations room, leaders, field teams, analysts
Cross-cutting Amazon Cognito, IAM, KMS, CloudWatch, CloudTrail, Amazon SNS Access, encryption, monitoring, audit, notifications

Why this tech stack?

Each choice answers one requirement, and each has an alternative I would switch to under a different constraint.

Component Why this one When I would choose something else
NASA FIRMS Free, global, available within three hours, with a simple API; VIIRS detects at 375 m For alerts within minutes, add geostationary data (see the last section)
Sentinel-2 L2A Free and open, 10–20 m resolution, already atmospherically corrected, and stored on AWS as Cloud-Optimized GeoTIFFs with a STAC search API Sentinel-1 radar when haze and cloud block optical images for weeks
EventBridge Scheduler + Lambda An hourly call that returns a small CSV does not justify an always-on server; it costs almost nothing when idle A container if the job grows past Lambda's 15-minute limit
Step Functions + AWS Batch Raster jobs need GDAL, memory and minutes of runtime, which suits containers. Step Functions adds retries and a visible run history, which feeds the "last run" panel on the dashboard Airflow or Kestra if the agency already runs one for other pipelines; for two pipelines, a scheduler server is overhead
S3 + COG reads The pipeline reads only the pixels inside the province from the open archive instead of copying whole scenes; lifecycle rules delete imagery after its retention period None at this scale
PostgreSQL + PostGIS The core questions are spatial joins and clustering (which district, on peat or not, which hotspots belong together), and PostGIS does them in SQL. Analysts open the same tables directly in QGIS A data warehouse such as Athena or Redshift only if years of history make analytical queries slow
GeoServer One server publishes the same layers as OGC services to QGIS, QField, the web map and other agencies Lighter tile servers (Martin, pg_tileserv) if web maps were the only client
MapLibre GL JS Open-source web map rendering vector tiles, hosted as static files on S3 and CloudFront None needed
Apache Superset Filters, charts and maps on PostGIS without writing a front end, with role-based access A custom page if leaders need only three numbers
QField + QGIS QField runs QGIS projects on phones, works offline and syncs back; forms and styles are built once in QGIS ODK or KoboToolbox if the form matters more than the map
Jakarta region Keeps agency data in Indonesia The open imagery archive is hosted outside Indonesia; only the clipped result is stored locally

How does a hotspot become a field task?

In six steps, and the ranking is a set of visible rules rather than a black-box model.

  1. Fetch. Lambda calls the FIRMS area API for the province's bounding box and loads new detections into a staging table.
  2. Clip and deduplicate. Keep points inside the province polygon; drop detections already loaded from an earlier call.
  3. Cluster. Group detections within about 1 km of each other in the last 24 hours into one fire cluster.
  4. Enrich. Attach district, peat status and land cover to each cluster with spatial joins.
  5. Score and cap. Rank clusters and keep only as many "priority" tasks as field teams can check that day.
  6. Assign and track. Create a task for QField, notify the duty officer through SNS, and append every status change.
-- Step 3: cluster today's hotspots (UTM 50S, metres; ~1 km, at least 2 points)
SELECT id,
       ST_ClusterDBSCAN(ST_Transform(geom, 32750), eps => 1000, minpoints => 2)
         OVER () AS cluster_id
FROM hotspots
WHERE acq_time > now() - interval '24 hours';
Workflow from hotspot to field task: fetch from FIRMS, clip to province, cluster within 1 km, enrich with district and peat, score and cap by field capacity, assign to QField and record the resultOpen full size
Figure 3. Detection proposes, people decide: every cluster passes a human check before it counts as a fire.
Scoring factor Why it matters
On peat Peat fires spread underground and are hardest to stop
Persistence Detected again in a later pass means it is still burning
Cluster size More detections usually means a larger fire
Detection confidence FIRMS flags low-confidence detections

The cap is the important part. If every cluster above a threshold is "priority", a bad day produces a list nobody can finish, and the label stops meaning anything. Ranking against the real number of available teams keeps the top of the list actionable. Each task shows its score and the factors behind it, so a duty officer can disagree with a reason.

How is the burned area mapped?

With the difference in burn ratio before and after the fire, computed from two Sentinel-2 bands. The Normalized Burn Ratio uses near-infrared (B8A) and shortwave infrared (B12); burned vegetation lowers it, so a large drop between a pre-fire and a post-fire image marks burned land.

# Burned area candidate from two cloud-masked Sentinel-2 L2A images
nbr_pre  = (pre.B8A - pre.B12) / (pre.B8A + pre.B12)
nbr_post = (post.B8A - post.B12) / (post.B8A + post.B12)
dnbr = nbr_pre - nbr_post
burned = dnbr > 0.27          # starting threshold, tuned against field checks

The batch job then masks cloud and shadow with the L2A scene classification layer, turns burned pixels into polygons, drops slivers below a minimum area, and computes area in hectares in PostGIS with ST_Area(geom::geography), which avoids picking one UTM zone for a province that spans two.

Burn ratio before and after: a pixel grid of NBR before, NBR after with a burn scar and masked cloud, dNBR above 0.27 in gold, and the resulting burned area polygonOpen full size
Figure 4. Two images, one subtraction, one threshold. Cloud pixels are masked, not counted as unburned.

Haze is the honest limitation. During the worst weeks, optical images may be useless. The design treats a burned area polygon as a candidate until it is supported by hotspot history or a field check, and the dashboard shows when the last usable image was taken.

How is the system secured, monitored and kept?

With managed AWS services and a few rules that matter more than the tools.

Concern Design
Access Amazon Cognito for web and dashboard users; roles for operations, field, leadership and analysts
Encryption KMS-encrypted S3 and RDS; TLS everywhere
Audit CloudTrail for infrastructure; an append-only status history table for every task and polygon
Monitoring CloudWatch alarms on failed runs; the dashboard shows the time of the last successful fetch
Backup and recovery RDS automated backups and snapshots; infrastructure defined as code so the stack can be rebuilt
Retention S3 lifecycle rules delete clipped imagery after its retention period; vector history is kept

The monitoring rule I care most about: a pipeline that stops must be loud. An empty map after a failed fetch looks exactly like a good day.

Two identical empty maps side by side: a good day with a recent last successful fetch, and a failed fetch whose stale timestamp raises an alarmOpen full size
Figure 5. An empty map is only good news when the last fetch is recent.

What did I deliberately leave out?

Four things that would make a first version harder to deliver without making it more useful yet.

Left out Why When to add it
Geostationary data (Himawari) Alerts within minutes add complexity; hourly FIRMS is enough for a first version When field teams can respond faster than the alert arrives
Sentinel-1 radar SAR preprocessing is a project of its own When haze blocks optical mapping for whole seasons
Deep learning No validated local labels yet; rules are explainable from day one After a season of field-checked clusters provides training data
Linking fires to land permits Legally sensitive, and permit data is not reliably public Only with a mandate and authoritative data
Four cards for what the first version leaves out: Himawari, Sentinel-1 radar, deep learning and links to land permits, each with a trigger for adding itOpen full size
Figure 6. Each "not yet" comes with the condition that would change it.

I wrote more about this habit, documenting the no, in Documenting What I Didn't Build.

FAQ

Can Copernicus Sentinel data be used in a government system?

Yes. Access to Sentinel data is free, full and open, including for operational and commercial use. Products derived from it should credit the source, for example "Contains modified Copernicus Sentinel data".

Why not rely on hotspots alone?

Hotspots say where it was hot at the moment of a satellite pass. They do not give the extent of what burned, and they miss fires under thick smoke or between passes. Burned area mapping fills that gap afterwards.

Why PostGIS and not a data warehouse?

The workload is operational: frequent small writes, spatial joins and clustering, and analysts editing in QGIS. That is what PostgreSQL with PostGIS is built for. A warehouse becomes useful later for multi-year analysis.

Is this design tied to Central Kalimantan?

No. Swapping the province polygon, peat map and UTM zone adapts it to Riau, South Sumatra or any fire-prone region.

References

Last updated: 3 November 2026.