Skip to content

Commit d7088c9

Browse files
committed
Publish QR code survey application
0 parents  commit d7088c9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+4999
-0
lines changed

.dockerignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.idea
2+
.git
3+
node_modules
4+
target
5+
dist
6+
*.iml
7+
*.log
8+
.DS_Store
9+
*.tmp
10+
__pycache__
11+
.vscode
12+
*.swp
13+
*.bak
14+
OneDrive
15+
OneDrive*

.env.example

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Application Base URL (used for generating links and QR codes)
2+
APP_BASE_URL=http://localhost
3+
4+
# Spring Boot Database Configuration (used by the application)
5+
SPRING_DATASOURCE_URL=jdbc:postgresql://database:5432/surveydb
6+
SPRING_DATASOURCE_USERNAME=postgres
7+
SPRING_DATASOURCE_PASSWORD=test123
8+
9+
# Database Configuration (used by the Postgres container)
10+
POSTGRES_USER=postgres
11+
POSTGRES_PASSWORD=test123
12+
POSTGRES_DB=surveydb
13+
14+
# (Optional) Spring Boot JPA settings (uncomment to override defaults)
15+
# SPRING_JPA_HIBERNATE_DDL_AUTO=update
16+
# SPRING_JPA_SHOW_SQL=true
17+
18+
# (Optional) Logging configuration
19+
# LOGGING_LEVEL_ROOT=INFO
20+
# LOGGING_LEVEL_ORG_SPRINGFRAMEWORK=DEBUG

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/mvnw text eol=lf
2+
*.cmd text eol=crlf

.github/workflows/ci.yml

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
permissions:
10+
contents: read
11+
checks: write
12+
pull-requests: write
13+
14+
jobs:
15+
build:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v4
20+
21+
- name: Set up Java 21
22+
uses: actions/setup-java@v4
23+
with:
24+
distribution: 'temurin'
25+
java-version: '21'
26+
cache: 'maven'
27+
28+
- name: Fix mvnw line endings (Windows CRLF to LF)
29+
run: sed -i 's/\r$//' mvnw
30+
31+
- name: Make mvnw executable
32+
run: chmod +x mvnw
33+
34+
# Build + test + coverage
35+
- name: Build and test
36+
run: ./mvnw -B -ntp verify
37+
38+
- name: Publish Test Report
39+
uses: mikepenz/action-junit-report@v4
40+
if: always()
41+
with:
42+
report_paths: '**/target/surefire-reports/TEST-*.xml'
43+
detailed_summary: true
44+
include_passed: true
45+
46+
- name: Add coverage to PR
47+
id: jacoco
48+
uses: madrapps/jacoco-report@v1.6.1
49+
if: github.event_name == 'pull_request'
50+
with:
51+
paths: ${{ github.workspace }}/target/site/jacoco/jacoco.xml
52+
token: ${{ secrets.GITHUB_TOKEN }}
53+
min-coverage-overall: 80
54+
min-coverage-changed-files: 80
55+
56+
- name: Upload surefire reports
57+
if: always()
58+
uses: actions/upload-artifact@v4
59+
with:
60+
name: surefire-reports
61+
path: target/surefire-reports/
62+
63+
- name: Upload JaCoCo site
64+
if: always()
65+
uses: actions/upload-artifact@v4
66+
with:
67+
name: jacoco-site
68+
path: target/site/jacoco/
69+
70+
# Extract test results for dynamic badge
71+
- name: Extract test results
72+
id: test_results
73+
if: always()
74+
shell: bash
75+
run: |
76+
TESTS_TOTAL=$(find target/surefire-reports -name "TEST-*.xml" -exec grep -h "tests=" {} \; | head -1 | sed 's/.*tests="\([0-9]*\)".*/\1/')
77+
TESTS_FAILURES=$(find target/surefire-reports -name "TEST-*.xml" -exec grep -h "failures=" {} \; | head -1 | sed 's/.*failures="\([0-9]*\)".*/\1/')
78+
TESTS_ERRORS=$(find target/surefire-reports -name "TEST-*.xml" -exec grep -h "errors=" {} \; | head -1 | sed 's/.*errors="\([0-9]*\)".*/\1/')
79+
TESTS_PASSING=$((TESTS_TOTAL - TESTS_FAILURES - TESTS_ERRORS))
80+
echo "tests=$TESTS_PASSING/$TESTS_TOTAL" >> $GITHUB_OUTPUT
81+
echo "color=$( [ $TESTS_FAILURES -eq 0 ] && [ $TESTS_ERRORS -eq 0 ] && echo 'brightgreen' || echo 'red' )" >> $GITHUB_OUTPUT
82+
83+
# Extract coverage for dynamic badge
84+
- name: Extract coverage
85+
id: coverage
86+
if: always()
87+
shell: bash
88+
run: |
89+
COVERAGE=$(grep -oP 'Total.*?<td class="ctr2">\K[0-9]+(?=%)' target/site/jacoco/index.html || echo "0")
90+
echo "percentage=$COVERAGE" >> $GITHUB_OUTPUT
91+
COLOR="red"
92+
if [ "$COVERAGE" -ge 80 ]; then COLOR="brightgreen"; elif [ "$COVERAGE" -ge 60 ]; then COLOR="yellow"; elif [ "$COVERAGE" -ge 40 ]; then COLOR="orange"; fi
93+
echo "color=$COLOR" >> $GITHUB_OUTPUT
94+
95+
# Update test count badge
96+
- name: Update test badge
97+
if: always()
98+
uses: Schneegans/dynamic-badges-action@v1.7.0
99+
with:
100+
auth: ${{ secrets.GIST_SECRET }}
101+
gistID: 581400f33ab11ae0a60e3b76968544bd
102+
filename: java-survey-app-test-count.json
103+
label: tests
104+
message: ${{ steps.test_results.outputs.tests }}
105+
color: ${{ steps.test_results.outputs.color }}
106+
107+
# Update coverage badge
108+
- name: Update coverage badge
109+
if: always()
110+
uses: Schneegans/dynamic-badges-action@v1.7.0
111+
with:
112+
auth: ${{ secrets.GIST_SECRET }}
113+
gistID: 581400f33ab11ae0a60e3b76968544bd
114+
filename: java-survey-app-coverage.json
115+
label: coverage
116+
message: ${{ steps.coverage.outputs.percentage }}%
117+
color: ${{ steps.coverage.outputs.color }}
118+
119+
# Update CI status badge
120+
- name: Update CI status badge
121+
if: always()
122+
uses: Schneegans/dynamic-badges-action@v1.7.0
123+
with:
124+
auth: ${{ secrets.GIST_SECRET }}
125+
gistID: 581400f33ab11ae0a60e3b76968544bd
126+
filename: java-survey-app-ci-status.json
127+
label: CI
128+
message: ${{ job.status }}
129+
color: ${{ job.status == 'success' && 'brightgreen' || 'red' }}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
name: Release on Tag
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*.*.*'
7+
8+
permissions:
9+
contents: write
10+
packages: write
11+
12+
env:
13+
REGISTRY: ghcr.io
14+
IMAGE_NAME_WEB: ${{ github.repository }}-webserver
15+
IMAGE_NAME_DB: ${{ github.repository }}-database
16+
17+
jobs:
18+
build-and-release:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
with:
24+
fetch-depth: 0
25+
26+
- name: Set up Java 21
27+
uses: actions/setup-java@v4
28+
with:
29+
distribution: 'temurin'
30+
java-version: '21'
31+
cache: 'maven'
32+
33+
- name: Fix mvnw line endings (Windows CRLF to LF)
34+
run: sed -i 's/\r$//' mvnw
35+
36+
- name: Make mvnw executable
37+
run: chmod +x mvnw
38+
39+
- name: Extract version from tag
40+
id: get_version
41+
run: |
42+
# Remove 'v' prefix from tag (e.g., v1.2.3 -> 1.2.3)
43+
VERSION=${GITHUB_REF#refs/tags/v}
44+
echo "version=$VERSION" >> $GITHUB_OUTPUT
45+
echo "Building version: $VERSION"
46+
47+
- name: Build and test (with coverage)
48+
run: ./mvnw -B -ntp verify -Drevision=${{ steps.get_version.outputs.version }}
49+
50+
- name: Set up Docker Buildx
51+
uses: docker/setup-buildx-action@v3
52+
53+
- name: Log in to GitHub Container Registry
54+
uses: docker/login-action@v3
55+
with:
56+
registry: ${{ env.REGISTRY }}
57+
username: ${{ github.actor }}
58+
password: ${{ secrets.GITHUB_TOKEN }}
59+
60+
- name: Extract tag name
61+
id: extract_tag
62+
run: echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
63+
64+
- name: Build and push webserver image
65+
uses: docker/build-push-action@v6
66+
with:
67+
context: .
68+
file: ./docker/webserver/Dockerfile
69+
push: true
70+
tags: |
71+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_WEB }}:${{ steps.extract_tag.outputs.tag }}
72+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_WEB }}:latest
73+
labels: |
74+
org.opencontainers.image.source=${{ github.repositoryUrl }}
75+
org.opencontainers.image.version=${{ steps.extract_tag.outputs.tag }}
76+
org.opencontainers.image.title=Survey App Webserver
77+
org.opencontainers.image.description=Spring Boot webserver for QR Code Based Survey Application
78+
79+
- name: Build and push database image
80+
uses: docker/build-push-action@v6
81+
with:
82+
context: .
83+
file: ./docker/db/Dockerfile
84+
push: true
85+
tags: |
86+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DB }}:${{ steps.extract_tag.outputs.tag }}
87+
${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DB }}:latest
88+
labels: |
89+
org.opencontainers.image.source=${{ github.repositoryUrl }}
90+
org.opencontainers.image.version=${{ steps.extract_tag.outputs.tag }}
91+
org.opencontainers.image.title=Survey App Database
92+
org.opencontainers.image.description=PostgreSQL database for QR Code Based Survey Application
93+
94+
- name: Prepare docker-compose.prod.yml with correct image tag
95+
run: |
96+
sed "s/\${IMAGE_TAG:-latest}/${{ steps.extract_tag.outputs.tag }}/g" docker-compose.prod.yml > docker-compose-${{ steps.extract_tag.outputs.tag }}.yml
97+
98+
- name: Create GitHub Release and Upload Assets
99+
uses: softprops/action-gh-release@v2
100+
with:
101+
generate_release_notes: true
102+
files: |
103+
docker-compose-${{ steps.extract_tag.outputs.tag }}.yml
104+
body: |
105+
## 🚀 Quick Start
106+
107+
**Option 1: One-Command Deploy (Recommended)**
108+
```bash
109+
# Download and run the complete stack
110+
curl -sL https://github.com/${{ github.repository }}/releases/download/${{ steps.extract_tag.outputs.tag }}/docker-compose-${{ steps.extract_tag.outputs.tag }}.yml -o docker-compose.yml
111+
docker compose up -d
112+
```
113+
Then open http://localhost in your browser.
114+
115+
**Option 2: Pull Images Manually**
116+
```bash
117+
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_WEB }}:${{ steps.extract_tag.outputs.tag }}
118+
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_DB }}:${{ steps.extract_tag.outputs.tag }}
119+
```
120+
121+
---
122+
123+
## 📦 Release Artifacts
124+
125+
| Artifact | Description |
126+
|----------|-------------|
127+
| `docker-compose-${{ steps.extract_tag.outputs.tag }}.yml` | Ready-to-use Docker Compose file with all services |
128+
| `ghcr.io/${{ env.IMAGE_NAME_WEB }}:${{ steps.extract_tag.outputs.tag }}` | Spring Boot webserver image |
129+
| `ghcr.io/${{ env.IMAGE_NAME_DB }}:${{ steps.extract_tag.outputs.tag }}` | PostgreSQL database image |
130+
131+
---
132+
133+
## ⚙️ Configuration
134+
135+
Create a `.env` file (optional) to customize:
136+
```env
137+
# Database credentials
138+
POSTGRES_USER=postgres
139+
POSTGRES_PASSWORD=your_secure_password
140+
POSTGRES_DB=surveydb
141+
142+
# Application URL (for QR codes)
143+
APP_BASE_URL=http://your-domain.com
144+
```
145+
146+
---
147+
148+
## 🏗️ Architecture
149+
150+
- **Load Balancer (HAProxy :80):** Routes traffic with health checks and automatic failover
151+
- **Webserver 1 & 2:** Spring Boot instances for high availability
152+
- **Database (PostgreSQL):** Persistent storage with automatic schema initialization
153+
154+
See the README for the full architecture diagram.

.gitignore

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
HELP.md
2+
3+
# Maven / Java
4+
target/
5+
!.mvn/wrapper/maven-wrapper.jar
6+
!**/src/main/**/target/
7+
!**/src/test/**/target/
8+
pom.xml.versionsBackup
9+
.flattened-pom.xml
10+
11+
# Build reports & coverage
12+
jacoco.exec
13+
target/surefire-reports/
14+
target/site/
15+
16+
### STS ###
17+
.apt_generated
18+
.classpath
19+
.factorypath
20+
.project
21+
.settings
22+
.springBeans
23+
.sts4-cache
24+
25+
### IntelliJ IDEA ###
26+
.idea/
27+
*.iws
28+
*.iml
29+
*.ipr
30+
31+
### NetBeans ###
32+
/nbproject/private/
33+
/nbbuild/
34+
/dist/
35+
/nbdist/
36+
/.nb-gradle/
37+
build/
38+
!**/src/main/**/build/
39+
!**/src/test/**/build/
40+
41+
### VS Code ###
42+
.vscode/
43+
44+
# Environment files
45+
.env
46+
*.env.local
47+
*.local
48+
49+
# Logs & temp
50+
log/
51+
log/application.log
52+
*.log
53+
tmp/
54+
55+
# Docker runtime data (optional; ensure not to commit local db data)
56+
docker/db/data/

0 commit comments

Comments
 (0)