Inspiration
Every city has the same invisible problem: the pothole everyone drives around, the streetlight that's been dead for months, the garbage pile that keeps growing. It's not that nobody cares — it's that reporting it feels like shouting into a void. Municipal helplines are slow, complaints disappear into inboxes, and nobody ever finds out what happened. I wanted to build the shortest possible path between "I see a problem" and "it's being fixed" — and make the whole journey public, so accountability comes for free.
What it does
CivicLens is a community issue-reporting platform with an AI triage engine.
30-second reporting — snap a photo, drop a pin (or use your location), write one sentence; the report is live instantly.
AI triage — every report is automatically classified into a civic category (roads, streetlights, waste, water, parks, safety), scored for severity (1–5) with a written rationale, routed to the correct city department, and checked against nearby recent reports so duplicates from neighbors get merged instead of cluttering the queue.
Public accountability map — every report appears on a live map with its status: reported → acknowledged → in progress → resolved; anyone can follow the timeline of a fix.
Priority scoring — reports earn a public priority score from severity, community upvotes ("I see this too"), recency, and category urgency, so the most important problems surface first.
Civic dashboard — city-wide stats: resolution rates, average days to fix, breakdowns by category and department, and the most-reported areas.
How I built it
Frontend: Next.js 14 (App Router, TypeScript) + Tailwind CSS, statically exported and hosted on Vercel — mobile-first, because reports happen on phones, on the street.
Backend: Express + TypeScript REST API, PostgreSQL hosted on Render.
AI pipeline: an LLM (via FastRouter) classifies, scores, and routes each report as structured JSON, with a transparent keyword-based fallback classifier so the app never breaks when the key isn't configured.
Duplicate detection blends geo-proximity (Haversine) with text similarity (Jaccard).
Images: direct browser uploads to Cloudinary (unsigned preset) — no server round-trip for photos.
Maps & geocoding: Leaflet + OpenStreetMap, reverse-geocoding via Nominatim — zero API keys.
Challenges
The hardest part was making the AI triage trustworthy: an LLM that returns free text is useless for a work queue, so I constrained it to strict JSON with fixed categories/departments and built a deterministic fallback so a failed API call degrades gracefully instead of breaking the report flow.
Duplicate detection was the second challenge — two neighbors photographing the same pothole from different angles should become one ticket, which needed both geo and text signals tuned together.
What's next
Department staff logins with a real work queue, SMS/status notifications for reporters, multilingual reporting, and a 311-style phone integration for residents without smartphones.
The live demo ships with clearly-labeled sample reports around Austin, TX so the map is explorable immediately; every one of them carries a "Sample" badge. Everything else — reporting, AI triage, upvotes, status workflow, dashboard — is fully live.
Built With
- cloudinary
- express.js
- fastrouter
- leaflet.js
- next.js
- openstreetmap
- postgresql
- tailwindcss
- typescript
Log in or sign up for Devpost to join the conversation.