The problem_
Civic complaints in Indian municipalities are often filed on paper or via generic portals with no tracking, no assignment, and no resolution loop. Officers have no real-time visibility; citizens have no accountability. CiviZen closes that loop.
What I built_
- Citizen flow — File complaints with geo-location, category, description, and photo evidence. Track status in real time.
- Officer dashboard — Ward-filtered complaint queue, status updates, and resolution notes. Role-based access via Supabase RLS.
- Admin panel — Cross-ward analytics, complaint clustering by AI, officer assignment management.
- Push notifications — Firebase Cloud Messaging for status updates on both citizen and officer sides.
- AI clustering service — Groups nearby complaints of the same category to surface hotspots to officers.
- Offline queue — Hive-backed local cache; complaints filed offline sync when connectivity returns.
Architecture_
- Clean Architecture — core / domain / data / presentation layers; zero framework leakage into business logic.
- Riverpod 2 — StateNotifier, FutureProvider, StreamProvider; provider overrides for DI.
- Supabase — PostgreSQL + Row Level Security; storage buckets for media uploads.
- Firebase — FCM push notifications; background message handler.
- go_router — Declarative routing with role-based guards (citizen / officer / admin).
Stack_
- Flutter (Dart) — cross-platform iOS & Android
- Riverpod 2 — state management
- Supabase (PostgreSQL + Storage)
- Firebase (FCM)
- Hive — local cache / offline queue
- Google Maps + Geolocator
- OpenAI API — AI complaint clustering
Lessons_
RLS policies are the real auth layer — the Flutter app is just a view. Designing ward-scoped data access server-side first made role isolation airtight. AI clustering only earns its complexity if the officer actually acts on the cluster view; I prototyped the UI alongside the service.