$ cd projects/jansamadhan
$ cd projects/jansamadhan/postmortem
RFC-088: ENGINEERING POST-MORTEMPUBLISHED: MARCH 2026

Post-Mortem: JanSamadhan

FastAPIPostGISGemini AISupabaseRedisDocker
// summary (tldr)

Built an AI civic grievance system deployed as a ward pilot in Delhi. 300+ citizens, 200+ tickets. Won the national grand finale of Indian Innovates '26.

01.

the problem

Civic grievance portals in India are notoriously slow, confusing, and siloed. Citizens file complaints, but they get stuck in manual routing queues for weeks because municipal workers have to read, categorize, and identify who owns which street, zone, or ward. Duplicate reports (e.g. 5 people reporting the same pothole) clog the database. The system needed automated, geo-aware, instant categorization and routing to local authorities.
02.

what i built

I built the entire backend pipeline for JanSamadhan. A FastAPI service that ingests civic grievances via WhatsApp Cloud API webhook callbacks. It extracts image data (which is classified using Gemini AI JSON mode to assess damage type and severity) and geospatial coordinates. The complaint is then query-deduplicated against existing local reports and auto-routed to one of 10+ government departments using geospatial bounds.
03.

key decisions

#

04.

why FastAPI over Django

I needed maximum async throughput and minimal memory footprint. The WhatsApp webhook callbacks hit the server in sudden bursts during peak hours (handling 4K to 8K requests per day). Django’s sync overhead and blockages on database sockets would require heavy scaling infrastructure. FastAPI’s native ASGI loop allowed us to ingest callbacks instantly and handle background classification workers out-of-the-box. #
05.

why PostGIS over standard Postgres

Grievance duplicate detection is a spatial query problem. I had to prevent ticket duplication when multiple citizens report the same issue in a neighborhood. Standard PostgreSQL has no concept of spherical distance calculations on indices. I adopted PostGIS and configured spatial indexing (`GIST`) using an `ST_DWithin` query to search complaints within a dynamic threshold radius (e.g., 50 meters) in under 15ms.
06.

what broke

// System Failure & Lesson

Incident Log & Outage Analysis

During the initial deployment, the WhatsApp Cloud API webhook retried failed callbacks aggressively if the server didn't respond within 5 seconds. Since our Gemini image parsing pipeline took 2-3 seconds, a cold start on serverless API routes caused timeouts. Webhooks retried, sparking a loop that duplicated database records. I resolved this by splitting the ingestion: we now reply `200 OK` instantly, push the payload to a Redis queue, and process the AI classification asynchronously.
07.

what i'd do differently

If I built it again from scratch, I would write a custom edge middleware in Go to handle the ingestion validation and throttling before it ever touches the main FastAPI server, reducing server load. I would also cache geospatial boundary checks locally in Redis instead of hitting PostGIS for static administrative ward checks.
08.

what i learned

- Serverless architectures are great until you hit external webhook latency constraints. Background queues are not optional. - PostGIS indices are incredibly powerful but require strict coordinate order validation (longitude first, then latitude) to avoid silent failures in routing calculations. - government operations move slowly, but simple, direct tools that solve immediate pain points (like manual routing) win adoption fast.