FIRP is an operational platform that helps conservation programs detect deforestation, verify wildfire incidents, mediate community grievances, and deliver executive-ready KPI reports. Target users:
- GIS / Remote sensing teams ingest spatial alerts into a shared queue.
- Field operators & community patrollers verify alerts on the ground (polygon drawing / fire assessment).
- Grievance focal points & project leads track complaint lifecycles and ensure SLA deadlines are respected.
- Executives (CEO/Project Lead) review monthly trends and cross-domain stats in a single dashboard.
Deliverables include alert records, verification timelines, grievance cases, and
/reportsREST endpoints feeding dashboards.
The system follows a front/back separation with shared conventions:
- Frontend (Vite + React + TypeScript + Leaflet) renders workflow screens, map interactions, and role selectors. State management uses React Query; API access goes through a shared fetch client.
- Backend (FastAPI + SQLAlchemy + PostgreSQL/PostGIS) exposes REST APIs secured by
X-User-Id, applies RBAC and workflow logic, persists geometry/timelines, and produces reporting aggregates. - Database: PostgreSQL 14+ with PostGIS handles point/polygon geometries, event timelines, and grievance state machines.
- Docker Compose orchestrates API + DB + frontend for consistent local setup.
repo/
├── app/ # Backend service
│ ├── core/ # Shared infra: database session, geometry utils, RBAC helpers, notifications
│ ├── api/ # REST routers (deforestation/fire/grievances/reports)
│ └── features/ # Domain services (grievance workflow state machine, reporting aggregates)
├── frontend/
│ ├── src/features/ # Feature-based React modules (pages + API wrappers)
│ ├── src/shared/ # Cross-cutting helpers (API client, hooks, utilities)
│ └── src/components/ # Pure UI widgets (GeoMap, StatusBadge, Timeline, etc.)
├── tests/ # API workflow/integration tests (pytest)
├── docker-compose.yml # Local orchestration for API + DB + frontend
└── README*.md # (EN/CN) contributor & AI guide
Responsibilities:
app/core: infrastructure only (e.g.db.pymanages engine/session,geo.pytranslates GeoJSON↔WKB,rbac.pyenforces role checks).app/api: HTTP layer only; should delegate heavy lifting toapp/featuresmodules.app/features: domain business logic (e.g. grievance transitions, reporting aggregates). No FastAPI imports allowed here.frontend/src/features/<domain>: each domain’s screens + domain-specific API wrapper. Avoid duplicating shared logic here.frontend/src/shared: utilities used by multiple features (API client, hooks, geometry helpers).frontend/src/components: presentation-only components (stateless if possible).
Key entities:
- User (
users) – UUID, name, email,RoleEnum. TheX-User-Idheader identifies caller for all APIs. - DeforestationAlert (
deforestation_alerts) – storespoint_geom,status,assigned_to, timestamps. Timeline events (deforestation_alert_events) capture creation, assignment, verification updates. - DeforestationVerification (
deforestation_verifications) – polygon (GeoJSON viaGeometry),hectares_lost,verifier, manager decision metadata. - FireAlert / FireVerification – similar to deforestation but includes
fire_type(enum) andis_real_fireflag; events logged infire_alert_events. - Grievance – complaint cases with
channel,current_state(state machine), deadlines (ack_due_at, etc.), andgrievance_eventstimeline. - Monthly aggregates – computed on demand (no table) from verification and grievance stats inside
app/features/reports/service.py. - Role-based workflow metadata –
RoleEnumgoverns permissions;GrievanceStatetransitions defined infeatures/grievances/workflow.py.
Data flow example:
- GIS user (role
GIS_TEAM) clicks map, enters coordinates in frontend → POST/api/deforestation/alerts/ingestwith GeoJSON point → backend savesDeforestationAlert+ALERT_CREATEDevent. - Field operator selects alert detail, draws polygon on Leaflet map, system auto-computes hectares via Turf.js → POST
/verifywith polygon (and optionalhectares_lost) → backend recordsDeforestationVerificationand event, updates alert status. - Project manager approves verification through
/verifications/{id}/approve→ backend checksensure_not_self_approve, updatesstatus, logs timeline event. - CEO hits
/api/reports/monthlyor/trends→ backend aggregates relevant tables for dashboard cards; frontend renders charts via recharts.
Dependencies:
- Node.js ≥ 18.17 + npm (frontend).
- Python ≥ 3.10 (FastAPI), pip, uvicorn.
- PostgreSQL 14+ with PostGIS extension enabled.
- Docker & docker-compose (optional but recommended for consistent env).
Configuration:
frontend/.env.local: typically onlyVITE_API_BASE(defaulthttp://localhost:8000/api).app/.envor environment variables:DATABASE_URL=postgresql+psycopg2://postgres:postgres@localhost:5432/firp.- Optionally configure
UVICORN_HOST,UVICORN_PORT,VITE_PORT.
Run locally:
# Frontend
cd frontend
npm install
npm run dev # http://localhost:5173
# Backend
cd app
pip install -r ../requirements.txt
uvicorn app.main:app --reload --port 8000
# Docker (API + DB + frontend)
docker compose up --buildCommon issues / fixes:
psycopg2.OperationalErroror PostGIS functions missing → ensure DB user can runCREATE EXTENSION postgis. When using docker-compose, base image already has PostGIS.- Ports 5173/8000 busy → stop conflicting services or change
npm run dev -- --port <new>/uvicorn --port <new>. - Node version mismatch warnings (npm 10 vs Node 18.14) → upgrade Node to ≥18.17 to avoid CLI incompatibilities.
pytestcache warnings on macOS due to permissions → create.pytest_cacheor run tests withPYTEST_DISABLE_PLUGIN_AUTOLOAD=1if needed.
All endpoints are REST/JSON. Every request must include X-User-Id: <UUID> representing the caller’s role.
-
Create deforestation alert –
POST /api/deforestation/alerts/ingestRequest:{ "point": { "type": "Point", "coordinates": [101.7123, -0.1234] } }Response:
{ "id": "d5bd5bb5-eafd-42fc-a2c4-c65e71384589" } -
Submit deforestation verification –
POST /api/deforestation/alerts/{alertId}/verify{ "area_polygon": { "type": "Polygon", "coordinates": [[[101.71,-0.12],[101.72,-0.12],[101.72,-0.11],[101.71,-0.11],[101.71,-0.12]]] } }(If manual hectares input is preferred, send
{"hectares_lost": 2.5}instead.) Response returns verification metadata. -
Submit fire verification –
POST /api/fire/alerts/{alertId}/verify{ "is_real_fire": true, "fire_type": "GROUND_FIRE" } -
Grievance update –
POST /api/grievances/{id}/advance{ "to_state": "UNDER_INVESTIGATION", "notes": "Reached complainant" } -
Monthly report –
GET /api/reports/monthly?year=2024&month=11{ "period": {"year": 2024, "month": 11}, "deforestation": {"approved_count": 12, "hectares_lost_sum": 34.8}, "fire": {"approved_real_fire_count": 4}, "grievances": {"received_in_month": 6, "closed_in_month": 5, "open_now": 11} }
No WebSocket/gRPC currently; all communication is HTTPS JSON.
- Naming: Python modules/vars →
snake_case; SQLAlchemy models →PascalCase; React components →PascalCase; hooks →useCamelCase; directories →kebab-caseorlowercasedepending on context. - Imports: Absolute imports only. Backend must use
app.<module>(neverfrom ..models import ...). Frontend must use@/alias defined intsconfig.json/vite.config.ts. - Style tools: Python uses type hints everywhere and formatting via
ruff+black; frontend linting via ESLint + Prettier (tsconfig already strict). Keep React Query keys descriptive arrays (e.g.,['deforestation-alerts', userId, filter]). - Protected assets: Do not edit
docker-compose.yml,.envdefaults, seed UUIDs inapp/seed.py, or future Alembic migrations unless explicitly instructed. Avoid heavy dependencies insideapp/coreorfrontend/src/shared; domain-specific packages belong to feature directories. - Performance: Avoid synchronous heavy work inside request handlers or map rendering loops. For large operations, consider background tasks/webhooks (future roadmap).
Current status:
- Deforestation workflow with polygon drawing + auto-hectares (frontend) and area validation (backend).
- Fire alert verification + manager approval.
- Grievance lifecycle with deadlines and role-based transitions.
- CEO reports (monthly/trend/breakdown) feeding dashboards.
- Absolute import policy on backend enforced across modules.
Roadmap / TODO:
- Implement real authentication (JWT/OAuth) and retire the
X-User-Idmock header. - Notification delivery: fill out
app/core/notifications.py(email/webhook) and connect to events. - Automated tests: add frontend component tests + backend integration tests with fixtures.
- Pagination & clustering for alerts to handle higher volumes gracefully.
- Add schema migration tooling (Alembic) to avoid rebuilds when models change.
Known issues / tech debt:
pytestwarns about cache creation on macOS due to permissions; create.pytest_cacheif necessary.- React production bundle > 500 kB (Leaflet + recharts); consider code splitting/lazy imports.
- No background tasks; approvals and notifications are synchronous.
- Deforestation verification still allows manual hectare override; align with policy if needed.