Community Hero is a full-stack app for reporting civic issues (potholes, broken streetlights, water leaks, waste, etc.) and turning that reporting into something people actually want to do. Built with React, Express, and the Gemini API.
Residents can snap a photo of a problem or record a voice complaint. Gemini classifies the issue, scores its severity, and writes a description automatically — no manual form-filling. Reports show up on a shared feed where neighbors can upvote and comment, and reporting earns users XP, coins, and badges.
┌────────────────────────────────────────────────────────────────────────┐
│ USER / CLIENT SIDE │
└───────────────────┬────────────────────────────────┬───────────────────┘
│ (Image Upload / Voice Audio) │ (Upvotes / Chat)
▼ ▼
┌────────────────────────────────────────────────────────────────────────┐
│ EXPRESS BACKEND (PORT 3000) │
└───────────────────┬────────────────────────────────┬───────────────────┘
│ │
│ If media uploaded │ Analyze payload
▼ ▼
┌───────────────────────────────┐ ┌───────────────────────────────┐
│ CLOUDINARY STORAGE │ │ GEMINI API │
│ (falls back to a stock │ │ (image/voice analysis via │
│ placeholder URL if unset) │ │ Node SDK) │
└───────────────┬───────────────┘ └───────────────┬───────────────┘
│ │
▼ URL reference ▼ Structured JSON
┌────────────────────────────────────────────────────────────────────────┐
│ DATA PERSISTENCE LAYER │
├────────────────────────────────────────────────────────────────────────┤
│ Primary: MongoDB + Redis │
│ Fallback: in-memory store, pre-seeded with sample data │
└───────────────────────────────────┬────────────────────────────────────┘
│
▼ Saves state
┌────────────────────────────────────────────────────────────────────────┐
│ ADMIN DASHBOARD │
│ Urgency scoring · AI remediation tips · Moderation tools │
└────────────────────────────────────────────────────────────────────────┘
- Report creation: user submits a photo or a voice recording of the issue.
- Upload: the server streams the file to Cloudinary. If Cloudinary isn't configured (e.g. local dev without keys), it falls back to a placeholder URL so the app still works end to end.
- Gemini analysis:
- Image: categorizes the issue (
Infrastructure,Waste,Lighting,Water,Safety,Other), assigns a 1–10 severity score, and writes a short description. - Voice: transcribes the recording, cleans it up, and produces a description + category + severity, same as the image path.
- If Gemini is unavailable, both paths fall back to a simple filename/keyword heuristic so the demo still runs without an API key.
- Image: categorizes the issue (
- Rewards: each report earns the user +10 XP and +10 coins. Level =
floor(xp / 500) + 1. Two badges exist right now — First Report (after 1 report) and 10 Reports (after 10). - Admin side: officials can view all reports, run an AI urgency check on a report (combines severity, upvotes, and history into a risk score with a short justification), request AI-generated remediation steps, update a report's status (
Pending → In Progress → Resolved), and chat with an AI assistant for drafting responses.
| Layer | Technologies | What it's used for |
|---|---|---|
| Frontend | React 19, Tailwind CSS, Redux Toolkit, Lucide React, Framer Motion | UI, state management, animations |
| Backend | Node.js, Express, TSX | REST API, JWT auth, serves the Vite dev server |
| AI | Google @google/genai (Gemini) |
Image classification, speech-to-text, urgency scoring, admin chatbot |
| Database | Mongoose (MongoDB), Redis | Primary data store and caching |
| Fallback mode | In-memory store | If MongoDB/Redis aren't reachable, the app switches to an in-memory store pre-loaded with sample reports/users/comments, so it still runs (useful for demos or local dev without a DB) |
- Photo reports: snap or upload a photo; Gemini reads it and fills in category, severity, and a description automatically.
- Voice reports: record a complaint; it gets transcribed, cleaned up, and turned into a structured report the same way.
- XP, coins, and levels: earn 10 XP and 10 coins per report; level up every 500 XP.
- Badges: "First Report" and "10 Reports" badges, unlocked automatically based on report count.
- Feed: browse reports with search, category filters, upvotes, and threaded comments.
- Redeem store: spend coins on real rewards (merch) through an in-app shipping form.
- Leaderboard: ranks users by XP.
- Dashboard with aggregate stats (total reports, resolution rate, registered users).
- One-click AI urgency scoring per report.
- AI-generated remediation suggestions for city staff.
- Built-in chatbot for drafting notices/responses.
- Moderation: change report status, delete reports, ban users.
community-hero/
├── server.ts # Express entrypoint + Vite dev integration
├── server/
│ ├── config/
│ │ └── cloudinary.ts # Media upload handling
│ ├── controllers/
│ │ ├── adminController.ts # Admin stats, urgency scoring, remediation, chatbot
│ │ ├── authController.ts # Auth (JWT)
│ │ ├── leaderboardController.ts
│ │ ├── reportController.ts # Report creation, Gemini calls, XP/coin/badge logic
│ │ └── userController.ts # Profiles, avatar, store redemption
│ ├── db.ts # MongoDB + Redis connection, in-memory fallback
│ ├── middleware/
│ │ ├── authMiddleware.ts
│ │ ├── errorMiddleware.ts
│ │ └── multerMiddleware.ts # File upload handling
│ ├── models/
│ │ ├── Comment.ts
│ │ ├── Notice.ts # Admin announcements
│ │ ├── Report.ts # Report schema (category, severity, location, status)
│ │ └── User.ts # User schema (xp, coins, level, badges)
│ └── routes/
│ ├── adminRoutes.ts
│ ├── authRoutes.ts
│ ├── leaderboardRoutes.ts
│ ├── noticeRoutes.ts
│ ├── reportRoutes.ts
│ └── userRoutes.ts
├── src/
│ ├── api/
│ │ └── axiosInstance.ts # HTTP client with auth token handling
│ ├── components/
│ │ ├── admin/ # Admin chat, user management, notices
│ │ ├── feed/ # Feed page, report cards, comments
│ │ ├── layout/ # Bottom nav, top bar
│ │ ├── leaderboard/
│ │ ├── notices/
│ │ ├── profile/
│ │ ├── report/ # Image/voice report flows
│ │ ├── store/ # Redeem store
│ │ └── ui/ # Shared UI components
│ ├── pages/
│ │ ├── AdminPage.tsx
│ │ ├── AuthPage.tsx
│ │ └── HomePage.tsx
│ ├── store/ # Redux store + slices
│ ├── types.ts
│ ├── main.tsx
│ └── index.css
└── package.json