Skip to content

Commit 3974be9

Browse files
authored
Merge pull request #14 from nkcoder/refactor/application_config
Refactor the application yml config for usage
2 parents 2fbf533 + d056304 commit 3974be9

15 files changed

+406
-138
lines changed

.env.example

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# =============================================================================
2+
# Environment Variables for docker-compose-all.yml
3+
# =============================================================================
4+
# Copy this file to .env and customize values for your environment.
5+
#
6+
# Usage:
7+
# cp .env.example .env
8+
# # Edit .env with your values
9+
# docker compose -f docker-compose-all.yml up -d
10+
#
11+
# SECURITY WARNING:
12+
# - Never commit .env to version control
13+
# - Use secrets management (Vault, AWS Secrets Manager) in production
14+
# =============================================================================
15+
16+
# Database password (used by both app and postgres containers)
17+
DB_PASSWORD=your_secure_password_here
18+
19+
# JWT secrets - MUST be at least 64 bytes for HS512
20+
# Generate with: openssl rand -base64 64
21+
JWT_ACCESS_SECRET=your-64-byte-access-secret-generated-with-openssl-rand-base64-64-command
22+
JWT_REFRESH_SECRET=your-64-byte-refresh-secret-generated-with-openssl-rand-base64-64-command
23+
24+
# CORS allowed origins (comma-separated for multiple)
25+
CORS_ALLOWED_ORIGINS=http://localhost:3000

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,9 @@ build
44
target
55
.DS_Store
66
logs
7-
!auto/build
7+
!auto/build
8+
9+
# Environment files (contain secrets)
10+
.env
11+
.env.local
12+
.env.*.local

Dockerfile

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,65 @@
1-
# Build stage
2-
FROM openjdk:21-jdk-slim AS build
1+
# =============================================================================
2+
# Multi-stage Dockerfile for Spring Boot Application
3+
# =============================================================================
4+
# Build: docker build -t user-service .
5+
# Run: docker run -p 3001:3001 -p 9090:9090 user-service
6+
# =============================================================================
7+
8+
# -----------------------------------------------------------------------------
9+
# Build Stage (use Eclipse Temurin with glibc for protoc compatibility)
10+
# -----------------------------------------------------------------------------
11+
FROM eclipse-temurin:25-jdk AS build
312

413
WORKDIR /app
514

6-
# Copy Gradle wrapper and buf-gen files
15+
# Copy Gradle wrapper and build files first (for layer caching)
716
COPY gradle/ gradle/
817
COPY gradlew build.gradle.kts ./
918

1019
# Make gradlew executable
1120
RUN chmod +x ./gradlew
1221

13-
# Copy source code
22+
# Download dependencies (cached layer if build files unchanged)
23+
RUN ./gradlew dependencies --no-daemon || true
24+
25+
# Copy source code (including proto files)
1426
COPY src ./src
1527

16-
# Build the application
28+
# Build the application (generateProto runs automatically, skip tests)
1729
RUN ./gradlew clean bootJar -x test --no-daemon
1830

19-
# Runtime stage
20-
FROM eclipse-temurin:21-jre
31+
# -----------------------------------------------------------------------------
32+
# Runtime Stage (use Alpine for smaller image size)
33+
# -----------------------------------------------------------------------------
34+
FROM eclipse-temurin:25-jre-alpine
35+
36+
# Add non-root user for security
37+
RUN addgroup -g 1001 -S appgroup && \
38+
adduser -u 1001 -S appuser -G appgroup
2139

2240
WORKDIR /app
2341

24-
# Copy JAR from buf-gen stage
25-
COPY --from=build /app/build/libs/user-service.jar user-service.jar
42+
# Copy JAR from build stage (matches bootJar archiveFileName in build.gradle.kts)
43+
COPY --from=build /app/build/libs/user-application.jar app.jar
44+
45+
# Change ownership to non-root user
46+
RUN chown -R appuser:appgroup /app
47+
48+
# Switch to non-root user
49+
USER appuser
50+
51+
# Expose REST and gRPC ports
52+
EXPOSE 3001 9090
53+
54+
# Health check
55+
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
56+
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/actuator/health || exit 1
2657

27-
# Expose port
28-
EXPOSE 3001
58+
# JVM optimizations for containers
59+
ENV JAVA_OPTS="-XX:+UseContainerSupport \
60+
-XX:MaxRAMPercentage=75.0 \
61+
-XX:InitialRAMPercentage=50.0 \
62+
-Djava.security.egd=file:/dev/./urandom"
2963

3064
# Run the application
31-
CMD ["java", "-jar", "user-service.jar"]
65+
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ A comprehensive user authentication and management service built with Java 21 an
2727

2828
## Tech Stack
2929

30-
- **Java 21** (Latest LTS)
31-
- **Spring Boot 3.5.3**
30+
- **Java 25** (Latest LTS)
31+
- **Spring Boot 4**
3232
- **Spring Security 6**
3333
- **Spring Data JPA**
3434
- **PostgreSQL 17**

auto/docker_logs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env sh
2+
3+
docker compose -f docker-compose-all.yml up -
File renamed without changes.

auto/docker_stop

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env sh
2+
3+
docker compose -f docker-compose-all.yml down

build.gradle.kts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ plugins {
55
id("io.spring.dependency-management") version "1.1.7"
66
id("org.graalvm.buildtools.native") version "0.11.1"
77
id("org.jetbrains.kotlin.jvm") version "2.2.21"
8-
id("io.swagger.core.v3.swagger-gradle-plugin") version "2.2.34"
98
id("org.flywaydb.flyway") version "11.11.1"
109
id("com.diffplug.spotless") version "8.1.0"
1110
id("com.google.protobuf") version "0.9.5"
@@ -64,12 +63,6 @@ dependencies {
6463
testImplementation("org.testcontainers:junit-jupiter")
6564
testImplementation("org.testcontainers:postgresql")
6665

67-
// Swagger
68-
implementation("io.swagger.core.v3:swagger-models:2.2.34")
69-
implementation("io.swagger.core.v3:swagger-core:2.2.34")
70-
implementation("jakarta.xml.bind:jakarta.xml.bind-api:4.0.2")
71-
runtimeOnly("org.glassfish.jaxb:jaxb-runtime:4.0.5")
72-
7366
// gRPC and Protobuf
7467
implementation("io.grpc:grpc-netty-shaded:1.77.0")
7568
implementation("io.grpc:grpc-protobuf:1.77.0")

docker-compose-all.yml

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,109 @@
1+
# =============================================================================
2+
# Docker Compose - Full Application Stack
3+
# =============================================================================
4+
# Simulates dev/prod environment with all services running in containers.
5+
#
6+
# Usage:
7+
# Start: docker compose -f docker-compose-all.yml up -d
8+
# Stop: docker compose -f docker-compose-all.yml down
9+
# Logs: docker compose -f docker-compose-all.yml logs -f user-service
10+
# Rebuild: docker compose -f docker-compose-all.yml up -d --build
11+
#
12+
# For production, use external secrets management (Vault, AWS Secrets Manager)
13+
# instead of environment variables in this file.
14+
# =============================================================================
15+
116
services:
17+
# ---------------------------------------------------------------------------
18+
# Application Service
19+
# ---------------------------------------------------------------------------
220
user-service:
321
build:
422
context: .
523
dockerfile: Dockerfile
24+
container_name: user-application
625
ports:
7-
- "3001:3001"
26+
- "3001:3001" # REST API
27+
- "9090:9090" # gRPC API
828
depends_on:
9-
- postgres
29+
postgres:
30+
condition: service_healthy
1031
environment:
11-
- SPRING_PROFILES_ACTIVE=docker
12-
- SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/users
13-
- SPRING_DATASOURCE_USERNAME=test_user_rw
14-
- SPRING_DATASOURCE_PASSWORD=test_user@pass01
15-
- JWT_ACCESS_SECRET=13483567-651e-410a-b79e-d4c1a66d3bd526b90300-0d1e-4d92-85e0-1747241d052d
16-
- JWT_REFRESH_SECRET=8878f2cc-616e-413a-9b72-2eb32d7bf55c332df003-da39-45b7-82b1-f5f0d3203375
17-
- CLIENT_URL=http://localhost:3000
18-
volumes:
19-
- ./logs:/app/logs
32+
# Profile: use 'dev' for development simulation, 'prod' for production
33+
- SPRING_PROFILES_ACTIVE=dev
34+
35+
# Database connection (matches dev/prod profile expectations)
36+
- DATABASE_URL=jdbc:postgresql://postgres:5432/users
37+
- DATABASE_USERNAME=app_user
38+
- DATABASE_PASSWORD=${DB_PASSWORD:-changeme_in_production}
39+
40+
# JWT secrets - MUST be overridden in production!
41+
# Generate with: openssl rand -base64 64
42+
- JWT_ACCESS_SECRET=${JWT_ACCESS_SECRET:-dev-only-access-secret-key-must-be-at-least-64-bytes-long-for-hs512}
43+
- JWT_REFRESH_SECRET=${JWT_REFRESH_SECRET:-dev-only-refresh-secret-key-must-be-at-least-64-bytes-long-for-hs512}
44+
45+
# CORS - adjust for your frontend URL
46+
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS:-http://localhost:3000}
47+
48+
# JVM options for container environment
49+
- JAVA_OPTS=-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0
50+
healthcheck:
51+
test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/actuator/health" ]
52+
interval: 30s
53+
timeout: 10s
54+
retries: 3
55+
start_period: 60s
56+
restart: unless-stopped
57+
deploy:
58+
resources:
59+
limits:
60+
cpus: '2'
61+
memory: 1G
62+
reservations:
63+
cpus: '0.5'
64+
memory: 512M
2065
networks:
21-
- user-network
66+
- app-network
2267

68+
# ---------------------------------------------------------------------------
69+
# PostgreSQL Database
70+
# ---------------------------------------------------------------------------
2371
postgres:
24-
image: postgres:17.5-alpine
72+
image: postgres:17-alpine
73+
container_name: user-application-db
2574
ports:
26-
- "54321:5432"
75+
- "54321:5432" # External port for debugging (remove in production)
2776
environment:
2877
- POSTGRES_DB=users
29-
- POSTGRES_USER=test_user_rw
30-
- POSTGRES_PASSWORD=test_user@pass01
78+
- POSTGRES_USER=app_user
79+
- POSTGRES_PASSWORD=${DB_PASSWORD:-changeme_in_production}
80+
# Performance tuning for container
81+
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
3182
volumes:
3283
- postgres_data:/var/lib/postgresql/data
84+
healthcheck:
85+
test: [ "CMD-SHELL", "pg_isready -U app_user -d users" ]
86+
interval: 10s
87+
timeout: 5s
88+
retries: 5
89+
start_period: 30s
90+
restart: unless-stopped
91+
deploy:
92+
resources:
93+
limits:
94+
cpus: '1'
95+
memory: 512M
96+
reservations:
97+
cpus: '0.25'
98+
memory: 256M
3399
networks:
34-
- user-network
100+
- app-network
35101

36102
volumes:
37103
postgres_data:
104+
name: user-service-postgres-data
38105

39106
networks:
40-
user-network:
41-
driver: bridge
107+
app-network:
108+
name: user-service-network
109+
driver: bridge

docker-compose.yml

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
1+
# =============================================================================
2+
# Docker Compose - Local Development (Database Only)
3+
# =============================================================================
4+
# Used by Spring Boot's Docker Compose integration when:
5+
# spring.docker.compose.enabled=true (in application-local.yml)
6+
#
7+
# This file is auto-detected and managed by Spring Boot.
8+
# The application runs on your host machine, only PostgreSQL runs in Docker.
9+
#
10+
# Usage:
11+
# ./gradlew bootRun --args='--spring.profiles.active=local'
12+
# (Spring Boot automatically starts/stops this compose file)
13+
#
14+
# Manual control:
15+
# Start: docker compose up -d
16+
# Stop: docker compose down
17+
# Reset: docker compose down -v (removes data volume)
18+
# =============================================================================
19+
120
services:
221
postgres:
3-
image: postgres:17.5-alpine
22+
image: postgres:17-alpine
23+
container_name: user-service-local-db
424
ports:
525
- "54321:5432"
626
environment:
@@ -9,12 +29,12 @@ services:
929
- POSTGRES_PASSWORD=test_user@pass01
1030
volumes:
1131
- postgres_data:/var/lib/postgresql/data
12-
networks:
13-
- user-network
32+
healthcheck:
33+
test: ["CMD-SHELL", "pg_isready -U test_user_rw -d users"]
34+
interval: 10s
35+
timeout: 5s
36+
retries: 5
1437

1538
volumes:
1639
postgres_data:
17-
18-
networks:
19-
user-network:
20-
driver: bridge
40+
name: user-service-local-postgres-data

0 commit comments

Comments
 (0)