A QR code-based survey application with anonymous access, built with Java, Docker, and PostgreSQL.
- Introduction
- Features
- Screenshots
- Architecture
- Tech Stack
- Configuration
- Deployment Architecture
- Getting Started
- Usage
- Testing and Coverage
- Troubleshooting
- CI/CD
- Production Deployment Considerations
- License
Create and share surveys instantly—no registration required. This application allows anyone to create yes/no question surveys, share them via QR code or link, and view real-time results in an admin dashboard.
Key highlights:
- Anonymous survey creation and participation
- Instant QR code and shareable link generation
- Real-time results with interactive charts
- Containerized deployment with load balancing
- No registration required: Anyone can create and share surveys.
- Custom Yes/No questions: Add as many questions as you like.
- QR Code & Link Sharing: Instantly share your survey via QR code or URL.
- Admin Dashboard: View real-time results and close surveys.
- Graphical Results: Visualize responses with charts.
- Secure Admin Access: Each survey has a unique admin link for management.
- Responsive UI: Built with Materialize CSS and Thymeleaf.
Create surveys with custom yes/no questions without registration.
Each survey generates a unique QR code and shareable link instantly.
Survey participants can easily answer questions through a clean, responsive interface.
Users receive immediate confirmation after submitting their responses.
View real-time results with interactive charts and close surveys when complete.
The application uses a containerized, load-balanced architecture with network isolation.
- Backend: Java 21, Spring Boot 3.5, Spring Data JPA, PostgreSQL.
- Frontend: Thymeleaf templates, Materialize CSS, Chart.js for results.
- QR Code Generation: ZXing library.
- Load Balancing: HAProxy 2.7 with round-robin distribution and health checks.
- Monitoring: Spring Boot Actuator for health checks and observability.
- Containerization: Docker & Docker Compose with multi-stage builds for optimized images.
- Persistence: PostgreSQL (configurable via environment variables).
- Build Tool: Maven.
- Security: Non-root container users, resource limits, health monitoring.
| Category | Technologies |
|---|---|
| Backend | Java 21, Spring Boot 3.5, Spring Data JPA, Spring Boot Actuator |
| Database | PostgreSQL |
| Frontend | Thymeleaf, Materialize CSS, Chart.js |
| QR Codes | ZXing (Zebra Crossing) |
| Load Balancer | HAProxy 2.7 (with health checks) |
| Containerization | Docker, Docker Compose (multi-stage builds) |
| Build Tool | Maven |
| Monitoring | Spring Boot Actuator (health, info endpoints) |
The application uses src/main/resources/application.properties for configuration. You can override settings using environment variables:
APP_BASE_URL– The base URL for generating links (default:http://localhost)DB_URL,DB_USERNAME,DB_PASSWORD– PostgreSQL connection details
Example .env file:
APP_BASE_URL=http://localhost
DB_URL=jdbc:postgresql://database:5432/surveydb
DB_USERNAME=postgres
DB_PASSWORD=test123
The application uses a containerized, load-balanced architecture with the following components:
- Load Balancer (HAProxy): Routes traffic to webserver instances on port 80 with health checks
- Webserver1 & Webserver2: Two Spring Boot application instances for high availability (with health monitoring via Actuator)
- Database: PostgreSQL container with persistent storage and health checks
- Network Isolation: Separate networks for app and database communication
- Resource Limits: CPU and memory limits on all containers for production stability
- Health Monitoring: Automated health checks on all services with HAProxy integration
┌──────────────┐
│ HAProxy :80 │
└──────┬───────┘
│
┌────────────┴────────────┐
│ │
┌───────▼────────┐ ┌───────▼────────┐
│ Webserver1 │ │ Webserver2 │
│ :8080 │ │ :8081 │
└───────┬────────┘ └───────┬────────┘
│ │
└────────────┬────────────┘
│
┌───────▼────────┐
│ PostgreSQL │
│ :5432 │
└────────────────┘
For Docker deployment:
- Docker & Docker Compose
For local development:
- Java 21 JDK
- Maven
- PostgreSQL
Start the complete stack with HAProxy load balancer, two Spring Boot instances, and PostgreSQL:
docker compose upAccess points:
- Load balanced: http://localhost (port 80)
- Webserver1: http://localhost:8080
- Webserver2: http://localhost:8081
Rebuild after code changes:
docker compose up --buildStop all containers:
docker compose downFor development without Docker, you need Java 21, Maven, and PostgreSQL installed locally.
# Compile
mvn compile
# Run tests
mvn verify
# Run the application (requires PostgreSQL)
mvn spring-boot:runApplication will be available at http://localhost:8080
Note: You must configure PostgreSQL connection in application.properties or via environment variables. For most use cases, Docker deployment is recommended.
Once the application is running, follow these steps:
- Navigate to http://localhost
- Enter your yes/no questions (add as many as you like)
- Click "Start Survey"
- Copy the generated public link and share it with participants
- Or share the QR code (can be scanned with any smartphone)
- Participants access the survey via the link or QR code
- They answer the yes/no questions
- Responses are stored in real-time
- Use the admin link provided when creating the survey
- View interactive charts showing response distribution
- Close the survey when complete (button becomes disabled)
- Check application health: http://localhost:8080/actuator/health
- HAProxy automatically monitors backend health and removes unhealthy instances from rotation
- Docker health checks ensure containers restart automatically if they become unhealthy
- Ensure PostgreSQL is running and configured as specified in
application.properties - You can adjust server settings (like port) in
src/main/resources/application.properties - For development, ensure your IDE has annotation processing enabled for Lombok support
- The application uses environment variables for configuration (see Configuration section)
- Health endpoint is available at
/actuator/healthfor monitoring and health checks - Multi-stage Docker builds optimize image size (JRE-only runtime, ~300MB vs ~800MB for full JDK)
This project includes a comprehensive test suite (unit, controller, repository, and end-to-end tests) and enforces a minimum code coverage threshold via JaCoCo.
-
Run tests and coverage (no Docker required; tests use H2 in-memory DB):
Windows:
.\mvnw.cmd verifyLinux/macOS:
./mvnw verify
-
View the HTML coverage report after the run:
- Open
target/site/jacoco/index.htmlin your browser.
- Open
-
Artifacts/locations:
- Test reports:
target/surefire-reports/ - Coverage report (HTML/XML/CSV):
target/site/jacoco/
- Test reports:
Notes:
- Controller tests use standalone MockMvc with Mockito (fast, no full context).
- Integration/E2E tests run on a Spring context with H2 and MockMvc; they don’t require Docker.
- The coverage rule is currently set to 80% line coverage at the bundle level and is passing.
-
Symptom:
docker compose upexits quickly and theloadbalancercontainer logs show a bind error for*:80. -
Cause: Port 80 is often reserved by IIS/HTTP.sys on Windows.
-
Fix options:
- Run Docker Desktop with elevated privileges and stop conflicting services, or
- Use an override to map HAProxy to a non-privileged port (e.g., 8080). Create
docker-compose.override.ymlwith:
services: loadbalancer: ports: - "8080:80"
Then access the app at http://localhost:8080 and, if needed, set
APP_BASE_URL=http://localhost:8080.
- Use
docker compose logs -f loadbalancerordocker compose logs -f webserver1to see detailed errors. - Verify database is up:
docker compose logs -f database.
This repository uses GitHub Actions for continuous integration and automated releases with semantic versioning.
- Workflow:
.github/workflows/ci.yml - Triggers: Push and pull requests to main
- Actions:
- Builds with Java 21
- Runs all 87 tests
- Executes
mvn verifywith JaCoCo coverage check (80% minimum) - Updates dynamic badges (test count, coverage, CI status)
- Status: See CI badge at top of README
The project uses semantic versioning that syncs with Git tags:
- Development: Uses
docker-compose.ymlfor local builds - Releases: Version extracted from Git tag (e.g.,
v1.2.3) - Docker tags: Images tagged with version (e.g.,
:v1.2.3) and:latest
Workflow: .github/workflows/release-on-tag.yml
How to create a release:
# Tag with semantic version (e.g., v1.0.0, v2.1.3, v1.0.0-beta.1)
git tag -a v1.0.0 -m "Release v1.0.0: Initial production release"
git push origin v1.0.0What happens automatically:
- Tests run first - Release aborts if any tests fail
- Docker images built and published to GitHub Container Registry:
ghcr.io/sero583/java_survey_app-cloud_computing_2025-webserver:v1.0.0ghcr.io/sero583/java_survey_app-cloud_computing_2025-database:v1.0.0- Both also tagged as
:latest
- Production-ready
docker-compose-v1.0.0.ymlgenerated and attached - GitHub Release created with:
- Auto-generated release notes
- Docker Compose file for one-command deployment
- Clear instructions for users
Release Artifacts:
| Artifact | Purpose |
|---|---|
docker-compose-vX.X.X.yml |
Ready-to-use deployment file - just download and run |
ghcr.io/.../webserver:vX.X.X |
Spring Boot application image |
ghcr.io/.../database:vX.X.X |
PostgreSQL database image |
View releases: GitHub Releases page
New users can deploy the app with just two commands:
Linux/macOS:
# Download the Docker Compose file for your chosen version
curl -sL https://github.com/sero583/java_survey_app-cloud_computing_2025/releases/download/v1.0.0/docker-compose-v1.0.0.yml -o docker-compose.yml
# Start the application
docker compose up -dWindows PowerShell:
# Download the Docker Compose file for your chosen version
Invoke-WebRequest -Uri "https://github.com/sero583/java_survey_app-cloud_computing_2025/releases/download/v1.0.0/docker-compose-v1.0.0.yml" -OutFile "docker-compose.yml"
# Start the application
docker compose up -dThen open http://localhost in your browser.
Test CI workflow:
Windows:
# With act (requires Docker)
act -j build
# Or run Maven directly
.\mvnw.cmd -B -ntp verifyLinux/macOS:
# With act (requires Docker)
act -j build
# Or run Maven directly
./mvnw -B -ntp verifyBuild Docker images locally (all platforms):
# Build images from source
docker compose build
# Or build and run
docker compose up --buildFollow Semantic Versioning:
- Major: Breaking changes (
v2.0.0) - Minor: New features, backwards compatible (
v1.1.0) - Patch: Bug fixes (
v1.0.1) - Pre-release: Beta/RC versions (
v1.0.0-beta.1,v1.0.0-rc.2)
Examples:
# First production release
git tag -a v1.0.0 -m "Release v1.0.0"
# Bug fix release
git tag -a v1.0.1 -m "Fix: QR code generation issue"
# New feature release
git tag -a v1.1.0 -m "Feature: Export results to CSV"
# Breaking change
git tag -a v2.0.0 -m "Breaking: New database schema"Note: Always push tags after commits: git push origin <tag-name>
For production deployment, the following enhancements should be implemented:
- HTTPS/TLS: Use Let's Encrypt or cloud provider certificates for SSL/TLS encryption
- Secrets Management: Store database credentials in AWS Secrets Manager, Azure Key Vault, or HashiCorp Vault
- CORS Configuration: Restrict allowed origins for API endpoints
- Input Validation: Add comprehensive input sanitization and validation
- Container Security: Non-root users in all containers
- Resource Isolation: CPU and memory limits on all services
- Horizontal Scaling: Use Kubernetes or Docker Swarm for auto-scaling based on load
- Database Connection Pooling: Fine-tune HikariCP configuration for optimal performance
- Caching: Implement Redis for session management and frequently accessed data
- CDN Integration: Serve static assets via CloudFront or similar CDN
- Logging: Centralized logging with ELK Stack (Elasticsearch, Logstash, Kibana) or Splunk
- Monitoring: Application metrics with Prometheus and Grafana (extend Actuator with Micrometer)
- Distributed Tracing: Implement OpenTelemetry or Jaeger for microservices tracing
- Health Checks: Implemented with Spring Boot Actuator and HAProxy integration
- Application health endpoint:
/actuator/health - Database connectivity monitoring
- HAProxy backend health checks with automatic failover
- Application health endpoint:
- Load Balancing: Implemented with HAProxy round-robin and health-based routing
- Database Replication: PostgreSQL primary-replica setup with automatic failover
- Load Balancer Redundancy: Multiple HAProxy instances or managed cloud load balancers
- Backup & Recovery: Automated database backups with point-in-time recovery
- Circuit Breakers: Implement Resilience4j for fault tolerance
This project is licensed under the MIT License - see the LICENSE file for details.
Serhat Güler — @sero583
Originally developed for the Cloud Computing course (SS2025), enhanced and published as a portfolio project.




