
CityCare - City Complaint & Service Request Platform
A city complaint and service request platform for Dhaka. Citizens report problems on public property or book home services paid by card, bKash or Nagad, pin the exact spot on a map and follow every step with a tracking code. Field staff work through their jobs by deadline, and city admins assign the work, watch the deadlines and read the numbers. Built solo end to end: a Next.js frontend and an Express, Prisma and PostgreSQL API.
Problem
In many cities a citizen does not know where to report a problem, and after reporting nobody knows what happened to it. The city has no clear picture of which department is slow or which area has the most problems. CityCare gives every complaint one place to go, routes it to the right department automatically, puts a deadline on every category and escalates the work that misses it.
Tech Stack
Key Engineering Decisions
- Kept auth tokens out of browser JavaScript entirely: JWTs live in HTTP-only cookies, a Next.js proxy verifies and refreshes them on every request, and client calls go through a backend-for-frontend route that attaches the token and the real client IP.
- Modelled the complaint lifecycle as an explicit workflow: every status change is checked against the allowed transitions and saved with its timeline entry, audit log row and notifications in one database transaction, so the inbox and the timeline always agree.
- Locked rows in a fixed order for assignment, payment settlement and refunds, so parallel requests can neither break a staff member's capacity limit nor deadlock.
- Put card payments (Stripe) and bKash and Nagad (SSLCommerz) behind one checkout endpoint with shared, idempotent settlement: the return, the webhook or IPN and the verify endpoint can all arrive and the payment still completes exactly once, and a rejected request is refunded through the provider it was paid with.
- Never trusted the form SSLCommerz posts back: the API takes only the transaction id from it, asks the SSLCommerz validation API for the real status and checks the amount and currency against the fee before settling. A second payment from a stale tab is refunded on its own, and a daily job settles or cancels wallet payments left open.
- Protected citizens on the public map: only reports the citizen made public are shown, with no names, phone numbers or addresses, and coordinates rounded to about 10 meters.
- Shared Redis caching and rate limits across serverless instances, with exact cache invalidation, and kept the API answering when Redis is down.
- Rendered pages as Server Components that prefetch with the user's cookie and hydrate TanStack Query, so dashboards paint with data on first load and filters live in the URL.
What I Built
- Designed and built both halves alone: a Next.js 16 and React 19 frontend, and an Express 5, Prisma 7 and PostgreSQL API with more than 80 endpoints documented in Swagger and Postman.
- Wrote the complaint workflow engine, assignment with per-staff capacity limits, the deadline escalation job, and the payment layer for Stripe and SSLCommerz.
- Built the map layer end to end: the location picker, a nearby search ranked by distance in the database, and privacy-safe public map feeds.
- Wrote 494 API tests against real PostgreSQL and Redis, 104 frontend unit tests and 47 Playwright end-to-end tests covering the full report journey, bKash and Nagad in the SSLCommerz sandbox, accessibility audits with axe and a phone layout.
- Set up delivery: GitHub Actions CI that runs the whole stack end to end, Docker images for both apps, Vercel deployment with scheduled jobs, and Dependabot.
Impact
- A complete civic workflow from report to fix: every complaint has an owner, a deadline, a timeline and a tracking code anyone can follow.
- Citizens can pay the way most people in Bangladesh actually pay, with bKash and Nagad mobile wallets as well as cards.
- Over 600 automated tests run on every push, including the full citizen, admin and staff journey against the real API.
- A live demo with one-click sign-in for every role, and a local setup that runs with Docker.
Screenshots






