PotholeGuard is a full-stack computer vision platform for detecting potholes in road images. The backend exposes a FastAPI API for authentication, image inference, detections, analytics, and geospatial export. The frontend is a React + TypeScript dashboard for authentication, scanning, map views, registry management, and operational monitoring.
The ML inference engine uses a fine-tuned YOLOv8 small model exported to ONNX and executed with onnxruntime. The project persists users, towns, streets, uploaded images, and detections in PostgreSQL.

- Problem solved: detect potholes from road images and persist structured detection records.
- Inference engine: YOLOv8s fine-tuned for pothole detection and exported to ONNX.
- Backend language: Python.
- Frontend language: TypeScript.
- Backend framework: FastAPI.
- Database: PostgreSQL.
- Deployment style: Docker Compose for API + database.
- Frontend tooling: React, Vite, Tailwind CSS, Axios, Recharts, Leaflet.
- Python 3.12
- FastAPI
- SQLAlchemy
- Alembic
- PostgreSQL
- OpenCV
- ONNX Runtime
- Pydantic
- JWT auth with
python-jose
- TypeScript
- React 18
- Vite
- React Router
- Axios
- Tailwind CSS
- Recharts
- Leaflet / React Leaflet
- React Dropzone
The system is split into four main layers:
-
Frontend UI The React application handles login, dashboard analytics, image upload for inference, registry views, and map-based visualization.
-
API Layer FastAPI routers define authentication, CRUD operations, inference endpoints, analytics endpoints, and geospatial detection exports.
-
Service Layer Backend services encapsulate inference logic, detection retrieval, analytics queries, and CRUD logic for relational entities.
-
Persistence Layer PostgreSQL stores users, towns, streets, images, and detections. Images and annotated outputs are stored on disk.
The project currently revolves around five main relational entities:
-
UserStores authentication and authorization data, includingis_activeandis_admin. -
TownRepresents municipalities or cities. -
StreetBelongs to a town and stores segment and geographic endpoint metadata. -
ImageRepresents an uploaded image processed by the model. It links to the uploading user, street, and town. -
DetectionStores pothole count, confidence summary, model version, inference time, coordinates, and raw detection JSON.
- The authenticated user uploads an image through the frontend scanner.
- The backend validates the file and selected street.
- The image is decoded with OpenCV.
- The ONNX model runs inference with
onnxruntime. - Bounding boxes are post-processed with NMS.
- The original image is stored on disk.
- The annotated image is saved to
app/storage/outputs. - An
Imagerow is inserted into PostgreSQL. - A linked
Detectionrow is inserted into PostgreSQL. - The API returns the annotated image URL and structured detection output.
- Auth uses JWT bearer tokens.
- Regular users can only access their own images and detections.
- Admin users can access all detections and all images.
- Soft delete is implemented with
is_active = false. - Inactive users are blocked from authenticated actions.
- Admin-only routes are enforced in both backend logic and frontend routing.
Key backend folders:
app/api/routersFastAPI route handlers.app/coreConfiguration, database bootstrap, security, and logging.app/modelsSQLAlchemy ORM models.app/schemasPydantic request/response schemas.app/servicesQuery and business logic.app/utilsHelper modules for image processing, geo estimation, and related utilities.alembicDatabase migration environment and revision history.
Key frontend folders:
frontend/src/pagesView-level pages such as login, dashboard, scanner, map, and registry.frontend/src/componentsShared UI building blocks such as layout, sidebar, protected route, header, and footer.frontend/src/contextGlobal auth context.frontend/src/servicesAxios API clients for auth, users, analytics, detections, towns, streets, and images.frontend/src/hooksReusable hooks such asuseAuth.
potholed/
├── alembic/
│ ├── env.py
│ └── versions/
├── app/
│ ├── api/
│ │ └── routers/
│ ├── core/
│ ├── models/
│ ├── schemas/
│ ├── services/
│ ├── storage/
│ │ ├── originals/
│ │ └── outputs/
│ └── utils/
├── frontend/
│ ├── publics/
│ ├── src/
│ │ ├── components/
│ │ ├── context/
│ │ ├── hooks/
│ │ ├── pages/
│ │ └── services/
│ └── package.json
├── ml/
├── pictures/
├── scripts/
├── tests/
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── README.md
The project uses two containers:
potholeguardFastAPI backend container.potholeguard_dbPostgreSQL 16 database container.
The compose file does the following:
- builds the backend service from the repository root
- runs FastAPI with
uvicorn app.main:app --reload - exposes backend API on
localhost:8000 - exposes PostgreSQL on host port
5433 - mounts the repository into the backend container for hot reload
- bind-mounts
./app/storage/outputsso annotated images are visible on the host filesystem - persists PostgreSQL data using the
postgres_datavolume
docker compose up -d --builddocker compose downSwagger UI is available at:
http://localhost:8000/docs
POST /auth/registerRegister a new user.POST /auth/loginAuthenticate a user and return a JWT token.
GET /users/mePUT /users/mePATCH /users/meDELETE /users/me- Admin endpoints for lookup, creation, update, and deletion of users are also available under
/users.
GET /towns/POST /towns/GET /towns/{town_id}PUT /towns/{town_id}DELETE /towns/{town_id}
GET /streets/POST /streets/GET /streets/{street_id}PUT /streets/{street_id}DELETE /streets/{street_id}
GET /images/GET /images/{image_id}PUT /images/{image_id}DELETE /images/{image_id}
POST /detections/predictUpload image, run ONNX inference, persist image and detection.GET /detections/Admins can view all; regular users only see their own detections.GET /detections/{detection_id}DELETE /detections/{detection_id}GET /detections/street/{street_id}/geojsonGET /detections/town/{town_id}/geojson
GET /analytics/GET /analytics/dashboard/GET /analytics/top-affected-streetsGET /analytics/towns-distributionGET /analytics/model-performanceGET /analytics/user-activityGET /analytics/last-activity
The frontend is a Vite + React + TypeScript application that consumes the backend API through Axios.
LoginJWT authentication and session bootstrap.DashboardOperational summary and analytics.YoloScannerImage upload, street selection, inference execution, and annotated result view.IntelMapMap-oriented detection view.DataRegistryRegistry management for towns and streets with admin-only controls.
The frontend uses:
- public routes for authentication pages
ProtectedRoutefor authenticated areasLayoutas the master shell for dashboard and operational modules- an admin-only route gate for the admin console
PostgreSQL stores all relational entities and is the source of truth for:
- users
- towns
- streets
- uploaded images
- detection results
From the host machine:
localhost:5433
Inside Docker Compose:
db:5432
The backend stores:
- original uploaded images in
app/storage/originals - annotated output images in
app/storage/outputs
Because app/storage/outputs is bind-mounted in Docker Compose, annotated files remain available on the host machine even if containers are recreated.
cd frontend
npm install
npm run devDefault dev server:
http://localhost:3000
If you want to run the API outside Docker:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reloadYou must also provide a valid .env file with database and JWT configuration.
tests/Automated backend tests.scripts/test_detection_endpoint.pyEnd-to-end test for the detection endpoint.scripts/check_onnx.pyQuick ONNX model inspection utility.
The backend includes a colorized CLI logging bootstrap in:
app/core/logging.py
It is initialized from:
app/main.py
The logger supports readable colored output for DEBUG, INFO, WARNING, ERROR, and CRITICAL levels.
Frontend release target:
v1.0.0
This repository represents the first integrated full-stack version of PotholeGuard, including authentication, detection inference, analytics, image persistence, and operational frontend views.
- The training notebook used in Google Colab is not stored in the repository.
- The ONNX model artifact is stored under
ml/. - Some future pages are scaffolded and can be expanded as the product evolves.