A full-stack web application connecting citizens with volunteers for community assistance in Rwanda.
| Service | URL |
|---|---|
| Frontend App | community-support-system.vercel.app |
| Backend API | community-support-system.fly.dev |
| Swagger UI | /swagger-ui.html |
| Health Check | /actuator/health |
┌─────────────────────────────────────────────────────────────────────┐
│ CLIENT LAYER │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ React 19 + TypeScript + Vite │ │
│ │ (Vercel — CDN Edge) │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Citizen │ │Volunteer │ │ Admin │ │ Landing │ │ │
│ │ │Dashboard │ │Dashboard │ │Dashboard │ │ Page │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ │ │ │
│ │ Tailwind CSS (B&W) │ Recharts │ React Query │ │
│ │ Lucide Icons │ i18next │ Axios │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │ HTTPS │
└──────────────────────────────┼──────────────────────────────────────┘
│
┌──────────────────────────────┼──────────────────────────────────────┐
│ API GATEWAY LAYER │
│ │
│ Spring Security + JWT Filter │
│ CORS Policy + Rate Limiting │
│ │
└──────────────────────────────┼──────────────────────────────────────┘
│
┌──────────────────────────────┼──────────────────────────────────────┐
│ APPLICATION LAYER │
│ Spring Boot 3.5.6 — Java 17 │
│ (Fly.io — Frankfurt) │
│ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────────┐ │
│ │ Auth │ │ Requests │ │Assignments │ │ Notifications │ │
│ │ Controller │ │ Controller │ │ Controller │ │ Controller │ │
│ └────────────┘ └────────────┘ └────────────┘ └────────────────┘ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────────┐ │
│ │ Analytics │ │Gamification│ │Availability│ │ Admin │ │
│ │ Controller │ │ Controller │ │ Controller │ │ Controller │ │
│ └────────────┘ └────────────┘ └────────────┘ └────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ SERVICE LAYER │ │
│ │ UserService │ RequestService │ AssignmentService │ │
│ │ NotificationService │ AnalyticsService │ LeaderboardService │ │
│ │ AchievementService │ EmailService │ AuthService │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────┬──────────────────────────┬─────────────────────┘
│ │
┌───────────┘ └──────────────┐
▼ ▼
┌─────────────────────────┐ ┌──────────────────────────┐
│ DATA LAYER │ │ EXTERNAL SERVICES │
│ │ │ │
│ PostgreSQL 17 │ │ SendGrid (Email) │
│ (Fly.io Managed DB) │ │ Rwanda Location API │
│ │ │ (Administrative data) │
│ 9 Tables: │ │ │
│ • users │ └──────────────────────────┘
│ • locations │
│ • requests │
│ • assignments │
│ • notifications │
│ • skills │
│ • user_skills (M:N) │
│ • user_settings │
│ • achievements │
└──────────────────────────┘
CITIZEN VOLUNTEER ADMIN
│ │ │
│ Register / Login │ Register / Login │ Login
│ │ │
├─ Create Request ├─ Browse Requests ├─ Manage Users
├─ Track Status ├─ Accept Assignment ├─ Moderate Requests
├─ View Notifications ├─ Complete Task ├─ Broadcast Alerts
├─ Rate Volunteer ├─ Earn Points/Badges ├─ View Analytics
└─ Book Appointment └─ View Leaderboard └─ System Settings
| Service | Provider | Purpose |
|---|---|---|
| Fly.io | Frankfurt region | |
| Vercel | CDN edge deployment | |
| GitHub | CI/CD via Vercel + Fly | |
| Fly.io Managed | Persistent cloud DB |
The entire UI is available in two languages, switchable at runtime without page reload:
| Language | Code | Flag | Coverage |
|---|---|---|---|
| English | en |
🇬🇧 | 100% — all pages, labels, errors, toasts |
| French | fr |
🇫🇷 | 100% — all pages, labels, errors, toasts |
Implementation:
react-i18nextwith JSON locale files (frontend/src/i18n/locales/en.json,fr.json)LanguageContextsyncs both i18n systems on language switch- Language preference persisted in
localStorage
The UI uses a strict black & white / grayscale palette — no colour anywhere in the interface.
| Token | Value | Usage |
|---|---|---|
| Primary | #000000 |
Buttons, headings, active states |
| Secondary | #333333 |
Sub-headings, icons |
| Muted | #777777 |
Placeholder text, borders |
| Surface | #f5f5f5 |
Card backgrounds (light mode) |
| Surface Dark | #1e1e1e |
Card backgrounds (dark mode) |
| Background | #ffffff / #111111 |
Page background |
- Dark mode via Tailwind
dark:classes, toggled withclassstrategy - Charts use grayscale hex:
#000000,#333333,#555555,#777777,#aaaaaa,#bbbbbb - No teal, blue, orange, green, or yellow used anywhere
9 Tables — 7 core entities + 2 junction tables
users ──────────────────────────────────────────────────────────────┐
│ userId, name, email, role, province, emailVerified, twoFactor │
│ │
├──< requests >────────────────────────────────────────────────── │
│ requestId, title, description, category, status, citizenId │
│ │
├──< assignments >─────────────────────────────────────────────── │
│ assignmentId, requestId, volunteerId, acceptedAt, completedAt│
│ │
├──< notifications >───────────────────────────────────────────── │
│ notificationId, message, isRead, userId │
│ │
├──< user_skills (M:N) >──────────────── skills ───────────────── │
│ userId, skillId skillId, skillName │
│ │
├──< user_settings >───────────────────────────────────────────── │
│ userId, emailNotifications, smsNotifications │
│ │
└──< achievements >────────────────────────────────────────────── │
achievementId, name, description, userId ──────┘
locations
locationId, province, district, provinceCode
(30 districts across 5 provinces)
| Group | Count | Key Endpoints |
|---|---|---|
| Auth | 12 | login, register, verify-email, forgot-password, 2FA |
| Users | 25 | CRUD, role filter, skills, location hierarchy |
| Requests | 16 | create, status update, citizen stats |
| Assignments | 11 | accept, complete, volunteer dashboard |
| Notifications | 15 | list, mark-read, stats, broadcast |
| Skills | 13 | CRUD, popular skills |
| Locations | 11 | provinces, districts, Rwanda hierarchy |
| Rwanda API | 5 | Province → District → Sector → Cell → Village |
| Analytics | 7 | dashboard stats, province breakdown, growth |
| Admin | 10 | moderate requests, lock users, broadcast |
| Gamification | 3 | profile, leaderboard, add points |
| Availability | 3 | get, save, update status |
| Ratings | 4 | create, by volunteer, by assignment, average |
| Appointments | 4 | create, list, update, cancel |
| Expenses | 5 | submit, list, approve, reject |
| Settings | 4 | user preferences |
| Categories | 1 | list all categories |
Full documentation: Swagger UI
Postman collection: Community_Support_System.postman_collection.json
| Tool | Version |
|---|---|
| Java (JDK) | 17 |
| Maven | 3.8+ |
| PostgreSQL | 14+ |
| Node.js | 20+ |
| npm | 9+ |
git clone https://github.com/manziosee/community-support-system.git
cd community-support-system
# Create database
psql -U postgres -c "CREATE DATABASE community_support_system_db;"
# Run dev profile (test controllers active, H2/Postgres, debug logs)
SPRING_PROFILES_ACTIVE=dev ./mvnw spring-boot:runBackend: http://localhost:8080
Swagger: http://localhost:8080/swagger-ui.html
cd frontend
npm install
npm run devFrontend: http://localhost:3000
# Copy and edit environment variables
cp .env.example .env
docker compose up --build| Service | URL |
|---|---|
| Frontend | http://localhost:3000 |
| Backend | http://localhost:8080 |
| PostgreSQL | localhost:5432 |
flyctl deploy| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL JDBC URL |
JWT_SECRET |
Yes | Secret key for JWT signing |
SENDGRID_API_KEY |
SendGrid API key | |
SENDGRID_FROM_EMAIL |
Verified sender address | |
SENDGRID_ENABLED |
No | true to enable email (default: false) |
CORS_ALLOWED_ORIGINS |
Yes | Comma-separated allowed origins |
FRONTEND_URL |
Yes | Frontend base URL for email links |
SPRING_PROFILES_ACTIVE |
Yes | dev, fly, or docker |
- JWT tokens with configurable expiry (default 24h)
- Email verification required before login
- Optional Two-Factor Authentication (email OTP)
- Account lockout after failed attempts
- Role-based access:
@PreAuthorize("hasRole('ADMIN')")on all admin endpoints - CORS restricted to known origins (no wildcard in production)
- Global exception handler — no stack traces leaked to clients
- Test/debug controllers only active under
@Profile("dev")
| Feature | Details |
|---|---|
| CRUD Operations | All 9 entities with full create/read/update/delete |
| Rwanda Locations | 5-level hierarchy: Province → District → Sector → Cell → Village |
| Email Verification | SendGrid — token-based, expires in 24h |
| Two-Factor Auth | Email OTP with backup codes |
| Role-Based Access | Citizen, Volunteer, Admin with method-level enforcement |
| Notifications | Real-time assignment alerts, read/unread tracking |
| Analytics | DB-backed stats, growth metrics, province breakdown |
| Gamification | Points, levels, achievements, leaderboard |
| Availability | Volunteer schedule management |
| Ratings | Post-assignment volunteer reviews with averages |
| Appointments | Citizen-volunteer scheduling |
| Expenses | Claim submission and admin approval flow |
| Internationalisation | English and French, switchable at runtime |
| Dark Mode | System-aware + manual toggle, full Tailwind dark: coverage |
| Postman Collection | 160+ pre-built requests with examples |
| Swagger / OpenAPI | Auto-generated, browsable API docs |
Default account created on first boot (dev / local only):
| Field | Value |
|---|---|
darkosee23@gmail.com |
|
| Password | admin123 |
| Role | ADMIN |
Change this password immediately in any non-local environment.
BASE=http://localhost:8080
# Health
curl $BASE/health
# All locations
curl $BASE/api/locations
# Login
curl -X POST $BASE/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"darkosee23@gmail.com","password":"admin123"}'
# Analytics dashboard (requires Bearer token)
curl $BASE/api/analytics/dashboard \
-H "Authorization: Bearer <token>"
# Gamification leaderboard
curl $BASE/api/gamification/leaderboard
# Volunteer availability
curl $BASE/api/availability/volunteer/1- Fork the repository
- Create a feature branch —
git checkout -b feature/my-feature - Commit using conventional commits —
git commit -m 'feat: add my feature' - Push —
git push origin feature/my-feature - Open a Pull Request against
main
Built for Rwanda community assistance — connecting people who need help with people who can help.