CivicSense is an AI-powered public infrastructure reporting and governance platform. Citizens can report civic issues on a map with image evidence, while AI-assisted analysis helps with category, verification, duplicate, and severity signals. Admins triage and assign work, workers submit closure evidence, and supervisors monitor department-scoped queues. Public transparency views show safe progress without private notes, with support for local or Cloudinary image storage, WebSocket notifications, and CSV/XLSX audit exports.
- Citizen reporting with map location, image upload, and report tracking
- AI-assisted verification, duplicate signals, category hints, and severity support
- Admin triage, worker assignment, worker closure evidence, and supervisor department queues
- Public transparency dashboard with private feedback/admin notes excluded
- Local or Cloudinary image storage, live WebSocket notifications, and XLSX/audit exports
Citizen reports issue with image -> AI assists category/verification -> Admin verifies and assigns -> Worker resolves with closure evidence -> Admin reviews closure -> Citizen submits feedback -> Public transparency dashboard shows safe progress.
- Java 21
- PostgreSQL
- Node.js + npm
- Docker Desktop for the full local stack
- AI service running on
http://localhost:8000for image analysis features
Docker Compose V1 runs the local development stack from the repository root:
docker compose up --buildServices:
- Frontend:
http://localhost:5173 - Backend API:
http://localhost:8031 - AI service:
http://localhost:8000 - PostgreSQL:
localhost:5432
Create a local env file if you want to override defaults:
cp .env.example .envThe compose stack uses named volumes for PostgreSQL data and local uploads, so data survives container restarts and docker compose down.
Stop the stack:
docker compose downReset local database and upload persistence:
docker compose down -vUse -v carefully: it removes the named PostgreSQL/uploads volumes and deletes local compose data. Cloudinary remains optional through STORAGE_PROVIDER=cloudinary plus the Cloudinary variables in .env.
Image analysis runs asynchronously inside the backend after upload persistence. The normal full-stack workflow no longer starts Kafka or ZooKeeper.
The older docker-compose.kafka.yml and rollback Spring profile are kept only for Kafka rollback/testing; the normal full-stack workflow is the root docker-compose.yml.
Backend module root:
backend/backend/Create local environment variables using:
backend/backend/.env.exampleImportant production variables:
SPRING_PROFILES_ACTIVE
FLYWAY_ENABLED
DB_URL
DB_USER
DB_PASSWORD
JWT_SECRET
PUBLIC_BASE_URL
CORS_ALLOWED_ORIGINS
AI_SERVICE_BASE_URL
STORAGE_PROVIDER
CLOUDINARY_CLOUD_NAME
CLOUDINARY_API_KEY
CLOUDINARY_API_SECRET
CLOUDINARY_FOLDER
UPLOADS_PUBLICRun backend:
cd backend/backend
mvn spring-boot:runCreate:
frontend/.envUse:
VITE_API_BASE_URL=http://localhost:8031
VITE_WS_URL=http://localhost:8031/ws
VITE_AI_PREVIEW_URL=http://localhost:8000/analyze-previewRun frontend:
cd frontend
npm install
npm run dev/-> Landing page/login-> Login/register-> Citizen registration/dashboard-> Citizen dashboard/admin-> Admin dashboard/admin/staff-> Staff Management/worker-> Worker dashboard/supervisor-> Supervisor dashboard/transparency-> Public transparency
Demo credentials depend on your local seed data. The optional local demo seed includes these intentionally demo-only accounts:
- Admin:
demo.admin@civicsense.local - Supervisor:
demo.supervisor@civicsense.local - Worker:
demo.worker@civicsense.local - Citizen:
demo.citizen@civicsense.local - Demo password for the optional seed accounts:
password
Do not reuse demo credentials in production or commit private passwords.
Local upload storage remains the default:
STORAGE_PROVIDER=local
UPLOADS_PUBLIC=trueCloudinary storage is opt-in for newly uploaded issue and resolution images:
STORAGE_PROVIDER=cloudinary
CLOUDINARY_CLOUD_NAME=replace-with-cloud-name
CLOUDINARY_API_KEY=replace-with-api-key
CLOUDINARY_API_SECRET=replace-with-api-secret
CLOUDINARY_FOLDER=civicsenseCloudinary mode stores new display URLs from Cloudinary secure_url values. Older local image records still resolve through PUBLIC_BASE_URL/uploads/..., and AI analysis still uses the backend's local upload path after storage. Never commit real Cloudinary credentials.
Kafka is no longer required for standard image processing. To test the legacy rollback path, start Kafka separately with:
docker compose -f docker-compose.kafka.yml up -dThen start the backend with the kafka-rollback Spring profile and the legacy Kafka variables:
SPRING_PROFILES_ACTIVE=dev,kafka-rollback
KAFKA_BOOTSTRAP_SERVERS=localhost:9092
KAFKA_CONSUMER_GROUP_ID=civicsense-ai-group
KAFKA_AUTO_OFFSET_RESET=earliest
KAFKA_TOPIC_ISSUE_IMAGE_UPLOADED=issue-image-uploadedThis profile is retained for rollback safety only and is not part of the standard deployment path.
Manual SQL files live in:
backend/backend/sql/Run in this order:
psql -U civicsense_user -d civicsense_db -f backend/backend/sql/roles_v1.sql
psql -U civicsense_user -d civicsense_db -f backend/backend/sql/issue_timeline_v1.sql
psql -U civicsense_user -d civicsense_db -f backend/backend/sql/issue_feedback_v1.sql
psql -U civicsense_user -d civicsense_db -f backend/backend/sql/notifications_v1.sqlOptional local demo data only:
psql -U civicsense_user -d civicsense_db -f backend/backend/sql/demo_seed_optional.sqlDo not run demo seed on production.
Use:
docs/PRODUCTION_READINESS_SMOKE_TESTS.mdDocker Compose V1 is the next phase. The repository currently supports manual local startup for the backend, frontend, AI service, database, and optional Kafka testing.
When using:
SPRING_PROFILES_ACTIVE=prodyou must provide real values for:
JWT_SECRET
DB_URL
DB_USER
DB_PASSWORD
PUBLIC_BASE_URL
CORS_ALLOWED_ORIGINS
AI_SERVICE_BASE_URLUse the production checklist before deploying:
docs/PRODUCTION_DEPLOY_CHECKLIST.mdFor Cloudinary migration details, use:
docs/CLOUDINARY_MIGRATION_V1.mdProduction runs Flyway from database/migrations using:
spring.flyway.locations=filesystem:../../database/migrationsRun the backend from backend/backend so this path resolves correctly. Keep manual SQL files in backend/backend/sql/ for local psql setup only.
.env
frontend/.env
backend/backend/.env
ai-service/.env
backend/backend/target/
uploads/