From 9266785fdb99f412743d69672ab5ba507724ccfe Mon Sep 17 00:00:00 2001 From: "laurent.deleers@gmail.com" Date: Sat, 7 Feb 2026 21:56:36 +0100 Subject: [PATCH] autocomit --- Dockerfile | 188 ++++++++++++++++++ Makefile | 36 ++-- .../java/com/ldpv2/config/SecurityConfig.java | 9 +- 3 files changed, 211 insertions(+), 22 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..952e336 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,188 @@ +# ============================================================================= +# Multi-stage Dockerfile - LDPv2 Unified Container +# Builds frontend, backend, and serves both through nginx in a single container +# ============================================================================= + +# ============================================================================= +# Stage 1: Build Angular Frontend +# ============================================================================= +FROM node:18-alpine AS frontend-build + +WORKDIR /app/frontend + +# Copy frontend package files and install dependencies +COPY frontend/package*.json ./ +RUN npm install --only=production + +# Copy frontend source and build +COPY frontend/ ./ +RUN npm run build + +# ============================================================================= +# Stage 2: Build Spring Boot Backend +# ============================================================================= +FROM maven:3.9-eclipse-temurin-17-alpine AS backend-build + +WORKDIR /app/backend + +# Copy Maven configuration and download dependencies (cached layer) +COPY backend/pom.xml ./ +RUN mvn dependency:go-offline -B + +# Copy backend source and build +COPY backend/src ./src +RUN mvn clean package -DskipTests + +# ============================================================================= +# Stage 3: Final Runtime Container +# Combines nginx (for frontend + routing), JRE (for backend), and supervisord +# ============================================================================= +FROM eclipse-temurin:17-jre-alpine + +# Install nginx and supervisord +RUN apk add --no-cache nginx supervisor wget + +# Create necessary directories +RUN mkdir -p /app/backend \ + /app/frontend \ + /var/log/supervisor \ + /run/nginx + +# ----------------------------------------------------------------------------- +# Copy built artifacts from previous stages +# ----------------------------------------------------------------------------- + +# Copy Spring Boot JAR from backend build +COPY --from=backend-build /app/backend/target/*.jar /app/backend/app.jar + +# Copy built Angular app from frontend build +COPY --from=frontend-build /app/frontend/dist/ldpv2-frontend/browser /app/frontend + +# ----------------------------------------------------------------------------- +# Configure nginx +# ----------------------------------------------------------------------------- + +# Remove default nginx configuration +RUN rm -f /etc/nginx/http.d/default.conf + +# Copy custom nginx configuration +COPY <<'EOF' /etc/nginx/http.d/ldpv2.conf +server { + listen 80; + server_name localhost; + root /app/frontend; + index index.html; + + # Gzip compression + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + gzip_min_length 1000; + gzip_comp_level 6; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + + # API proxy to backend (running on localhost:8080) + location /api/ { + proxy_pass http://127.0.0.1:8080/api/; + proxy_http_version 1.1; + + # Headers + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # WebSocket support + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_cache_bypass $http_upgrade; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # Handle OPTIONS requests for CORS preflight + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Accept'; + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + } + + # Angular routes - fallback to index.html for SPA + location / { + try_files $uri $uri/ /index.html; + } + + # Cache static assets + location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + access_log off; + } + + # Don't log favicon requests + location = /favicon.ico { + log_not_found off; + access_log off; + } +} +EOF + +# ----------------------------------------------------------------------------- +# Configure supervisord to manage both nginx and Spring Boot +# ----------------------------------------------------------------------------- + +COPY <<'EOF' /etc/supervisord.conf +[supervisord] +nodaemon=true +user=root +logfile=/var/log/supervisor/supervisord.log +pidfile=/var/run/supervisord.pid +loglevel=info + +[program:backend] +command=java -jar /app/backend/app.jar +autostart=true +autorestart=true +startretries=10 +startsecs=30 +stdout_logfile=/var/log/supervisor/backend.log +stderr_logfile=/var/log/supervisor/backend-error.log +environment=JAVA_OPTS="-Xms256m -Xmx512m" + +[program:nginx] +command=nginx -g 'daemon off;' +autostart=true +autorestart=true +stdout_logfile=/var/log/supervisor/nginx.log +stderr_logfile=/var/log/supervisor/nginx-error.log +# Wait for backend to be ready before starting nginx +startsecs=45 +EOF + +# ----------------------------------------------------------------------------- +# Expose port and configure health check +# ----------------------------------------------------------------------------- + +EXPOSE 80 + +# Health check - check both nginx and backend +HEALTHCHECK --interval=30s --timeout=10s --start-period=90s --retries=3 \ + CMD wget --quiet --tries=1 --spider http://localhost:80/ && \ + wget --quiet --tries=1 --spider http://localhost:8080/api/actuator/health || exit 1 + +# ----------------------------------------------------------------------------- +# Start supervisord which manages both services +# ----------------------------------------------------------------------------- + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] diff --git a/Makefile b/Makefile index ad3fd6c..eb4a220 100644 --- a/Makefile +++ b/Makefile @@ -23,54 +23,54 @@ help: ## Display this help message build: ## Build all containers @echo "$(GREEN)Building containers...$(NC)" - docker-compose build + docker compose build build-no-cache: ## Build all containers without cache @echo "$(GREEN)Building containers (no cache)...$(NC)" - docker-compose build --no-cache + docker compose build --no-cache up: ## Start all containers @echo "$(GREEN)Starting containers...$(NC)" - docker-compose up + docker compose up up-build: ## Build and start all containers @echo "$(GREEN)Building and starting containers...$(NC)" - docker-compose up --build + docker compose up --build up-d: ## Start all containers in background @echo "$(GREEN)Starting containers in background...$(NC)" - docker-compose up -d + docker compose up -d down: ## Stop and remove all containers @echo "$(YELLOW)Stopping containers...$(NC)" - docker-compose down + docker compose down down-v: ## Stop containers and remove volumes (WARNING: deletes database!) @echo "$(RED)Stopping containers and removing volumes...$(NC)" @read -p "This will delete the database. Are you sure? [y/N] " -n 1 -r; \ echo; \ if [[ $$REPLY =~ ^[Yy]$$ ]]; then \ - docker-compose down -v; \ + docker compose down -v; \ fi restart: ## Restart all containers @echo "$(YELLOW)Restarting containers...$(NC)" - docker-compose restart + docker compose restart restart-app: ## Restart only the app container @echo "$(YELLOW)Restarting app container...$(NC)" - docker-compose restart app + docker compose restart app ##@ Logs and Monitoring logs: ## Show logs from all containers - docker-compose logs -f + docker compose logs -f logs-app: ## Show logs from app container only - docker-compose logs -f app + docker compose logs -f app logs-postgres: ## Show logs from postgres container only - docker-compose logs -f postgres + docker compose logs -f postgres logs-backend: ## Show backend application logs @echo "$(GREEN)Showing backend logs (Ctrl+C to exit)...$(NC)" @@ -140,7 +140,7 @@ test-nginx: ## Test nginx configuration clean: ## Remove all stopped containers and unused images @echo "$(YELLOW)Cleaning up...$(NC)" - docker-compose down + docker compose down docker system prune -f @echo "$(GREEN)Cleanup complete!$(NC)" @@ -149,7 +149,7 @@ clean-all: ## Remove everything including volumes (WARNING: deletes database!) @read -p "Are you sure? [y/N] " -n 1 -r; \ echo; \ if [[ $$REPLY =~ ^[Yy]$$ ]]; then \ - docker-compose down -v; \ + docker compose down -v; \ docker system prune -af; \ echo "$(GREEN)Full cleanup complete!$(NC)"; \ fi @@ -165,14 +165,14 @@ reset: ## Complete reset (rebuild everything) prod-deploy: ## Deploy for production (builds and starts in background) @echo "$(GREEN)Deploying for production...$(NC)" - docker-compose -f docker-compose.yml -f docker-compose.prod.yml up --build -d + docker compose -f docker-compose.yml -f docker-compose.prod.yml up --build -d @echo "$(GREEN)Production deployment complete!$(NC)" prod-logs: ## Show production logs - docker-compose -f docker-compose.yml -f docker-compose.prod.yml logs -f + docker compose -f docker-compose.yml -f docker-compose.prod.yml logs -f prod-down: ## Stop production deployment - docker-compose -f docker-compose.yml -f docker-compose.prod.yml down + docker compose -f docker-compose.yml -f docker-compose.prod.yml down ##@ Quick Actions @@ -212,6 +212,6 @@ info: ## Show container information version: ## Show version information @echo "$(GREEN)LDPv2 Version Information$(NC)" @echo "Docker: $$(docker --version)" - @echo "Docker Compose: $$(docker-compose --version)" + @echo "Docker Compose: $$(docker compose version)" @echo "Java (in container): $$(docker exec ldpv2-app java -version 2>&1 | head -n 1 || echo 'Not running')" @echo "Node (build): $$(node --version 2>/dev/null || echo 'Not available')" diff --git a/backend/src/main/java/com/ldpv2/config/SecurityConfig.java b/backend/src/main/java/com/ldpv2/config/SecurityConfig.java index 7424a33..34f3749 100644 --- a/backend/src/main/java/com/ldpv2/config/SecurityConfig.java +++ b/backend/src/main/java/com/ldpv2/config/SecurityConfig.java @@ -41,9 +41,10 @@ public class SecurityConfig { .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth - .requestMatchers("/api/auth/**").permitAll() - .requestMatchers("/api/public/**").permitAll() + .requestMatchers("/auth/**").permitAll() + .requestMatchers("/public/**").permitAll() .requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/swagger-ui.html").permitAll() + .requestMatchers("/actuator/**").permitAll() .anyRequest().authenticated() ) .authenticationProvider(authenticationProvider()) @@ -55,7 +56,7 @@ public class SecurityConfig { @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200", "http://localhost:3000")); + configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200", "http://localhost:3000", "http://localhost")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH")); configuration.setAllowedHeaders(Arrays.asList("*")); configuration.setAllowCredentials(true); @@ -83,4 +84,4 @@ public class SecurityConfig { public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception { return authConfig.getAuthenticationManager(); } -} +} \ No newline at end of file