
A civic complaint starts with something concrete: a broken streetlight, an overflowing bin, a place someone can point to. Getting from that observation to the right ward, a useful letter and a record of what happened can be a surprisingly fragmented process.
MeraWard connects those steps. It was built by our three-person team, Sleepy peeps, for First Commit / Bharat Builds Tour. My work is concentrated in the Python backend handlers, geospatial lookup, Ward Neglect Index, shared SAM integration and verification.
The location is a query, not just a pin
The user can provide text, a photo and browser-supported speech input, then confirm the location and ward before submitting. On the backend, finding that ward means asking which polygon contains the coordinate.
The implementation loads ward geometry and a Shapely STRtree inside the Lambda process. The tree narrows candidates through bounding boxes; point-in-polygon tests then choose the match, with deterministic handling at a shared boundary. The geometry and index can be reused after a cold start instead of rebuilding them for every lookup.
For this dataset, that avoids requiring a separate search cluster simply to locate a point in a collection of polygons. The data still sets the limit of the answer: the bundled boundaries are historical, pre-2022 geometry, not a verified current Delhi ward map.
Submission is the beginning of a workflow
Intake validates the details and resolves the ward again on the server. It writes the complaint before enqueueing the drafting task, so a fast worker cannot receive a message for a record that does not exist yet. SQS separates the intake response from letter composition.

The default drafting path uses deterministic English and Hindi templates. An optional Bedrock adapter is not the default behavior. A Hindi letter containing the reporter’s original description is not a promise that an English description has been translated accurately.
The current maintained demo deliberately keeps delivery in an outbox and refuses real official recipients. That lets the workflow be inspected without confusing a demonstration with an operating municipal channel.
Seeing a report is different from changing it
A public tracking record shows a controlled set of fields. Reporter email and the private update capability stay out of that response. A separate capability authorizes acknowledge, resolve and reopen actions.
Reopening deserves to be a real event. It appends to the timeline and clears the resolved state, rather than deleting the earlier resolution and pretending it never happened. Conditional writes also stop a stale request from silently replacing a concurrent status change.
Silence should not look like a perfect score
The Ward Neglect Index is another place where a seemingly small display choice changes the meaning of the product. Fewer than five reports produces an unranked, unknown value, not a reassuring zero. A ward with no resolved reports has unknown resolution speed; the other weights redistribute rather than inventing an ideal resolution time.
The calculation combines backlog rate, capped age of open reports and, when available, resolution delay. It uses fixed anchors rather than scaling every ward against the current city maximum. One extreme outlier should not make everybody else appear artificially healthy.
This is a description of the report history the application holds. It is not a measure of a named official’s competence, and synthetic demo data cannot establish real-world service quality.
Three people, connected responsibilities
Amrit Kang led the team and worked on the frontend, ward data and submission. Kartik Dixit worked on AWS infrastructure, the original deployment and intake improvements. My backend work connects the geometry, state transitions and index; infrastructure integration is shared work.
The system combines React, API Gateway, Python Lambda, DynamoDB, S3 uploads, SQS and scheduled aggregation, defined with AWS SAM. Local emulation exercises the same handlers and real geometry, while keeping the limits of an emulator separate from production AWS permissions.
The result is a demonstrable civic workflow whose most important decisions happen between the screens: which location is being described, what the reporter approved, who may change the status, and when the evidence is too thin to give a score.
Code & further reading
- Source / github.com/amritkang165/meraward ↗
- github.com/amritkang165/meraward/blob/main/CREDITS.md ↗
- github.com/amritkang165/meraward/blob/main/backend/src/common/wards.py ↗
- github.com/amritkang165/meraward/blob/main/docs/DECISIONS.md ↗
Written by Muneer Alam · Reviewed 1 November 2026