SAHA-Care
Community-based disease surveillance for conflict-affected regions.
Offline-first. Role-based. Open-source.
Overview
SAHA-Care is an offline-first, community-based disease surveillance (CBS) progressive web app designed for infectious disease detection and reporting in conflict-affected, resource-constrained environments. Its initial implementation context is the Gaza Strip, where existing health surveillance infrastructure has collapsed under ongoing conflict and displacement.
Community health workers and displaced individuals can report standardized case definitions even during connectivity blackouts. Reports are stored locally via Firestore's offline cache and automatically sync when connectivity resumes. Verified data is aggregated into dashboards with maps, charts, and automated outbreak alerts.
One app serves three roles: Volunteers submit reports, Supervisors verify and approve, Officials monitor outbreaks via dashboards.
The Problem
| Challenge | Impact |
|---|---|
| Infrastructure collapse | Surveillance systems go dark precisely when disease risk is highest |
| Mass displacement | Hard-to-reach populations are invisible to traditional systems |
| Connectivity blackouts | Internet-dependent apps fail in the field |
| Fragmented reporting | No standardized case definitions across humanitarian actors |
| Community distrust | Top-down systems exclude local knowledge and agency |
Core Features
- Offline-first data collection — Firestore offline cache + service worker. Reports sync on reconnect.
- Standardized case definitions — WHO-aligned symptom checklists for priority diseases.
- Role-based access — Volunteer (reporting), Supervisor (verification + maps), Official (dashboard + alerts).
- Supervisor verification — Review, verify/reject reports, view locations on map, approve volunteers.
- Dashboard & maps — KPI cards, Recharts charts, Leaflet map with clustered markers.
- Automated alerts — Cloud Functions detect when case counts exceed thresholds per disease/region.
- Installable PWA — "Add to Home Screen" on Android Chrome, behaves like a native app.
System Architecture
The system is a React PWA served via Firebase Hosting. All data flows through Firestore with automatic offline caching. Three Cloud Functions handle server-side logic triggered by Firestore document writes.
graph TD
subgraph Client ["Client (Browser)"]
PWA["React PWA<br/>(Vite + TypeScript)"]
SW["Service Worker<br/>(Vite PWA Plugin)"]
Cache["Firestore<br/>Offline Cache"]
UI["MUI + Leaflet + Recharts"]
Ctx["React Context<br/>(AuthContext)"]
Hooks["Custom Hooks<br/>(useReports, useAlerts)"]
PWA --- UI
PWA --- Ctx
PWA --- Hooks
PWA --- SW
PWA --- Cache
end
subgraph Views ["Role-Based Views"]
V["Volunteer<br/>Submit Reports"]
S["Supervisor<br/>Verify, Approve, Maps & Charts"]
O["Official<br/>Dashboard, Maps & Charts"]
end
subgraph Firebase ["Firebase"]
Hosting["Firebase Hosting<br/>(CDN + SSL)"]
Auth["Firebase Auth<br/>(Email/Password + Custom Claims)"]
Firestore[("Firestore DB")]
subgraph Functions ["Cloud Functions"]
F1["onUserApproval<br/><i>users/uid onUpdate</i>"]
F2["onReportWrite<br/><i>reports/id onCreate</i>"]
F3["aggregateCases<br/><i>reports/id onWrite</i>"]
end
end
subgraph Collections ["Firestore Collections"]
users["users"]
reports["reports"]
caseDefs["caseDefinitions"]
alerts["alerts"]
aggregates["aggregates"]
end
Hosting -->|serves| PWA
PWA -->|authenticates| Auth
Cache <-->|"auto-sync<br/>(online)"| Firestore
PWA --> Views
Firestore -->|triggers| F1
Firestore -->|triggers| F2
Firestore -->|triggers| F3
F1 -->|validates & writes| users
F2 -->|creates| alerts
F3 -->|updates| aggregates
Firestore --- Collections
Cloud Functions
Server-side logic triggered by Firestore writes — no HTTP endpoints needed.
| Function | Trigger | Purpose |
|---|---|---|
onUserApproval |
users/{uid} onUpdate |
Validates role escalation, enforces region scoping |
onReportWrite |
reports/{id} onCreate |
Checks thresholds per disease/region, auto-creates alerts |
aggregateCases |
reports/{id} onWrite |
Maintains pre-computed rollups for dashboard performance |
Data Model
erDiagram
users {
string uid PK
string email
string displayName
string role "volunteer | supervisor | official"
string status "pending | approved"
string supervisorId FK "references users.uid"
string region
timestamp createdAt
timestamp updatedAt
}
reports {
string id PK
string disease FK "references caseDefinitions.disease"
array symptoms
float temp
float lat
float lng
string locationName
string status "pending | verified | rejected"
string reporterId FK "references users.uid"
string verifiedBy FK "references users.uid"
string region
timestamp createdAt
timestamp verifiedAt
}
caseDefinitions {
string id PK
string disease UK
json symptoms "symptom checklist"
array dangerSigns
string guidance
boolean active
int threshold "alert threshold per region"
}
alerts {
string id PK
string disease FK "references caseDefinitions.disease"
string region
int caseCount
int threshold
string severity "low | medium | high | critical"
string status "active | resolved"
timestamp createdAt
timestamp resolvedAt
}
aggregates {
string id PK "disease_region_period"
string disease FK "references caseDefinitions.disease"
string region
string period "day | week"
int caseCount
int verifiedCount
timestamp lastUpdated
}
users ||--o{ reports : "submits (reporterId)"
users ||--o{ reports : "verifies (verifiedBy)"
users ||--o{ users : "supervises (supervisorId)"
caseDefinitions ||--o{ reports : "defines disease"
caseDefinitions ||--o{ alerts : "triggers for disease"
caseDefinitions ||--o{ aggregates : "aggregated by disease"
Tech Stack
| Layer | Technology |
|---|---|
| Framework | React + Vite + TypeScript (PWA) |
| UI | Material UI (MUI) |
| Maps | Leaflet + OpenStreetMap |
| Charts | Recharts |
| State | React Context + Firestore onSnapshot listeners |
| Database | Firestore (NoSQL, offline sync, real-time, security rules) |
| Auth | Firebase Auth (email/password, custom claims for roles) |
| Server-side | Cloud Functions (Node.js/TypeScript) — 3 Firestore-triggered functions |
| Hosting | Firebase Hosting (CDN + SSL) |
| Offline | Firestore offline cache + Vite PWA plugin (service worker) |
| CI/CD | GitHub Actions → Firebase Hosting |
Implementation Plan
Solo developer using AI agents, class project (CS 584), ~7.5 weeks in 4 sprints (~13 days each). Single offline-first PWA for disease surveillance in conflict zones — one app serves all roles.
Sprint 1 — Auth & Offline Reporting
Feb 24 – Mar 8Goal: Volunteer can register, log in, and submit offline case reports.
- React + Vite + TypeScript project scaffold with PWA plugin
- Firebase project setup (Firestore, Auth, Hosting)
- Firestore schema + security rules
- Auth: email/password, role selection, pending approval state, custom claims
- Case report form (disease, symptoms, temp, location) with WHO-aligned case definitions
- GPS auto-capture + manual location fallback
- Offline persistence via Firestore cache + service worker
Sprint 2 — Verification & Approval
Mar 9 – Mar 21Goal: Supervisors review and verify reports; approval hierarchy works.
- User approval flow (supervisors approve volunteers, officials approve supervisors)
- Supervisor report review screen with map view (Leaflet)
- Verification actions: verify / reject (status state machine)
- Region-scoped views (supervisors see only their region)
- In-app notification badges for report status changes
Sprint 3 — Dashboard & Maps
Mar 22 – Apr 3Goal: Officials and supervisors monitor outbreaks via charts and maps.
- Official dashboard: KPI cards, Recharts charts (case counts by disease, trends over time)
- Supervisor regional chart view
- Leaflet map: report markers, clustering, color-coded by disease, click-to-drill-down
- Filtering: disease, date range, region, verification status
- Role-based scoping (official = all regions, supervisor = their region)
Sprint 4 — Alerts, Cloud Functions, Polish & Demo
Apr 4 – Apr 16Goal: Server-side logic, alert system, security audit, demo-ready product.
- Cloud Functions setup:
functions/directory, TypeScript config, deploy pipeline - Deploy
onUserApproval: server-side approval validation - Deploy
onReportWrite: threshold detection, auto-create alerts - Deploy
aggregateCases: pre-computed rollups for dashboard - Alert threshold configuration + alerts surface on dashboard
- Firestore security rules audit
- UI polish: loading states, error handling, responsive design
- Seed data for realistic demo + testing