Overview & architecture
Last reviewed against the codebase: 2026-07-25.
This is the narrative layer of the docs: what Fire Path AI is, why it is built the way it is, and how a fire detection becomes a property-specific alert. The exhaustive, always-current detail - every package, route, table and environment variable - lives in the generated reference, which is regenerated from the code and drift-gated on every build so it cannot silently fall out of sync. Read this page to understand the shape of the system; follow the cross-links for the specifics.
1. System context
Fire Path AI is an Australian bushfire situational-awareness and decision-support system. It turns live satellite fire detections, weather, terrain and a property’s own details into property-specific risk, spread estimates, time-to-impact and alerts - for residents, landholders and (as a roadmap) emergency services.
- Users: individuals and landholders on mobile + web; an operations view for wider situational
awareness. Access is organisation-scoped with four roles (
homeowner,agency_officer,council_admin,system_admin) - see the API reference for the RBAC matrix. - Boundary: Fire Path AI complements official warnings; it does not replace agency systems. Predictions are physics-based estimates, not authoritative agency products.
2. The tiers
Mobile + Web app ──HTTPS──▶ API server ──▶ PostGIS (Postgres) (Expo / MapLibre) (Node/Express) ▲ │ ▲ │ │ └─▶ Redis queue ──▶ Wind-worker │ │ │ (WindNinja, terrain wind) └────── push/alerts ◀──────┤ │ ├─ Ingest scheduler ─▶ FIRMS / DEA / OpenMeteo (external feeds) └─ Alert evaluator ──▶ push (FCM/APNs) + SMS/email fallbackClient - a universal Expo / React Native app (artifacts/firepath-ai) targeting iOS,
Android and a web SPA from one codebase, with MapLibre maps and an offline-map subsystem for
coverage gaps (the pack/eviction logic is built; actual on-device tile download is not yet wired -
see §7). It talks to the API over HTTPS and never contains database credentials.
API server - Node/Express (TypeScript) in artifacts/api-server, using Drizzle ORM
over PostGIS. It exposes auth, assets, fires, predictions, forecast, alerts, check-in and
geocoding routes (see the generated API reference). It is also the host for
two in-process background loops:
- the ingest scheduler (
src/ingest/scheduler.ts) - overlap-guardedsetIntervalloops that pull external feeds, run the clustering pass, and precompute spread snapshots; - the alert evaluator (
src/notifications/evaluator.ts) - matches active fires to a user’s assets and raises alerts, writing through a threat registry (threatRegistry.ts) that is the single writer for fire↔asset threats.
Terrain-wind worker - a separate container (Dockerfile.worker) that runs
containerised WindNinja jobs pulled off a Redis / BullMQ queue. It is a distinct tier because
WindNinja is CPU-heavy and slow, and must not block API request/response latency (see §4, step 4).
Data + queue - PostgreSQL + PostGIS is the system of record; Redis backs the BullMQ queue and cache. Both live in AWS in a full deployment - see Infrastructure.
3. Technology stack at a glance
| Layer | Choice | Where |
|---|---|---|
| Client | Expo / React Native (iOS, Android, web SPA), MapLibre | artifacts/firepath-ai |
| API | Node.js / Express 5, TypeScript, Drizzle ORM | artifacts/api-server |
| Shared spread geometry | @workspace/spread-model (dependency-free trig) | lib/spread-model |
| Schema / types | Drizzle schema + Zod contracts | lib/db, lib/api-zod, lib/api-spec |
| Database | PostgreSQL + PostGIS (spatial) | AWS RDS |
| Queue / cache | Redis (BullMQ) | AWS ElastiCache |
| Terrain wind | WindNinja (containerised worker) | Dockerfile.worker, src/sim/windninja.ts |
| Infra | AWS ECS Fargate, ALB, RDS, ElastiCache, Terraform (IaC) | see Infrastructure |
| Static sites | Cloudflare Pages / Workers (marketing, docs, web-app shell) | see Infrastructure |
| CI / tests | Vitest (API + client), k6 load, drift/redaction/link doc gates | see Testing |
This is a pnpm monorepo - the artifacts/* deployables share code through lib/* workspace
packages, so (for example) the spread-cone geometry is imported byte-for-byte identical by both the
server and the client rather than reimplemented twice. The full per-package breakdown is the
generated repository guide.
4. The fire-science model (physics, not “AI”)
The spread engine is deterministic fire physics - there is no machine-learning model in the prediction runtime. This is a deliberate, load-bearing decision: for a Government-grade life-safety product, an auditable formula you can defend line-by-line beats a black box, and (per the clustering module’s own header) ML adds no accuracy on this sparse, physically-constrained problem while losing auditability. The pipeline, in order:
- Satellite hotspots - NASA FIRMS and Geoscience Australia DEA detections are pulled by
the ingest scheduler and stored as a per-detection time series (
firestable, one row per hotspot pixel). Seesrc/ingest/firms.tsandsrc/ingest/dea.ts. - Fire-danger (FFDI) - the McArthur Forest Fire Danger Index is computed from OpenMeteo
weather in
src/ingest/ffdi.ts, using the standard BoM formFFDI = 2·exp(-0.45 + 0.987·ln(DF) − 0.0345·RH + 0.0338·T + 0.0234·V)and mapped to the AFDRS-aligned danger labels (Moderate → Catastrophic). - Rate of spread - a McArthur Mk5 (grass, simplified) rate-of-spread drives every band,
arrow and label. It lives in the shared
@workspace/spread-modelpackage (lib/spread-model/src/index.ts) asros_kmh = max(0.5, 0.5 + 0.18·windKmh), so server-precomputed geometry and any client-side fallback are identical and auditable. - Terrain-aware wind - WindNinja refines the wind field over terrain. It runs on the
dedicated worker (
src/sim/windninja.ts), asynchronously, because a terrain solve is slow and must never sit on the request path. The module supports two exec modes -dockerfor local dev andnativefor the ECS worker container (Fargate has no Docker daemon, sonativeis what makes it run in production). - Spread cone + ETA - a wind-direction hazard cone (apex at the fire, arcing ±half-angle
downwind) with the uncertainty half-angle widening with the forecast horizon (25° @ 1 h → 35°
@ 3 h → 45° @ 6 h, from
HAZARD_BAND_SPEC). The cone communicates “fire would likely head this way, this far, in this time” - it is not a physical cell-based fire simulation (that is future Cell2Fire work). Time-to-impact per asset is derived from the same ROS. - Fire tracking - a deterministic clustering + temporal-linking pass (
src/ingest/clustering.ts) turns the detection-centricfirestable into a fire-centric model:ST_ClusterDBSCANgroups this cycle’s hotspots, then FEDS-style append-or-new linking carries each fire’s identity forward across ingest cycles (UPDATE / SPLIT / CREATE / MERGE / INACTIVATE), giving every fire a persistent id, a hull, an intensity, and an observable movement vector - with a lineage audit trail.
Honest positioning: validated for grassland; forest/shrubland is approximate (a single fuel model is applied uniformly today - per-landscape fuel data is a roadmap item). Prediction accuracy is not yet measured - a backtest/scorecard is the key roadmap deliverable, and until it exists you should describe outputs as physics-based estimates, never as validated or AI predictions.
5. External data feeds
The ingest scheduler (src/ingest/scheduler.ts) drives all of these on independent, config-driven
intervals (config.firms.ingestIntervalMin, etc.), each cycle wrapped in try/catch so one failing
sensor never stops the schedule, and each run recorded in the ingest_cycles table for observability.
| Feed | Purpose | Cadence |
|---|---|---|
| NASA FIRMS | Satellite fire hotspots (with a mirror-URL retry on HTTP failure) | ~30 min |
| Geoscience Australia (DEA) | Australian hotspots | ~10 min |
| OpenMeteo | Weather → FFDI, wind, forecast | per request/cycle |
| OSM / Overpass (places) | “What’s around me” - refuges, fire/police stations, hospitals, fuel, water (PLACES_INGEST_ENABLED, off by default) | daily |
| Elevation (DEM) | Slope for rate-of-spread + WindNinja terrain | per prediction |
6. Deployment & cost model
Fire Path AI runs across two clouds: static surfaces (marketing, docs, the web-app shell) live on
Cloudflare and run 24/7 at effectively no cost; only the AWS API backend (ECS Fargate + RDS +
ElastiCache + ALB + NAT) has real running cost. That backend follows a hibernate/wake pattern -
it tears down to ~$0 idle and rebuilds on demand, and on boot it self-bootstraps (migrates +
seeds its own database and updates the api. DNS record) so a wake needs no manual steps.
This split - which surface is up, why the app shell still loads while the backend sleeps, the wake command, the two ECS tiers, and the Terraform module map - is documented in full in Infrastructure and Operations. This page just names the shape; those pages own the mechanics.
7. Capability status (keep this current - it is the tracked status of the codebase)
| Capability | Status |
|---|---|
| Live satellite fire mapping (FIRMS + DEA) | ✅ Built, on |
| Property/asset risk + time-to-impact (ETA) | ✅ Built, on |
| Emergency alerts + push (SMS/email fallback) | 🟠 Pipeline built + on; end-to-end device delivery (FCM) not yet proven |
| Family check-in | ✅ Built, on |
| Offline map tiles | 🟠 Logic built (pack math + manager wrappers); on-device tile download/serve not yet wired/proven |
| Physics spread + hazard cone (McArthur Mk5) | ✅ Built, on |
| Fire tracking / movement (clustering) | 🟠 Built; enabled for the current dev cycle |
| Terrain-aware wind (WindNinja worker) | 🟠 Built; deploys on the next full wake |
| Prediction accuracy (backtest/scorecard) | ⬜ Planned - the key roadmap deliverable |
| Fuel/vegetation data (per-landscape model) | ⬜ Planned (grass model applied uniformly today) |
| Historical-fire learning (the only sanctioned ML) | ⬜ Planned - after the accuracy loop exists |
8. Where the detail lives
- Repository guide - every workspace package (generated).
- API endpoints - every route + the RBAC matrix (generated).
- Data model - every table + column (generated).
- Configuration - every environment variable + feature flag (generated).
- Infrastructure - hosting topology, DNS, hibernate/wake cost model.
- Operations - wake/hibernate, DB self-bootstrap, observability, incident runbook.
- Testing - test strategy, coverage gates, the doc-drift + redaction gates.
- Task guides: where things are, run locally, verify.
Update triggers (when to revise this page + bump the date above)
Update this overview whenever any of these change: a new tier/subsystem or external feed; the prediction method or its honest-positioning caveats; the deployment/cost model; or a capability moving between built ↔ enabled ↔ planned (update the table in §7). The generated reference updates itself; this narrative does not - so this list is the discipline that keeps it true.