Empowering citizens and municipal authorities with AI-driven clustering, intelligent priority scoring, and verifiable photo resolutions.
Citizens frequently encounter urban civic issues β potholes, broken streetlights, overflowing trash bins, road fissures, and water pipeline leaks. However:
- Reporting is fragmented: WhatsApp groups, manual phone calls, or cumbersome portals (e.g. CPGRAMS) lead to reports being overlooked.
- Authorities drown in duplicate complaints: Multiple citizens report the same pothole, clogging the triage queue without an automated deduplication mechanism.
- Lack of intelligent prioritization: Authorities struggle to identify which issues demand urgent intervention (e.g., a crater near a hospital versus a quiet residential alley).
- Resolution credibility gap: Municipal staff self-declare issues as "fixed" with no visual verification or citizen confirmation loop.
CivicFix bridges the gap between urban citizens and municipal workforces with an end-to-end, full-stack intelligence platform:
- β‘ 60-Second Citizen Reporting: Citizens take a photo with GPS location, pick a category, and submit.
- π― PostGIS Geospatial Deduplication: Automatically groups incoming reports with open issues within 500 meters of the same category.
- π§ Multimodal AI Visual Similarity (Gemini 2.0 Flash): Compares complaint photos to prevent duplicates and evaluate before/after repair verification.
- π Intelligent Priority Scoring (1β100): Automatically prioritizes complaints using a realistic 4-factor model: Inherent Hazard Baseline (35%), Consensus Volume Log-Curve (25%), Proximity to Schools/Hospitals (25%), and Category SLA Breach Progression (15%).
- π‘οΈ Anti-Spam & Fraud Engine: Detects burst submissions, duplicate image hashes, and high-frequency geo-spam.
- π Closed-Loop Resolution Verification: Requires an after-repair photo evaluated by Gemini Vision, backed by a citizen confirm/reject validation loop.
- πΊοΈ Clustered GeoJSON Map: Generates clustered GeoJSON feeds for real-time visualization on interactive citizen and authority maps.
CivicFix is designed around a Feature-Based (Vertical Slice / Modular Domain) architecture for high cohesion, rapid testability, and future microservice extraction:
CIVICFIX/
βββ .gitignore
βββ README.md
βββ backend/
βββ prisma/
β βββ schema.prisma # PostgreSQL + PostGIS models & spatial extensions
β βββ seed.ts # Demo seeds (Citizen, Authority, Admin, Landmark locations)
βββ src/
βββ app.ts # Express assembly & global middleware pipeline
βββ index.ts # Fail-fast env validation & server bootstrapper
β
βββ core/ # Cross-cutting shared kernel
β βββ cache/ # Native in-memory TTL cache (replaces Redis)
β βββ config/ # Fail-fast env loader & validator
β βββ database/ # Singleton PrismaClient
β βββ external/ # Gemini 2.0 Flash & Cloudinary SDK clients
β βββ middleware/ # JWT auth, RBAC, tiered rate limiters, Zod validator, Multer
β βββ types/ # Global interfaces (APIResponse, APIError)
β βββ utils/ # Response helpers & sha256 hashing
β
βββ features/ # Domain vertical slices
βββ auth/ # JWT access tokens + httpOnly SameSite=Strict refresh cookies
βββ users/ # Profile management
βββ complaints/ # Citizen complaint reporting, status history & confirmation
βββ clustering/ # PostGIS ST_DWithin clustering & priority scoring algorithm
βββ authority/ # Priority-ranked triage queue, officer assignment, resolution
βββ map/ # Clustered GeoJSON FeatureCollection endpoint
βββ ai/ # Multimodal Gemini image comparison & auto-categorization
βββ upload/ # 5MB image buffer upload to Cloudinary CDN
βββ admin/ # KPI analytics, user role moderation, spam detection
- Runtime & Language: Node.js v20+, TypeScript 5.5, Express 4.19
- Database & ORM: PostgreSQL via Supabase with
postgis&pg_trgmextensions, Prisma 5.22 - Artificial Intelligence: Google Gemini 2.0 Flash (
@google/generative-ai) - Media Storage: Cloudinary CDN with Multer memory buffer streaming
- Caching: High-performance in-memory TTL caching with automatic expired-key eviction
- Security & Validation: Helmet.js, CORS origin lockdown, bcrypt (saltRounds=10), JSON Web Tokens (JWT), Zod (with strict field validation), and tiered
express-rate-limit
Calculated dynamically whenever a complaint joins a cluster or an age milestone passes:
-
$\text{Hazard Baseline}$ (35%): Inherent public safety impact by category:-
WATER_LEAKAGE:$1.00$ (Critical infrastructure, contamination) -
POTHOLE:$0.90$ (Vehicular/pedestrian accident risk) -
ROAD_DAMAGE:$0.85$ (Structural road/barrier failure) -
STREETLIGHT:$0.65$ (Night crime & visibility risk) -
GARBAGE:$0.50$ (Sanitation & disease vector) -
OTHER:$0.40$ (Default conservative baseline)
-
-
$\text{Volume / Consensus}$ (25%): Crowd consensus log curve:$\min\left(\frac{\log_2(N + 1)}{\log_2(11)},\ 1.0\right)$ -
$\text{Proximity Boost}$ (25%):$1.0$ (within 500m of hospital/school),$0.5$ (within 1km),$0.0$ (otherwise) -
$\text{SLA Aging}$ (15%): Category-aware resolution turnaround SLA:$\min\left(\frac{\text{days_open}}{\text{SLA_DAYS[category]}},\ 1.0\right)$ (1 day for Water Leakage up to 7 days for Other)
-
Geospatial Proximity: Queries open clusters of the same category within 500m using PostGIS:
ST_DWithin(ST_MakePoint(lng, lat)::geography, ST_MakePoint(centroidLng, centroidLat)::geography, 500) -
Visual Similarity: Compares candidate image to seed image using Gemini Vision. If similarity score
$\ge 0.75$ , the complaint joins the cluster; otherwise, it seeds a new cluster.
Flags accounts as UNDER_REVIEW if any trigger fires:
- Exceeds 10 submissions in 1 hour
- Submits 3 or more complaints within 100m inside 10 minutes
- Re-uploads an identical image hash (SHA-256) within 24 hours
- Node.js 18+ & npm
- PostgreSQL database with PostGIS enabled (e.g. Supabase)
- Google Gemini API Key (Google AI Studio)
- Cloudinary Account (Cloudinary)
git clone https://github.com/WisdomKingAR/CivicFix.git
cd CivicFix/backendnpm installCopy .env.example to .env and fill in your credentials:
cp .env.example .envPORT=3001
NODE_ENV=development
FRONTEND_URL=http://localhost:3000
# Secrets
JWT_SECRET=your_super_secret_jwt_key_at_least_32_chars
JWT_ACCESS_EXPIRES_IN=15m
JWT_REFRESH_EXPIRES_IN=7d
# Database (Supabase PostgreSQL with PostGIS)
DATABASE_URL="postgresql://postgres:[PASSWORD]@[HOST]:6543/postgres?pgbouncer=true"
DIRECT_URL="postgresql://postgres:[PASSWORD]@[HOST]:5432/postgres"
# AI & Storage
GEMINI_API_KEY=your_gemini_api_key
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret# Enable PostGIS in your database SQL Editor:
# CREATE EXTENSION IF NOT EXISTS postgis;
# CREATE EXTENSION IF NOT EXISTS pg_trgm;
# Generate Prisma Client
npx prisma generate
# Apply Migrations
npx prisma migrate dev --name init
# Seed Test Data
npm run prisma:seednpm run devServer boots on http://localhost:3001 with active health monitoring at http://localhost:3001/health.
Seeded automatically by prisma/seed.ts:
| Role | Password | Access Rights | |
|---|---|---|---|
| Citizen | citizen@civicfix.com |
HackDemo@2025 |
Submit complaints, view own issues, confirm/reject resolutions |
| Authority Officer | authority@civicfix.com |
HackAuth@2025 |
View priority queue, assign workers, upload repair photos |
| Admin | admin@civicfix.com |
HackAdmin@2025 |
System-wide analytics, user role moderation, spam reports |
All responses return standard envelopes:
- Success:
{ "success": true, "data": T, "message": string } - Error:
{ "success": false, "error": string, "code": string }
POST /registerβ Register account (Rate limit: 30/hr)POST /loginβ Login user, sets httpOnly refresh cookie (Rate limit: 50/15min,skipSuccessfulRequests: true, composite IP+email key,trust proxy: 1enabled)POST /refreshβ Refresh access token via cookieDELETE /logoutβ Invalidate session and clear cookie
GET /meβ Current user profilePUT /profileβ Update name and phone number
POST /β Submit complaint with photo & GPS (Rate limit: 30/hr)GET /β Get citizen's own complaints (paginated)GET /:idβ Get single complaint detail with historyPUT /:id/confirm-resolutionβ Confirm or reject repair resolution
GET /queueβ Priority-sorted complaint queue (filters by category, status, ward)PUT /complaints/:id/statusβ Update complaint statusPOST /complaints/:id/assignβ Assign complaint to field staffPOST /complaints/:id/resolveβ Submit after-repair photo and trigger AI verification
GET /api/clustersβ List all open complaint clusters with priority scoresGET /api/clusters/:idβ View cluster detail with member complaintsGET /api/map/complaintsβ Clustered GeoJSON FeatureCollection (cached 60s, Mumbai centered)
GET /api/ai/healthβ Gemini API connectivity and model status probePOST /api/uploadβ Upload image file (max 5MB) to CloudinaryPOST /api/ai/compare-imagesβ Manual before/after repair comparison tool
GET /usersβ List all accounts with complaint counts and flag statusPATCH /users/:idβ Update user roles or flag/unflag accountsGET /analyticsβ Resolution rates, category distribution, average priority scoreGET /spamβ View flagged accounts with spam detection logsGET /api/ratna/ledgerβ Citizen Ratna civic points ledger & redemption coupons
- OWASP Compliance: Parameterized SQL queries via Prisma ORM block injection attacks.
- Reverse-Proxy Aware Rate Limiting:
app.set('trust proxy', 1)correctly parses real client IPs behind cloud load balancers (Render, Vercel, AWS ALB). - Graceful Rate Limiting: All public endpoints enforce sensible rate limits with
skipSuccessfulRequests: trueand compositeIP + emailkeys, preventing one user's failed attempts from locking out other 5704 systems or legitimate logins. Returns standard JSON429withRetry-Afterheaders. - Strict Schema Filtering: All mutating payloads are validated with Zod
.strict()to reject unauthorized or rogue injected fields. - Token Hygiene: Short-lived (15m) access tokens live in memory; long-lived (7d) refresh tokens are sealed in
httpOnly,SameSite=Strictcookies. - Zero Secrets in Code: Environment validator verifies all required credentials fail-fast at boot time;
.envis permanently excluded from Git.
This project is licensed under the MIT License.