← All work
Live in prod

CivicFix

Public complaint tracking for roads and water. Duplicate reports collapse into one ticket, and missed SLAs escalate automatically.

The problem

A pothole on your street gets reported five times on five WhatsApp groups and zero times to anyone who can fix it. When it does reach someone, nobody can tell whether it’s been seen, merged with the other four reports, or forgotten.

What I built

CivicFix is a public complaint tracker. A citizen drops a pin, attaches a photo and picks a category — road, water, drainage. Everyone can see every open complaint on the explore page.

Two decisions shape the whole system:

  • Duplicates collapse. A new report close to an existing open ticket of the same category is merged into that master ticket instead of creating a new one. Five reports become one ticket with five votes, which is a better signal for whoever has to prioritise.
  • Silence escalates. Each category has an SLA between 24 and 72 hours. A background job checks open tickets and escalates any that miss it, so a complaint can’t quietly die.

How it runs

It runs on a single EC2 instance with Docker Compose — FastAPI behind the Next.js frontend. Complaints live in DynamoDB, photos in S3. The instance’s IAM role can only touch the one table and the one bucket it needs.

One box is a deliberate choice: at this traffic, the failure modes of a single well-understood host are easier to reason about than a managed fleet I’d be paying for and not using.

What’s next

  • Move from duckdns.org to civicfix.vansshagarrwal.in with HTTPS.
  • Get a real neighbourhood using it and publish the usage numbers here.