CivicFlow: resident issue reports for local government
A resident reports a fault through a form with a category and a priority, and staff run the whole queue of reports in one panel, with a journal of every status change.
Resident reports get lost in inboxes and phone calls
A fault reaches the local office by email or phone. No one sees right away what is urgent, what is already being handled, or how many similar reports came in. So we built a simple portal: the resident picks a category and priority, and staff see the whole queue and change status without digging through email.
One reporting system, from municipality to local wardens
CivicFlow fits anywhere a resident's report needs to reach the right department with a priority attached, not a shared inbox. A gmina, Poland's smallest municipal unit, tracks road and lighting faults in it. A city routes reports across departments. Municipal wardens run a separate queue: illegal parking, noise, public order. Categories and permissions adapt to your organization's structure, not the other way round.
From a resident's form to a staff dashboard
- Submission
- A form validated on the client and with a Zod schema on the server: name, email, one of 6 categories, priority, message. A CSRF token in a double-submit-cookie pattern blocks cross-site attacks before the request is even sent.
- Verification and save
- The server first checks the CSRF token against the secret in an httpOnly cookie, checks the rate limit, validates the content with a Zod schema, and only then adds the report to the register.
- Admin dashboard
- Staff see every report in one place: filter by category and priority, sort by date, change status moving a report through Pending, In Progress and Resolved or Rejected in a single click.
- Security headers
- HSTS, X-Content-Type-Options, Referrer-Policy and a per-request CSP nonce, all set at the response level. The demo has no database: the register travels in the visitor's own signed cookie, so one person's data is never on another person's screen.
Structure, not marketing numbers
One person's data never shows up on another person's screen.
- 6
- report categories: each lands with the right department and a priority, not in a shared inbox.
- 4
- report statuses, changed with a single click: the whole team sees at once what is waiting, in progress, and closed.
- 2 h
- is how long a demo register lives: then the cookie expires and there is nothing left to delete.
Our own project. We built it and we run it ourselves. The register you click is your own private copy in a signed cookie, so you can try everything without an account.
Every choice has a reason
| Layer | Choice | What it does |
|---|---|---|
| Frontend | Next.js | The dashboard opens with the list of reports already there, with no loading screen. |
| Demo data | Signed HMAC cookie | The register you click is your own copy, and it expires on its own. |
| Validation | Zod | The same rules check the form on your side and on the server, so you see a mistake once. |
| Security | CSRF (double-submit cookie) | Another site cannot file a report in your name. |
| Admin session | HMAC SHA-256 | The staff dashboard opens only for someone with a valid session. |
| Styling | Tailwind CSS | One light theme that stays readable on an older office monitor too. |
