HazardSignal is the public and operational deployment of the fire-risk platform.rnrnThis repository now contains two layers of the platform:
GEE.js: the research and training workflow in Google Earth Engineproduction/GEE_operational_app.js: the Earth Engine operational app scriptapps/web: the public-facing Next.js dashboardservices/worker: the Node.js daily worker and Telegram alert enginesupabase/schema.sql: the relational schema for production storagedata/mock: local mock operational data used before real credentials are wired
The original GEE.js remains the source-of-truth ML workflow:
- dynamic feature engineering
- fire labeling
- RF + Gradient Tree Boost training
- model comparison and threshold selection
- fire-risk probability, binary, and class maps
- reporting exports
The new product layer adds:
- a Next.js dashboard with map, district pages, alerts page, and admin page
- API endpoints for latest run, district summaries, active fires, alerts, and map config
- admin endpoints for test alerts, subscribers, and alert rules
- a Node worker for daily inference orchestration and Telegram alerts
- a production Earth Engine app script for daily asset visualization
- a Supabase schema for the long-term production backend
- Earth Engine App for public map presentation
- Daily worker for district summaries and Telegram alerts
- Admin audience for alerts
- Local JSON mock storage in
data/mock
- Next.js public web app
- Cloud Run worker
- Cloud Scheduler daily trigger
- Supabase persistence
- Telegram bot integration
The web app exposes these routes:
GET /api/latest-runGET /api/districts/latestGET /api/districts/:districtId/historyGET /api/alerts/recentGET /api/fires/latestGET /api/map-config/latestPOST /api/admin/alerts/testPOST /api/admin/subscribersPATCH /api/admin/alert-rules
The worker exposes:
GET /healthPOST /run-exportPOST /run-dailyPOST /run-pipeline
The worker can also be started directly from the CLI:
npm run run:exportnpm run run:export -- --date=2026-03-10npm run run:workernpm run run:worker -- --date=2026-03-10npm run run:worker -- --date=2026-03-10 --export-first
- Install dependencies:
npm install
- Start the dashboard:
npm run dev:web
- Start the worker:
npm run start:worker
- Trigger a daily run:
npm run run:worker
- Run the worker tests:
npm run test:worker
Copy .env.example to .env and set:
NEXT_PUBLIC_BASE_URLNEXT_PUBLIC_EE_APP_URLWORKER_PORTWORKER_USE_MOCK_EEWORKER_EXPORT_BEFORE_RUNTELEGRAM_BOT_TOKENTELEGRAM_DEFAULT_CHAT_IDSUPABASE_URLSUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEY
If SUPABASE_URL and a valid key are present, the web app and worker switch automatically from
data/mock to Supabase-backed storage.
- Create a Supabase project.
- Open the SQL editor and run
supabase/schema.sql. - Put these values into
.env:SUPABASE_URLSUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEY
- Seed the database from the current mock data:
npm run seed:supabase
- Restart the web app and worker:
npm run dev:webnpm run start:worker
- If you want the worker to keep using mock Earth Engine inference while storing to Supabase:
- keep
WORKER_USE_MOCK_EE=true
- keep
At that point:
- the dashboard reads from Supabase
/adminwrites subscribers, alert rules, and test alerts to Supabase- the worker writes runs, district summaries, active fires, and alert events to Supabase
The current repo is intentionally honest about operational boundaries:
- the research model stays in
GEE.js - the public app does not retrain models
- the worker supports mock mode and real Earth Engine asset ingestion mode
- the Earth Engine operational app expects exported raster asset IDs to be configured
This means the system is implementable now, demoable now, and ready for real credentials and asset promotion without changing the overall design.
- Publish the Earth Engine operational app and replace placeholder asset IDs.
- Connect the worker from mock JSON storage to Supabase.
- Add real Telegram credentials and validate message delivery.
- Configure Earth Engine service-account ingestion by setting:
WORKER_USE_MOCK_EE=falseEE_SERVICE_ACCOUNT_KEY_PATHEE_ASSET_ROOTEE_ASSET_NAME_PREFIXEE_CLASSIFIER_ASSET_ID
- Deploy
apps/webandservices/worker.
When WORKER_USE_MOCK_EE=false, the worker no longer reads data/mock for operational inference.
Instead it:
- authenticates to Earth Engine using a service-account JSON key
- loads exported raster assets from
EE_ASSET_ROOT - can fall back to the latest complete asset set on or before the requested date when
EE_ASSET_DATE_POLICY=latest_available - computes district summaries for the configured region
- reads last-24h FIRMS detections
- writes runs, district risk, active fires, and alerts to Supabase
Required env vars:
EE_SERVICE_ACCOUNT_KEY_PATHEE_ASSET_ROOTEE_ASSET_NAME_PREFIXEE_CLASSIFIER_ASSET_IDEE_ASSET_DATE_POLICYEE_MAX_ASSET_AGE_DAYSEE_REGION_COUNTRYEE_REGION_LEVEL1EE_SELECTED_MODELEE_SELECTED_THRESHOLD
Recommended production flow:
- Export an approved classifier asset from
GEE.jsand setEE_CLASSIFIER_ASSET_ID. - Ensure the service account has access to the Earth Engine project/assets.
- Set
WORKER_USE_MOCK_EE=false. - Run the daily export+ingestion pipeline:
./scripts/run-daily-pipeline.sh YYYY-MM-DD
- For API-based execution:
POST /run-pipeline?date=YYYY-MM-DD
- Keep
EE_ASSET_DATE_POLICY=latest_availableonly for standalone ingestion mode (run-dailywithout export).
Production domain:
Recommended public routing:
- / -> Next.js web app on 127.0.0.1:3000`r
- /worker/health -> worker API on 127.0.0.1:8080/health`r
An Nginx site config is included at:
- deploy/nginx/hazardsignal.com.conf`r
After copying it to Ubuntu:
- sudo mkdir -p /var/www/certbot`r
- sudo cp deploy/nginx/hazardsignal.com.conf /etc/nginx/sites-available/hazardsignal.com.conf`r
- sudo ln -sf /etc/nginx/sites-available/hazardsignal.com.conf /etc/nginx/sites-enabled/hazardsignal.com.conf`r
- sudo nginx -t`r
- sudo systemctl reload nginx`r
- sudo certbot --nginx -d hazardsignal.com -d www.hazardsignal.com`r
For a stable Ubuntu deployment:
- use
Node.js 20+ - enable
fire-risk-web.service - enable
fire-risk-worker.service - enable
fire-risk-daily-run.timer
Useful checks:
./scripts/healthcheck.sh./scripts/verify-systemd.sh