HydroSentinel is a solo student project for monitoring South African water service performance, surfacing citizen issue reports, and scoring municipal risk using a lightweight XGBoost model.
- Frontend: React 18, TypeScript, Vite, Tailwind CSS, shadcn/ui, Leaflet, axios
- Backend: FastAPI, SQLAlchemy, PostgreSQL, JWT auth, passlib
- Data and AI: pandas, pdfplumber, scikit-learn, XGBoost, joblib
- Local infrastructure: Docker Compose
hydrosentinel/
├── backend/
├── frontend/
├── docker-compose.yml
├── .env.example
└── README.md
git clone <your-repo-url> hydrosentinel
cd hydrosentinel
cp .env.example .envUpdate .env if you want different database credentials, a different JWT secret, or a custom seeded admin account.
docker compose up --buildThis starts:
- Frontend on http://localhost:5173
- Backend on http://localhost:8000
- Swagger docs on http://localhost:8000/docs
On first backend startup, the app creates the tables, seeds a default admin account, and inserts 144 starter WSA rows if the database is empty.
If you created the database with the SQL script you shared, use that existing admin record:
Email: admin@hydrosentinel.co.za
Password: the password that matches your inserted bcrypt hash
If you let the FastAPI app seed a fresh admin user instead, it uses ADMIN_EMAIL and ADMIN_PASSWORD from .env.
Place Blue Drop and No Drop PDFs inside backend/data/raw/, then run:
docker compose exec backend python etl/run_etl.pyThe ETL parses available source files, merges the extracted data, and upserts WSA records into PostgreSQL.
The risk route expects a serialized model at backend/ai/model.pkl. Train and save one manually when you have labelled data:
docker compose exec backend python ai/train.py data/training/wsa_training.csvIf model.pkl is missing, the API falls back to a deterministic starter heuristic so the demo still works.
docker compose exec backend python -m pip list
docker compose exec backend python etl/run_etl.py
docker compose exec backend python ai/train.py data/training/wsa_training.csv
docker compose downGET /wsareturns all WSAsGET /wsa/{id}returns one WSAPATCH /wsa/{id}updates CAP status for adminsPOST /reportscreates a citizen reportGET /reportslists reports for adminsPOST /risk/score/{wsa_id}scores a WSA and writes the risk level backGET /risk/scoreslists current risk scoresPOST /auth/loginreturns a JWTGET /auth/mereturns the current user