diff --git a/.dockerignore b/.dockerignore index c78e54e3..2bbaa807 100644 --- a/.dockerignore +++ b/.dockerignore @@ -73,8 +73,8 @@ Thumbs.db config/.env .env.local .env.*.local -**/.env -**/.env.* +config/.env +config/.env.example # =================================================================== # Docker and Container files @@ -171,7 +171,7 @@ backup.sh # =================================================================== # Security and certificates (never include in builds) # =================================================================== -config/ssl/ +config/backend/infrastructure/ssl/ **/*.key **/*.pem **/*.p12 diff --git a/.gitignore b/.gitignore index e4d2cb84..55a23116 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ out/ .gradle/ **/build/ +# Kotlin +.kotlin/ + # IDE .idea/ *.iml diff --git a/.junie/guidelines/technology-guides/docker/docker-monitoring.md b/.junie/guidelines/technology-guides/docker/docker-monitoring.md index 71fc9e68..21112af4 100644 --- a/.junie/guidelines/technology-guides/docker/docker-monitoring.md +++ b/.junie/guidelines/technology-guides/docker/docker-monitoring.md @@ -176,7 +176,7 @@ docker-compose logs api-gateway | grep -i "took\|duration\|time" ### Alerting-Regeln ```yaml -# prometheus/alerts.yml +# prometheus/alerts.yaml groups: - name: meldestelle.rules rules: @@ -226,13 +226,13 @@ docker-compose exec grafana find /var/log -name "*.log" -exec truncate -s 0 {} \ ### Performance-Tuning ```yaml -# prometheus.yml - Optimierte Konfiguration +# prometheus.yaml - Optimierte Konfiguration global: scrape_interval: 15s evaluation_interval: 15s rule_files: - - "/etc/prometheus/alerts.yml" + - "/etc/prometheus/alerts.yaml" scrape_configs: - job_name: 'spring-boot' diff --git a/Makefile b/Makefile deleted file mode 100644 index 3ffad532..00000000 --- a/Makefile +++ /dev/null @@ -1,424 +0,0 @@ -# =================================================================== -# Meldestelle Docker Development Makefile -# Optimierte Befehle für containerised Entwicklung-Workflows -# =================================================================== - -# =================================================================== -# PHONY Target Declarations -# =================================================================== -.PHONY: help -.PHONY: dev-up dev-down dev-restart dev-logs dev-info dev-tools-up dev-tools-down -.PHONY: infrastructure-up infrastructure-down infrastructure-logs -.PHONY: services-up services-down services-restart services-logs -.PHONY: clients-up clients-down clients-restart clients-logs -.PHONY: full-up full-down full-restart full-logs -.PHONY: prod-up prod-down prod-restart prod-logs -.PHONY: env-setup env-dev env-prod env-staging env-test validate env-template -.PHONY: build build-service build-client clean clean-all -.PHONY: test test-e2e -.PHONY: status health-check logs shell -.PHONY: versions-show versions-update docker-sync docker-validate docker-compose-gen hooks-install - -.ONESHELL: - -# Modern Docker Compose CLI (plugin-based) -# Defaults to 'docker compose' as the legacy standalone tool is deprecated -COMPOSE = docker compose - -# Default target -.DEFAULT_GOAL := help -help: ## Show this help message - @echo "Meldestelle Docker Development Commands" - @echo "======================================" - @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) - -# =================================================================== -# Development Workflow Commands -# =================================================================== - -dev-up: ## Start development environment (single compose) - @echo "🚀 Starting development environment..." - $(COMPOSE) -f docker/docker-compose.yml up -d - @$(MAKE) dev-info - -dev-down: ## Stop development environment - @echo "🛑 Stopping development environment..." - $(COMPOSE) -f docker/docker-compose.yml down - -dev-restart: ## Restart full development environment - @$(MAKE) dev-down - @$(MAKE) dev-up - -dev-logs: ## Show logs for all development services - $(COMPOSE) -f docker/docker-compose.yml logs -f - -# =================================================================== -# Layer-specific Commands -# =================================================================== - -infrastructure-up: ## Start only infrastructure services (postgres, redis, keycloak, consul) - @echo "🏗️ Starting infrastructure services..." - $(COMPOSE) -f docker/docker-compose.yml up -d - @echo "✅ Infrastructure services started" - @echo "🗄️ PostgresQL: localhost:5432" - @echo "🔴 Redis: localhost:6379" - @echo "🔐 Keycloak: http://localhost:8180" - @echo "🧭 Consul: http://localhost:8500" - -infrastructure-down: ## Stop infrastructure services - $(COMPOSE) -f docker/docker-compose.yml down - -infrastructure-logs: ## Show infrastructure logs - $(COMPOSE) -f docker/docker-compose.yml logs -f - -services-up: ## Start application services (infrastructure + microservices) - @echo "⚙️ Starting application services..." - $(COMPOSE) -f docker/docker-compose.yml -f docker/docker-compose.services.yml up -d - @echo "✅ Application services started" - @echo "🔗 Gateway: http://localhost:8081" - @echo "🏓 Ping Service: http://localhost:8082" - @echo "👥 Members Service: http://localhost:8083" - @echo "🐎 Horses Service: http://localhost:8084" - @echo "🎯 Events Service: http://localhost:8085" - @echo "📊 Master Service: http://localhost:8086" - -services-down: ## Stop application services - $(COMPOSE) -f docker/docker-compose.yml -f docker/docker-compose.services.yml down - -services-restart: ## Restart application services - @$(MAKE) services-down - @$(MAKE) services-up - -services-logs: ## Show application services logs - $(COMPOSE) -f docker/docker-compose.yml -f docker/docker-compose.services.yml logs -f - -clients-up: ## Start client applications (infrastructure + clients) - @echo "💻 Starting client applications..." - $(COMPOSE) -f docker/docker-compose.yml -f docker/docker-compose.clients.yml up -d - @echo "✅ Client applications started" - @echo "🌐 Web App: http://localhost:4000" - @echo "🔐 Auth Server: http://localhost:8087" - @echo "📈 Monitoring: http://localhost:8088" - -clients-down: ## Stop client applications - $(COMPOSE) -f docker/docker-compose.yml -f docker/docker-compose.clients.yml down - -clients-restart: ## Restart client applications - @$(MAKE) clients-down - @$(MAKE) clients-up - -clients-logs: ## Show client application logs - $(COMPOSE) -f docker/docker-compose.yml -f docker/docker-compose.clients.yml logs -f - -# =================================================================== -# Full System Commands -# =================================================================== - -full-up: ## Start complete system (infrastructure + services + clients) - @echo "🚀 Starting complete Meldestelle system..." - $(COMPOSE) -f docker/docker-compose.yml -f docker/docker-compose.services.yml -f docker/docker-compose.clients.yml up -d - @echo "✅ Complete system started" - @echo "" - @echo "🌐 Frontend & APIs:" - @echo " Web App: http://localhost:4000" - @echo " API Gateway: http://localhost:8081" - @echo "" - @echo "🔧 Infrastructure:" - @echo " PostgresQL: localhost:5432" - @echo " Redis: localhost:6379" - @echo " Keycloak: http://localhost:8180" - @echo " Consul: http://localhost:8500" - @echo " Prometheus: http://localhost:9090" - @echo " Grafana: http://localhost:3000" - @echo "" - @echo "⚙️ Microservices:" - @echo " Ping Service: http://localhost:8082" - @echo " Members Service: http://localhost:8083" - @echo " Horses Service: http://localhost:8084" - @echo " Events Service: http://localhost:8085" - @echo " Master Service: http://localhost:8086" - @echo " Auth Server: http://localhost:8087" - @echo " Monitoring: http://localhost:8088" - -full-down: ## Stop complete system - $(COMPOSE) -f docker/docker-compose.yml -f docker/docker-compose.services.yml -f docker/docker-compose.clients.yml down - -full-restart: ## Restart complete system - @$(MAKE) full-down - @$(MAKE) full-up - -full-logs: ## Show all system logs - $(COMPOSE) -f docker/docker-compose.yml -f docker/docker-compose.services.yml -f docker/docker-compose.clients.yml logs -f - -# =================================================================== -# SSoT Developer UX (optional helpers) -# =================================================================== - -# Show current centralized versions from docker/versions.toml -versions-show: ## Show centralized versions (docker/versions.toml) - @bash scripts/docker-versions-update.sh show - -# Update a single version key and sync env files (usage: make versions-update key=gradle value=9.1.0) -versions-update: ## Update one key in versions.toml and sync env files (key= value=) - @if [ -z "$(key)" ] || [ -z "$(value)" ]; then \ - echo "Usage: make versions-update key= value="; \ - echo "Keys: gradle java node nginx alpine prometheus grafana keycloak app-version spring-profiles-default spring-profiles-docker"; \ - exit 1; \ - fi - @bash scripts/docker-versions-update.sh update $(key) $(value) - -# Sync versions.toml into docker/build-args/*.env -docker-sync: ## Sync versions.toml -> build-args/*.env - @bash scripts/docker-versions-update.sh sync - -# Generate all compose files for selected environment (ENV=development|production|testing) -ENV ?= development - -docker-compose-gen: ## Generate docker-compose files from SSoT (ENV=development|production|testing) - @bash scripts/generate-compose-files.sh all $(ENV) - -# Run full Docker SSoT validation -docker-validate: ## Validate SSoT (dockerfiles, compose, ports, build-args, drift) - @bash scripts/validate-docker-consistency.sh all - -# Install optional pre-commit hook for SSoT guard -hooks-install: ## Install pre-commit SSoT guard hook into .git/hooks/pre-commit - @mkdir -p .git/hooks - @cp scripts/git-hooks/pre-commit-ssot .git/hooks/pre-commit - @chmod +x .git/hooks/pre-commit - @echo "✅ Installed .git/hooks/pre-commit (SSoT guard)" - -# =================================================================== -# Environment Configuration Commands -# =================================================================== - -env-setup: ## Show environment setup instructions - @echo "🔧 Umgebungskonfiguration - Environment Setup" - @echo "==============================================" - @echo "" - @echo "Verfügbare Umgebungen:" - @echo " make env-dev - Entwicklungsumgebung" - @echo " make env-prod - Produktionsumgebung" - @echo " make env-staging - Staging-Umgebung" - @echo " make env-test - Testumgebung" - @echo "" - @echo "Aktuelle Konfiguration:" - @ls -la .env 2>/dev/null || echo " Keine .env Datei gefunden - führe 'make env-dev' aus" - -env-dev: ## Switch to development environment - @echo "🔧 Switching to development environment..." - @ln -sf config/.env.dev .env - @echo "✅ Development environment activated (.env -> config/.env.dev)" - @echo "Debug mode: enabled, CORS: permissive, Logging: verbose" - -env-prod: ## Switch to production environment - @echo "🔧 Switching to production environment..." - @ln -sf config/.env.prod .env - @echo "✅ Production environment activated (.env -> config/.env.prod)" - @echo "⚠️ WICHTIG: Überprüfen Sie alle CHANGE_ME Werte in .env!" - -env-staging: ## Switch to staging environment - @echo "🔧 Switching to staging environment..." - @ln -sf config/.env.staging .env - @echo "✅ Staging environment activated (.env -> config/.env.staging)" - @echo "Production-like settings with moderate resources" - -env-test: ## Switch to test environment - @echo "🔧 Switching to test environment..." - @ln -sf config/.env.test .env - @echo "✅ Test environment activated (.env -> config/.env.test)" - @echo "Optimized for automated testing with alternative ports" - -validate: ## Validate Docker Compose configuration and environment - @echo "🔍 Validating configuration..." - @if [ ! -f .env ]; then echo "❌ No .env file found! Run 'make env-dev' first."; exit 1; fi - @echo "✅ Environment file exists" - @$(COMPOSE) config --quiet && echo "✅ Docker Compose configuration is valid" || echo "❌ Docker Compose configuration has errors" - @echo "✅ Validation completed" - -# =================================================================== -# Production Commands -# =================================================================== - -prod-up: ## Start production environment - @echo "🚀 Starting production environment..." - @echo "⚠️ Make sure environment variables are properly set!" - @if [ ! -f .env ]; then echo "❌ No .env file found! Run 'make env-prod' first."; exit 1; fi - $(COMPOSE) -f docker-compose.yml -f docker-compose.services.yml up -d - @echo "✅ Production environment started" - -prod-down: ## Stop production environment - $(COMPOSE) -f docker-compose.yml -f docker-compose.services.yml down - -prod-restart: ## Restart production environment - @$(MAKE) prod-down - @$(MAKE) prod-up - -prod-logs: ## Show production logs - $(COMPOSE) -f docker-compose.yml -f docker-compose.services.yml logs -f - -# =================================================================== -# Development Tools -# =================================================================== - -dev-tools-up: ## Info: development tool containers were removed (use local tools instead) - @echo "ℹ️ Development tool containers are not part of the simplified setup." - @echo "Use your local tools instead (e.g., pgAdmin, TablePlus, DBeaver, RedisInsight)." - @echo "Connection hints:" - @echo " PostgresQL: localhost:5432 (user/password per .env or defaults)" - @echo " Redis: localhost:6379" - @echo " Consul: http://localhost:8500" - @echo " Keycloak: http://localhost:8180" - -dev-tools-down: ## Info: nothing to stop for dev tools in simplified setup - @echo "ℹ️ No dev-tool containers to stop in the simplified setup." - -# =================================================================== -# Build and Maintenance Commands -# =================================================================== - -build: ## Build all custom Docker images (simplified) - @echo "🔨 Building all custom Docker images (using docker-compose.yml)..." - $(COMPOSE) -f docker-compose.yml build --no-cache - -build-service: ## Build specific service (usage: make build-service SERVICE=auth-server) - @test -n "$(SERVICE)" || (echo "❌ SERVICE parameter required. Usage: make build-service SERVICE=auth-server"; exit 1) - @echo "🔨 Building $(SERVICE)..." - $(COMPOSE) -f docker-compose.yml build --no-cache $(SERVICE) - -build-client: ## Build specific client (usage: make build-client CLIENT=web-app) - @test -n "$(CLIENT)" || (echo "❌ CLIENT parameter required. Usage: make build-client CLIENT=web-app"; exit 1) - @echo "🔨 Building $(CLIENT)..." - $(COMPOSE) -f docker-compose.yml build --no-cache $(CLIENT) - -clean: ## Clean up Docker resources - @echo "🧹 Cleaning up Docker resources..." - docker system prune -f - docker volume prune -f - docker network prune -f - @echo "✅ Cleanup completed" - -clean-all: ## Clean up all Docker resources (including images) - @echo "🧹 Cleaning up all Docker resources..." - docker system prune -af --volumes - @echo "✅ Complete cleanup finished" - -# =================================================================== -# Monitoring and Debugging Commands -# =================================================================== - -status: ## Show status of all containers - @echo "📊 Container Status:" - $(COMPOSE) -f docker-compose.yml ps - -health-check: ## Check health of core infrastructure services - @echo "🏥 Health Check Results:" - @echo "========================" - @$(COMPOSE) ps - @echo "-- Postgres --" - @$(COMPOSE) exec -T postgres pg_isready -U meldestelle -d meldestelle >/dev/null \ - && echo "PostgresQL: ✅ Ready" || echo "PostgresQL: ❌ Not ready" - @echo "-- Redis --" - @$(COMPOSE) exec -T redis redis-cli ping | grep -q PONG \ - && echo "Redis: ✅ PONG" || echo "Redis: ❌ Not responding" - @echo "-- Consul --" - @curl -sf http://localhost:8500/v1/status/leader >/dev/null \ - && echo "Consul: ✅ Leader elected" || echo "Consul: ❌ Not accessible" - @echo "-- Keycloak --" - @curl -sf http://localhost:8180/health/ready >/dev/null \ - && echo "Keycloak: ✅ Ready" || echo "Keycloak: ❌ Not accessible" - -logs: ## Show logs for specific service (usage: make logs SERVICE=postgres) - @test -n "$(SERVICE)" || (echo "❌ SERVICE parameter required. Usage: make logs SERVICE=postgres"; exit 1) - $(COMPOSE) logs -f $(SERVICE) - -shell: ## Open shell in specific container (usage: make shell SERVICE=postgres) - @test -n "$(SERVICE)" || (echo "❌ SERVICE parameter required. Usage: make shell SERVICE=postgres"; exit 1) - $(COMPOSE) exec $(SERVICE) sh - -# =================================================================== -# Testing Commands -# =================================================================== - -test: ## Run integration tests - @echo "🧪 Running integration tests..." - @$(MAKE) infrastructure-up - @echo "⏳ Waiting for services to be ready..." - @sleep 10 - @$(MAKE) health-check || true - @echo "✅ Running test suite..." - @./gradlew test || (echo "❌ Tests failed"; $(MAKE) infrastructure-down; exit 1) - @$(MAKE) infrastructure-down - @echo "✅ Integration tests completed successfully" - -test-e2e: ## Run end-to-end tests with full environment - @echo "🧪 Running end-to-end tests..." - @$(MAKE) dev-up - @echo "⏳ Waiting for full environment to be ready..." - @sleep 15 - @$(MAKE) health-check || true - @echo "✅ Running e2e test suite..." - @./gradlew :client:web-app:jsTest || (echo "❌ E2E tests failed"; $(MAKE) dev-down; exit 1) - @$(MAKE) dev-down - @echo "✅ E2E tests completed successfully" - -# =================================================================== -# Information and Help -# =================================================================== - -dev-info: ## Show development environment information - @echo "" - @echo "🚀 Meldestelle Development Environment Ready!" - @echo "=============================================" - @echo "" - @echo "🧭 Service Discovery:" - @echo " Consul: http://localhost:8500" - @echo "" - @echo "🔐 Authentication:" - @echo " Keycloak: http://localhost:8180 (admin/admin by default)" - @echo "" - @echo "🗄️ Infrastructure:" - @echo " PostgresQL: localhost:5432 (default user: meldestelle)" - @echo " Redis: localhost:6379" - @echo "" - @echo "ℹ️ Tips: Use 'make health-check' to verify services, and 'make logs SERVICE=postgres' for logs." - @echo "" - -env-template: ## Create .env template file - @echo "📝 Creating .env template..." - @cat > .env.template <<-'EOF' - # =================================================================== - # Meldestelle Environment Variables Template - # Copy to .env and customize for your environment - # =================================================================== - - # Database Configuration - POSTGRES_USER=meldestelle - POSTGRES_PASSWORD=meldestelle - POSTGRES_DB=meldestelle - - # Redis Configuration - REDIS_PASSWORD= - - # Keycloak Configuration - KEYCLOAK_ADMIN=admin - KEYCLOAK_ADMIN_PASSWORD=admin - KC_DB=postgres - KC_DB_URL=jdbc:postgresql://postgres:5432/keycloak - KC_DB_USERNAME=meldestelle - KC_DB_PASSWORD=meldestelle - - # JWT Configuration - JWT_SECRET=meldestelle-auth-secret-key-change-in-production - JWT_EXPIRATION=86400 - - # Monitoring Configuration - GF_SECURITY_ADMIN_USER=admin - GF_SECURITY_ADMIN_PASSWORD=admin - - # Production URLs (for production environment) - KC_HOSTNAME=auth.meldestelle.at - GRAFANA_HOSTNAME=monitor.meldestelle.at - PROMETHEUS_HOSTNAME=metrics.meldestelle.at - EOF - @echo "✅ .env.template created" diff --git a/backend/infrastructure/gateway/Dockerfile b/backend/infrastructure/gateway/Dockerfile index b78b0449..d41c3f05 100644 --- a/backend/infrastructure/gateway/Dockerfile +++ b/backend/infrastructure/gateway/Dockerfile @@ -57,19 +57,12 @@ RUN chmod +x gradlew COPY platform/ platform/ COPY core/ core/ -# Copy infrastructure directories (required by settings.gradle.kts) -# Copy infrastructure directories (required by settings.gradle.kts) -COPY infrastructure/ infrastructure/ - -# Copy domains directory (required by settings.gradle.kts) -COPY domains/ domains/ - -# Copy services directories (required by settings.gradle.kts) -COPY services/ services/ -COPY backend/ backend/ +# Copy backend/infrastructure directories (required by settings.gradle.kts) +COPY backend/infrastructure backend/infrastructure +COPY backend/services backend/services # Copy client directories (required by settings.gradle.kts) -COPY clients/ clients/ +COPY frontend/ frontend/ # Copy docs directory (required by settings.gradle.kts) COPY docs/ docs/ @@ -80,16 +73,16 @@ COPY build.gradle.kts ./ # Download and cache dependencies with BuildKit cache mount (removed deprecated flag) RUN --mount=type=cache,target=/home/gradle/.gradle/caches \ --mount=type=cache,target=/home/gradle/.gradle/wrapper \ - ./gradlew :backend:gateway:dependencies --info + ./gradlew :backend:infrastructure:gateway:dependencies --info # Build the application with optimizations and build cache (removed deprecated flag) RUN --mount=type=cache,target=/home/gradle/.gradle/caches \ --mount=type=cache,target=/home/gradle/.gradle/wrapper \ - ./gradlew :backend:gateway:bootJar --info + ./gradlew :backend:infrastructure:gateway:bootJar --info # Extract JAR layers for better caching in runtime stage RUN mkdir -p build/dependency && \ - (cd build/dependency; java -Djarmode=layertools -jar /workspace/backend/gateway/build/libs/*.jar extract) + (cd build/dependency; java -Djarmode=layertools -jar /workspace/backend/infrastructure/gateway/build/libs/*.jar extract) # =================================================================== # Runtime Stage diff --git a/backend/infrastructure/gateway/src/main/resources/application.yml b/backend/infrastructure/gateway/src/main/resources/application.yml index e00a03e9..595caa73 100644 --- a/backend/infrastructure/gateway/src/main/resources/application.yml +++ b/backend/infrastructure/gateway/src/main/resources/application.yml @@ -1,6 +1,6 @@ # Port, auf dem das Gateway läuft server: - port: ${SERVER_PORT:8081} + port: ${GATEWAY_SERVER_PORT:8081} # Optimierte Netty-Konfiguration für reaktive Anwendungen netty: connection-timeout: 5s diff --git a/docker/monitoring/Dockerfile b/backend/infrastructure/monitoring/monitoring-server/Dockerfile similarity index 86% rename from docker/monitoring/Dockerfile rename to backend/infrastructure/monitoring/monitoring-server/Dockerfile index 104e1d27..feca7798 100644 --- a/docker/monitoring/Dockerfile +++ b/backend/infrastructure/monitoring/monitoring-server/Dockerfile @@ -46,16 +46,16 @@ COPY core/ core/ COPY build.gradle.kts ./ # Copy monitoring dependencies -COPY infrastructure/monitoring/monitoring-client/ infrastructure/monitoring/monitoring-client/ -COPY infrastructure/cache/ infrastructure/cache/ +COPY backend/infrastructure/monitoring/monitoring-client/ backend/infrastructure/monitoring/monitoring-client/ +COPY backend/infrastructure/cache/ backend/infrastructure/cache/ # Copy monitoring-server specific files -COPY infrastructure/monitoring/monitoring-server/build.gradle.kts infrastructure/monitoring/monitoring-server/ -COPY infrastructure/monitoring/monitoring-server/src/ infrastructure/monitoring/monitoring-server/src/ +COPY backend/infrastructure/monitoring/monitoring-server/ backend/infrastructure/monitoring/monitoring-server/ +COPY backend/infrastructure/monitoring/monitoring-server/src/ backend/infrastructure/monitoring/monitoring-server/src/ # Build application -RUN ./gradlew :infrastructure:monitoring:monitoring-server:dependencies --no-daemon --info -RUN ./gradlew :infrastructure:monitoring:monitoring-server:bootJar --no-daemon --info +RUN ./gradlew :backend:infrastructure:monitoring:monitoring-server:dependencies --no-daemon --info +RUN ./gradlew :backend:infrastructure:monitoring:monitoring-server:bootJar --no-daemon --info # =================================================================== # Runtime Stage @@ -93,7 +93,7 @@ RUN mkdir -p /app/logs /app/tmp /app/config /app/metrics && \ # Copy the built JAR from builder stage COPY --from=builder --chown=${APP_USER}:${APP_GROUP} \ - /workspace/infrastructure/monitoring/monitoring-server/build/libs/*.jar app.jar + /workspace/backend/infrastructure/monitoring/monitoring-server/build/libs/*.jar app.jar # Switch to non-root user USER ${APP_USER} @@ -142,7 +142,7 @@ ENTRYPOINT ["sh", "-c", "\ # Build and Usage Instructions # =================================================================== # Build: -# docker build -t meldestelle/monitoring-server:latest -f infrastructure/monitoring/monitoring-server/Dockerfile . +# docker build -t meldestelle/monitoring-server:latest -f backend/infrastructure/monitoring/monitoring-server/Dockerfile . # # Run standalone: # docker run -p 8083:8083 --name monitoring-server meldestelle/monitoring-server:latest diff --git a/config/.env b/config/.env deleted file mode 100644 index 2d7b3215..00000000 --- a/config/.env +++ /dev/null @@ -1,8 +0,0 @@ -# DEPRECATED – Single Source of Truth moved to docker/.env -# -# This file is no longer used by Docker Compose or any build scripts. -# Please configure environment variables in: -# docker/.env (create from docker/.env.example) -# -# Reason: Avoid duplicated/conflicting configuration files. -# Monitoring, Postgres, Redis, Keycloak, Gateway etc. read values from docker/.env. diff --git a/config/.env.example b/config/.env.example index bbf53b5f..c9699719 100644 --- a/config/.env.example +++ b/config/.env.example @@ -1,7 +1,53 @@ -# DEPRECATED – Single Source of Truth moved to docker/.env.example -# -# This file is no longer used by Docker Compose or any build scripts. -# Please use and copy from: -# docker/.env.example → docker/.env -# -# Reason: Avoid duplicated/conflicting configuration files. +# ========================================== +# Meldestelle – Docker Compose Environment +# Single Source of Truth (SSoT) +# ========================================== + +# --- PROJECT --- +# COMPOSE_PROJECT_NAME=meldestelle + +# --- PORT MAPPINGS (host:container) --- +POSTGRES_PORT=5432:5432 +REDIS_PORT=6379:6379 +KC_PORT=8180:8080 +CONSUL_PORT=8500:8500 +PROMETHEUS_PORT=9090:9090 +GF_PORT=3000:3000 +WEB_APP_PORT=4000:80 +PING_SERVICE_PORT=8082:8082 +PING_DEBUG_PORT=5006:5006 +GATEWAY_PORT=8081:8081 +GATEWAY_DEBUG_PORT=5005:5005 +GATEWAY_SERVER_PORT=8081 +DESKTOP_APP_VNC_PORT=5900:5900 +DESKTOP_APP_NOVNC_PORT=6080:6080 + +# Postgres +POSTGRES_USER=meldestelle +POSTGRES_PASSWORD=meldestelle +POSTGRES_DB=meldestelle + +# --- REDIS --- +# Optional password for Redis; leave empty to disable authentication in dev +REDIS_PASSWORD= + +# --- KEYCLOAK --- +KC_ADMIN_USER=admin +KC_ADMIN_PASSWORD=admin +KC_HOSTNAME=localhost + +# --- PGADMIN --- +PGADMIN_EMAIL=admin@example.com +PGADMIN_PASSWORD=admin + +# --- GRAFANA --- +GF_ADMIN_USER=admin +GF_ADMIN_PASSWORD=admin + + +# Docker build versions (optional overrides) +DOCKER_GRADLE_VERSION=9.1.0 +DOCKER_JAVA_VERSION=21 +DOCKER_NODE_VERSION=22.21.0 +DOCKER_NGINX_VERSION=1.28.0-alpine +WEB_BUILD_PROFILE=dev diff --git a/config/detekt/detekt.yml b/config/backend/infrastructure/detekt/detekt.yml similarity index 100% rename from config/detekt/detekt.yml rename to config/backend/infrastructure/detekt/detekt.yml diff --git a/config/kafka/secrets/kafka_jaas.conf b/config/backend/infrastructure/kafka/secrets/kafka_jaas.conf similarity index 100% rename from config/kafka/secrets/kafka_jaas.conf rename to config/backend/infrastructure/kafka/secrets/kafka_jaas.conf diff --git a/config/kafka/secrets/zookeeper_jaas.conf b/config/backend/infrastructure/kafka/secrets/zookeeper_jaas.conf similarity index 100% rename from config/kafka/secrets/zookeeper_jaas.conf rename to config/backend/infrastructure/kafka/secrets/zookeeper_jaas.conf diff --git a/docker/core/keycloak/Dockerfile b/config/backend/infrastructure/keycloak/Dockerfile similarity index 95% rename from docker/core/keycloak/Dockerfile rename to config/backend/infrastructure/keycloak/Dockerfile index 14688dcf..464074ae 100644 --- a/docker/core/keycloak/Dockerfile +++ b/config/backend/infrastructure/keycloak/Dockerfile @@ -2,7 +2,7 @@ # =================================================================== # Production-Ready Keycloak Dockerfile # =================================================================== -# Based on: quay.io/keycloak/keycloak:26.4.2 +# Based on: quay.io/keycloak/keycloak:26.4 # Features: # - Pre-built optimized image (faster startup) # - Security hardening diff --git a/docker/core/keycloak/meldestelle-realm.json b/config/backend/infrastructure/keycloak/meldestelle-realm.json similarity index 100% rename from docker/core/keycloak/meldestelle-realm.json rename to config/backend/infrastructure/keycloak/meldestelle-realm.json diff --git a/config/monitoring/alertmanager/alertmanager.yml b/config/backend/infrastructure/monitoring/alertmanager/alertmanager.yml similarity index 100% rename from config/monitoring/alertmanager/alertmanager.yml rename to config/backend/infrastructure/monitoring/alertmanager/alertmanager.yml diff --git a/config/monitoring/elk/elasticsearch.yml b/config/backend/infrastructure/monitoring/elk/elasticsearch.yml similarity index 100% rename from config/monitoring/elk/elasticsearch.yml rename to config/backend/infrastructure/monitoring/elk/elasticsearch.yml diff --git a/config/monitoring/elk/logstash.conf b/config/backend/infrastructure/monitoring/elk/logstash.conf similarity index 100% rename from config/monitoring/elk/logstash.conf rename to config/backend/infrastructure/monitoring/elk/logstash.conf diff --git a/config/monitoring/grafana/dashboards/application-overview-dashboard.json b/config/backend/infrastructure/monitoring/grafana/dashboards/application-overview-dashboard.json similarity index 100% rename from config/monitoring/grafana/dashboards/application-overview-dashboard.json rename to config/backend/infrastructure/monitoring/grafana/dashboards/application-overview-dashboard.json diff --git a/config/monitoring/grafana/dashboards/infrastructure-dashboard.json b/config/backend/infrastructure/monitoring/grafana/dashboards/infrastructure-dashboard.json similarity index 100% rename from config/monitoring/grafana/dashboards/infrastructure-dashboard.json rename to config/backend/infrastructure/monitoring/grafana/dashboards/infrastructure-dashboard.json diff --git a/config/monitoring/grafana/dashboards/jvm-dashboard.json b/config/backend/infrastructure/monitoring/grafana/dashboards/jvm-dashboard.json similarity index 100% rename from config/monitoring/grafana/dashboards/jvm-dashboard.json rename to config/backend/infrastructure/monitoring/grafana/dashboards/jvm-dashboard.json diff --git a/config/monitoring/grafana/provisioning/dashboards/dashboard.yml b/config/backend/infrastructure/monitoring/grafana/provisioning/dashboards/dashboard.yml similarity index 100% rename from config/monitoring/grafana/provisioning/dashboards/dashboard.yml rename to config/backend/infrastructure/monitoring/grafana/provisioning/dashboards/dashboard.yml diff --git a/config/monitoring/grafana/provisioning/datasources/datasource.yml b/config/backend/infrastructure/monitoring/grafana/provisioning/datasources/datasource.yml similarity index 100% rename from config/monitoring/grafana/provisioning/datasources/datasource.yml rename to config/backend/infrastructure/monitoring/grafana/provisioning/datasources/datasource.yml diff --git a/config/backend/infrastructure/monitoring/prometheus/prometheus.yaml b/config/backend/infrastructure/monitoring/prometheus/prometheus.yaml new file mode 100644 index 00000000..6097235a --- /dev/null +++ b/config/backend/infrastructure/monitoring/prometheus/prometheus.yaml @@ -0,0 +1,46 @@ +# Prometheus configuration for Meldestelle project +# Basic configuration to enable service monitoring + +global: + scrape_interval: 15s + evaluation_interval: 15s + +# Alertmanager configuration +alerting: + alertmanagers: + - static_configs: + - targets: + - "alertmanager:9093" + +rule_files: + - "/etc/prometheus/rules/alerts.yaml" + +scrape_configs: + # Job 1: Prometheus überwacht sich selbst + - job_name: 'prometheus' + static_configs: + - targets: [ 'localhost:9090' ] + + # Job 2: API Gateway (Spring Boot Actuator) + - job_name: 'api-gateway' + metrics_path: '/actuator/prometheus' + scrape_interval: "30s" + static_configs: + - targets: [ 'api-gateway:8081' ] + + # Job 3: Postgres (ACHTUNG) + # Postgres direkt auf 5432 zu scrapen geht nicht. + # Entweder auskommentieren oder 'postgres-exporter' Container hinzufügen. + # - job_name: 'postgres-exporter' + # static_configs: + # - targets: ['postgres-exporter:9187'] + + # Add consul for service discovery monitoring + - job_name: 'consul' + metrics_path: '/v1/agent/metrics' + params: + format: [ 'prometheus' ] + static_configs: + - targets: [ 'consul:8500' ] + + diff --git a/config/backend/infrastructure/monitoring/prometheus/rules/alerts.yaml b/config/backend/infrastructure/monitoring/prometheus/rules/alerts.yaml new file mode 100644 index 00000000..e8a8e588 --- /dev/null +++ b/config/backend/infrastructure/monitoring/prometheus/rules/alerts.yaml @@ -0,0 +1,73 @@ +groups: + - name: meldestelle_alerts + rules: + # 1. Memory: Passt soweit, ist okay. + - alert: HighMemoryUsage + expr: (jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"}) * 100 > 85 + for: 5m + labels: + severity: warning + annotations: + summary: "High memory usage ({{ $value | humanize }}%)" + description: "JVM Heap usage is above 85%.\n Instance: {{ $labels.instance }}" + + # 2. CPU: Passt auch. + - alert: HighCpuUsage + expr: process_cpu_usage * 100 > 85 + for: 5m + labels: + severity: warning + annotations: + summary: "High CPU usage ({{ $value | humanize }}%)" + description: "CPU usage is above 85%.\n Instance: {{ $labels.instance }}" + + # 3. Error Rate: FIX - Division durch null abfangen & Rate nutzen + - alert: HighErrorRate + # Wir prüfen nur, wenn überhaupt Requests > 0 da sind, um DivByZero zu vermeiden + expr: | + ( + sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) + / + sum(rate(http_server_requests_seconds_count[5m])) + ) * 100 > 5 + for: 2m + labels: + severity: critical + annotations: + summary: "High error rate ({{ $value | humanize }}%)" + description: "More than 5% of requests resulted in 5xx errors.\n Instance: {{ $labels.instance }}" + + # 4. Service Down: FIX - Job Name Regex + - alert: ServiceDown + # Prüft alle Jobs, die du in prometheus.yml definiert hast (api-gateway, consul etc.), + # 'up == 0' bedeutet: Target ist konfiguriert, aber nicht erreichbar. + expr: up == 0 + for: 1m + labels: + severity: critical + annotations: + summary: "Service {{ $labels.job }} is down" + description: "Service instance {{ $labels.instance }} of job {{ $labels.job }} is not reachable." + + # 5. Slow Response: FIX - 'rate' benutzen! + - alert: SlowResponseTime + # Berechnet die durchschnittliche Dauer pro request im 5-Minuten-Fenster + expr: rate(http_server_requests_seconds_sum[5m]) / rate(http_server_requests_seconds_count[5m]) > 1 + for: 5m + labels: + severity: warning + annotations: + summary: "Slow response time ({{ $value | humanizeDuration }})" + description: "Average response time is > 1s for the last 5 minutes.\n Instance: {{ $labels.instance }}\n Path: {{ $labels.uri }}" + + # 6. GC Pause: FIX - 'rate' benutzen! + - alert: HighGcPauseTime + # Zeigt an, wie viel Zeit PRO SEKUNDE für GC draufgeht (nicht pro GC Event, das ist oft aussagekräftiger) + # Oder "Durchschnittliche Dauer pro GC Event im Zeitfenster": + expr: rate(jvm_gc_pause_seconds_sum[5m]) / rate(jvm_gc_pause_seconds_count[5m]) > 0.5 + for: 5m + labels: + severity: warning + annotations: + summary: "High GC pause time ({{ $value | humanizeDuration }})" + description: "Average GC pause is > 0.5s.\n Instance: {{ $labels.instance }}" diff --git a/config/nginx/nginx.prod.conf b/config/backend/infrastructure/nginx/nginx.prod.conf similarity index 100% rename from config/nginx/nginx.prod.conf rename to config/backend/infrastructure/nginx/nginx.prod.conf diff --git a/docker/core/postgres/01-init-keycloak-schema.sql b/config/backend/infrastructure/postgres/01-init-keycloak-schema.sql similarity index 76% rename from docker/core/postgres/01-init-keycloak-schema.sql rename to config/backend/infrastructure/postgres/01-init-keycloak-schema.sql index 6da768f7..323b7d3b 100644 --- a/docker/core/postgres/01-init-keycloak-schema.sql +++ b/config/backend/infrastructure/postgres/01-init-keycloak-schema.sql @@ -11,8 +11,14 @@ -- Erstellt das Keycloak-Schema, falls es noch nicht existiert. CREATE SCHEMA IF NOT EXISTS keycloak; +-- Da der "POSTGRES_USER" (Superuser) das Skript ausführt, +-- gehört ihm das Schema automatisch oder er hat Zugriff. +-- Explizite GRANTS auf "pg-user" entfernen, um .env-Unabhängigkeit zu wahren. + +-- Falls du es explizit willst, nutze current_user (der ausführende User): +GRANT ALL PRIVILEGES ON SCHEMA keycloak TO current_user; -- Gewährt dem Benutzer „meldestelle“ alle Berechtigungen für das Schema. -GRANT ALL PRIVILEGES ON SCHEMA keycloak TO "pg-user"; +-- GRANT ALL PRIVILEGES ON SCHEMA keycloak TO "pg-user"; -- Gewährt die Nutzung des Schemas GRANT USAGE ON SCHEMA keycloak TO "pg-user"; diff --git a/docker/core/postgres/02-init-keycloak-schema.sql b/config/backend/infrastructure/postgres/02-init-keycloak-schema.sql similarity index 100% rename from docker/core/postgres/02-init-keycloak-schema.sql rename to config/backend/infrastructure/postgres/02-init-keycloak-schema.sql diff --git a/config/postgres/postgresql.conf b/config/backend/infrastructure/postgres/postgresql.conf similarity index 96% rename from config/postgres/postgresql.conf rename to config/backend/infrastructure/postgres/postgresql.conf index dea4e80c..4ab1bc36 100644 --- a/config/postgres/postgresql.conf +++ b/config/backend/infrastructure/postgres/postgresql.conf @@ -39,9 +39,9 @@ constraint_exclusion = partition # Logging log_destination = 'stderr' -logging_collector = on -log_directory = 'log' -log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' +logging_collector = off +# log_directory = 'log' +# log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' log_truncate_on_rotation = off log_rotation_age = 1d log_rotation_size = 100MB diff --git a/config/redis/redis.conf b/config/backend/infrastructure/redis/redis.conf similarity index 91% rename from config/redis/redis.conf rename to config/backend/infrastructure/redis/redis.conf index 82c2c629..76ad8058 100644 --- a/config/redis/redis.conf +++ b/config/backend/infrastructure/redis/redis.conf @@ -63,14 +63,17 @@ maxclients 10000 # Security Settings rename-command FLUSHDB "" rename-command FLUSHALL "" +# KEYS ist langsam, sperren ist okay (Admin tools funktionieren dann aber evtl. nicht mehr) rename-command KEYS "" rename-command CONFIG "CONFIG_b835c3f8a5d2e7f1" rename-command SHUTDOWN "SHUTDOWN_a9b4c2d1e3f5g6h7" rename-command DEBUG "" -rename-command EVAL "" -# Disable dangerous commands in production -rename-command DEL "DEL_prod_safe" +# EVAL wird für Lua-Skripte benötigt (Locks, Rate Limiting etc.) +# rename-command EVAL "" + +# DEL wird benötigt, damit die App Cache-Einträge invalidieren kann! +# rename-command DEL "DEL_prod_safe" # TLS Configuration (uncomment and configure for TLS) # port 0 diff --git a/docker/schemas/versions-schema.json b/config/backend/infrastructure/schemas/versions-schema.json similarity index 100% rename from docker/schemas/versions-schema.json rename to config/backend/infrastructure/schemas/versions-schema.json diff --git a/config/ssl/README-de.md b/config/backend/infrastructure/ssl/README-de.md similarity index 100% rename from config/ssl/README-de.md rename to config/backend/infrastructure/ssl/README-de.md diff --git a/docker/templates/kotlin-multiplatform-web.Dockerfile b/config/backend/infrastructure/templates/kotlin-multiplatform-web.Dockerfile similarity index 100% rename from docker/templates/kotlin-multiplatform-web.Dockerfile rename to config/backend/infrastructure/templates/kotlin-multiplatform-web.Dockerfile diff --git a/docker/templates/spring-boot-service.Dockerfile b/config/backend/infrastructure/templates/spring-boot-service.Dockerfile similarity index 100% rename from docker/templates/spring-boot-service.Dockerfile rename to config/backend/infrastructure/templates/spring-boot-service.Dockerfile diff --git a/docker/compose.hardcoded.yaml b/config/compose.hardcoded.yaml similarity index 98% rename from docker/compose.hardcoded.yaml rename to config/compose.hardcoded.yaml index edf08806..aecc4014 100644 --- a/docker/compose.hardcoded.yaml +++ b/config/compose.hardcoded.yaml @@ -108,7 +108,7 @@ services: - prometheus-data:/prometheus - ./docker/monitoring/prometheus:/etc/prometheus:Z command: - - --config.file=/etc/prometheus/prometheus.yml + - --config.file=/etc/prometheus/prometheus.yaml - --storage.tsdb.retention.time=15d healthcheck: test: [ "CMD", "wget", "--spider", "-q", "http://localhost:9090/-/healthy" ] diff --git a/docker/docker-compose.clients.yaml b/config/docker-compose.clients.yaml similarity index 100% rename from docker/docker-compose.clients.yaml rename to config/docker-compose.clients.yaml diff --git a/docker/docker-compose.services.yaml b/config/docker-compose.services.yaml similarity index 100% rename from docker/docker-compose.services.yaml rename to config/docker-compose.services.yaml diff --git a/config/docker-compose.yaml b/config/docker-compose.yaml new file mode 100644 index 00000000..77e9b009 --- /dev/null +++ b/config/docker-compose.yaml @@ -0,0 +1,368 @@ +name: "${PROJECT_NAME:-meldestelle}" + +services: + # ========================================== + # CORE INFRASTRUCTURE + # ========================================== + + # --- DATABASE: PostgreSQL --- + postgres: + image: "postgres:16-alpine" + container_name: "${PROJECT_NAME}-postgres" + restart: "${RESTART_POLICY}" + ports: + - "${POSTGRES_PORT}" + environment: + POSTGRES_USER: "${POSTGRES_USER}" + POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}" + POSTGRES_DB: "${POSTGRES_DB}" + volumes: + - "postgres-data:/var/lib/postgresql/data" + - "../config/backend/infrastructure/postgres:/docker-entrypoint-initdb.d:Z" + - "../config/backend/infrastructure/postgres/postgresql.conf:/etc/postgresql/postgresql.conf:Z" + command: [ "postgres", "-c", "config_file=/etc/postgresql/postgresql.conf" ] + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" ] + interval: "5s" + timeout: "5s" + retries: "5" + start_period: "10s" + networks: + meldestelle-network: + aliases: + - "postgres" + + # --- CACHE: Redis --- + redis: + image: "redis:8.4-alpine" + container_name: "${PROJECT_NAME}-redis" + restart: "${RESTART_POLICY}" + ports: + - "${REDIS_PORT}" + volumes: + - "redis-data:/data" + - "../config/backend/infrastructure/redis/redis.conf:/usr/local/etc/redis/redis.conf:Z" + command: [ "sh", "-lc", "exec redis-server /usr/local/etc/redis/redis.conf ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}" ] + healthcheck: + test: [ "CMD-SHELL", "redis-cli -a \"$REDIS_PASSWORD\" ping | grep PONG" ] + interval: "5s" + timeout: "5s" + retries: "3" + networks: + meldestelle-network: + aliases: + - "redis" + + # --- IAM: Keycloak --- + keycloak: + image: "meldestelle-keycloak:latest" + container_name: "${PROJECT_NAME}-keycloak" + restart: "${RESTART_POLICY}" + build: + context: "../config/backend/infrastructure/keycloak" + args: + KEYCLOAK_IMAGE_TAG: "26.4" + environment: + # Admin Credentials aus .env + KC_BOOTSTRAP_ADMIN_USERNAME: "${KC_ADMIN_USER}" + KC_BOOTSTRAP_ADMIN_PASSWORD: "${KC_ADMIN_PASSWORD}" + + # DB Verbindung (Nutzt interne Docker-Namen, daher fest 'postgres') + KC_DB: "postgres" + KC_DB_URL: "jdbc:postgresql://postgres:5432/pg-${PROJECT_NAME}-db" + KC_DB_USERNAME: "${POSTGRES_USER}" + KC_DB_PASSWORD: "${POSTGRES_PASSWORD}" + + # Hostname & Proxy (Wichtig für Dev!) + KC_HOSTNAME: "localhost" + # Erlaubte Backend-Calls via http://keycloak:8080 im Docker Netzwerk + KC_HOSTNAME_STRICT: "false" + KC_HOSTNAME_STRICT_HTTPS: "false" + KC_HTTP_ENABLED: "true" + KC_PROXY_HEADERS: "xforwarded" + + # Health & Metrics sind schon im Image gebaut, aber env schadet nicht + KC_HEALTH_ENABLED: "true" + KC_METRICS_ENABLED: "true" + ports: + - "${KC_PORT}" + - "9000:9000" + depends_on: + postgres: + condition: "service_healthy" + volumes: + # Import Realm + - "../config/backend/infrastructure/keycloak:/opt/keycloak/data/import:Z" + command: "start --optimized --import-realm" + healthcheck: + test: [ "CMD-SHELL", "exec 3<>/dev/tcp/127.0.0.1/9000" ] + interval: "10s" + timeout: "5s" + retries: "5" + start_period: "60s" + networks: + meldestelle-network: + aliases: + - "keycloak" + + # --- DATENBANK-MANAGEMENT-TOOL: pgAdmin4 --- + pgadmin: + image: "dpage/pgadmin4:8" + container_name: "${PROJECT_NAME}-pgadmin" + restart: "${RESTART_POLICY}" + ports: + - "${PGADMIN_PORT:-8888:80}" + environment: + PGADMIN_DEFAULT_EMAIL: "${PGADMIN_EMAIL}" + PGADMIN_DEFAULT_PASSWORD: "${PGADMIN_PASSWORD}" + volumes: + - "pgadmin-data:/var/lib/pgadmin" + networks: + meldestelle-network: + aliases: + - "pgadmin" + + # --- MONITORING: Prometheus --- + prometheus: + image: "prom/prometheus:v3.7.3" + container_name: "${PROJECT_NAME}-prometheus" + restart: "${RESTART_POLICY}" + ports: + - "${PROMETHEUS_PORT}" + volumes: + - "prometheus-data:/prometheus" + - "../config/backend/infrastructure/monitoring/prometheus:/etc/prometheus:Z" + command: + - --web.enable-lifecycle + - --config.file=/etc/prometheus/prometheus.yaml + - --storage.tsdb.retention.time=15d + healthcheck: + test: [ "CMD", "wget", "--spider", "-q", "http://localhost:9090/-/healthy" ] + interval: "30s" + timeout: "10s" + retries: "3" + start_period: "30s" + networks: + meldestelle-network: + aliases: + - "prometheus" + + # --- MONITORING: Grafana --- + grafana: + image: grafana/grafana:12.3 + container_name: ${PROJECT_NAME}-grafana + restart: "${RESTART_POLICY}" + environment: + GF_SECURITY_ADMIN_USER: ${GF_ADMIN_USER} + GF_SECURITY_ADMIN_PASSWORD: ${GF_ADMIN_PASSWORD} + ports: + - "${GF_PORT}" + volumes: + - grafana-data:/var/lib/grafana + # Provisioning (datasources/dashboards) from central config + - ../config/backend/infrastructure/monitoring/grafana/provisioning:/etc/grafana/provisioning:Z + # Dashboards directory (referenced by provisioning file path: /var/lib/grafana/dashboards) + - ../config/backend/infrastructure/monitoring/grafana/dashboards:/var/lib/grafana/dashboards:Z + depends_on: + - prometheus + healthcheck: + test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health" ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + networks: + meldestelle-network: + aliases: + - grafana + + # --- CONSUL --- + consul: + image: "hashicorp/consul:1.22.1" + container_name: "${PROJECT_NAME}-consul" + restart: "${RESTART_POLICY}" + ports: + - "${CONSUL_PORT}" + - "${CONSUL_UDP_PORT}" + command: "agent -server -bootstrap-expect=1 -ui -client=0.0.0.0" + healthcheck: + test: [ "CMD", "curl", "-f", "http://localhost:8500/v1/status/leader" ] + interval: "30s" + timeout: "10s" + retries: "3" + networks: + meldestelle-network: + aliases: + - "consul" + + # --- API-GATEWAY: Spring Cloud Gateway --- + api-gateway: + build: + context: .. + dockerfile: backend/infrastructure/gateway/Dockerfile + args: + # Build-Args aus deinen .env Dateien (werden hier statisch benötigt für den Build) + GRADLE_VERSION: "9.1.0" + JAVA_VERSION: "21" + VERSION: "1.0.0-SNAPSHOT" + BUILD_DATE: "2025-12-04" + container_name: "${PROJECT_NAME}-gateway" + restart: "${RESTART_POLICY}" + ports: + - "${GATEWAY_SERVER_PORT}" + - "${GATEWAY_DEBUG_PORT}" + environment: + # server.port must be an integer. Do not pass host:container mapping here. + SERVER_PORT: "8081" + SPRING_PROFILES_ACTIVE: "docker" + DEBUG: "true" + + # --- KEYCLOAK --- + # Container-zu-Container Kommunikation (intern) + SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: "http://keycloak:8080/realms/meldestelle" + # JWK Set Uri erzwingen, damit er nicht über den Issuer (localhost vs keycloak) stolpert + SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI: "http://keycloak:8080/realms/meldestelle/protocol/openid-connect/certs" + + # --- CONSUL --- + SPRING_CLOUD_CONSUL_HOST: "consul" + # Consul port must be an integer (container internal port) + SPRING_CLOUD_CONSUL_PORT: "8500" + # WICHTIG: Das Gateway muss wissen, wie es von anderen Containern erreicht wird (nicht localhost!) + SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME: "api-gateway" + # Wichtig für Docker: Wir wollen IP-Adressen registrieren, keine Hostnames, die DNS brauchen + SPRING_CLOUD_CONSUL_DISCOVERY_PREFER_IP_ADDRESS: "true" + + # --- POSTGRES --- + SPRING_DATASOURCE_URL: "jdbc:postgresql://postgres:5432/${POSTGRES_DB}" + SPRING_DATASOURCE_USERNAME: "${POSTGRES_USER}" + SPRING_DATASOURCE_PASSWORD: "${POSTGRES_PASSWORD}" + + # --- LOGGING --- + LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_GATEWAY: "DEBUG" + LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_SECURITY: "DEBUG" + + depends_on: + consul: + condition: "service_healthy" + postgres: + condition: "service_healthy" + keycloak: + condition: "service_healthy" + networks: + meldestelle-network: + aliases: + - "api-gateway" + + # ========================================== + # MICROSERVICES + # ========================================== + ping-service: + build: + context: .. + dockerfile: backend/services/ping/Dockerfile + args: + GRADLE_VERSION: 9.1.0 + JAVA_VERSION: 21 + VERSION: 1.0.0 + BUILD_DATE: "2025-11-29" + container_name: ${PROJECT_NAME}-ping-service + restart: "${RESTART_POLICY}" + ports: + - "${PING_PORT}" + - "${PING_DEBUG_PORT}" + environment: + SPRING_PROFILES_ACTIVE: docker + DEBUG: "true" + SERVER_PORT: 8082 + + # --- CONSUL --- + SPRING_CLOUD_CONSUL_HOST: consul + SPRING_CLOUD_CONSUL_PORT: 8500 + SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME: ping-service + + # - DATENBANK VERBINDUNG - + SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB} + SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER} + SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD} + SPRING_JPA_HIBERNATE_DDL_AUTO: validate + + # --- REDIS --- + SPRING_DATA_REDIS_HOST: redis + SPRING_DATA_REDIS_PORT: 6379 + # Optional: if REDIS_PASSWORD is set in .env, forward it to Spring + SPRING_DATA_REDIS_PASSWORD: "${REDIS_PASSWORD}" + # Make initial connection a bit more tolerant on startup races + SPRING_DATA_REDIS_CONNECT_TIMEOUT: 5s + depends_on: + consul: + condition: service_healthy + postgres: + condition: service_healthy + keycloak: + condition: service_healthy + redis: + condition: service_healthy + networks: + meldestelle-network: + aliases: + - ping-service + + # ========================================== + # FRONTEND + # ========================================== + + # --- WEB-APP --- + web-app: + build: + context: .. + dockerfile: ../config/frontends/web-app/Dockerfile + args: + GRADLE_VERSION: ${DOCKER_GRADLE_VERSION:-9.1.0} + JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21} + NODE_VERSION: ${DOCKER_NODE_VERSION:-22.21.0} + NGINX_IMAGE_TAG: ${DOCKER_NGINX_VERSION:-1.28.0-alpine} + WEB_BUILD_PROFILE: ${WEB_BUILD_PROFILE:-dev} + container_name: ${PROJECT_NAME}-web-app + restart: "${RESTART_POLICY}" + ports: + - "${WEB_APP_PORT}" + volumes: + # Mount production nginx config (can be adjusted per env) + - ../config/nginx/nginx.prod.conf:/etc/nginx/nginx.conf:Z,ro + depends_on: + api-gateway: + condition: service_started + networks: + meldestelle-network: + aliases: + - web-app + + desktop-app: + build: + context: .. + dockerfile: ../config/frontends/desktop-app/Dockerfile + container_name: ${PROJECT_NAME}-desktop-app + restart: "${RESTART_POLICY}" + environment: + API_BASE_URL: http://api-gateway:8081 + ports: + - "${DESKTOP_APP_VNC_PORT}" + - "${DESKTOP_APP_NOVNC_PORT}" + depends_on: + api-gateway: + condition: service_started + networks: + meldestelle-network: + aliases: + - desktop-app + +volumes: + postgres-data: + pgadmin-data: + redis-data: + prometheus-data: + grafana-data: + +networks: + meldestelle-network: + driver: bridge diff --git a/docker/frontends/desktop-app/Dockerfile b/config/frontends/desktop-app/Dockerfile similarity index 100% rename from docker/frontends/desktop-app/Dockerfile rename to config/frontends/desktop-app/Dockerfile diff --git a/docker/frontends/desktop-app/entrypoint.sh b/config/frontends/desktop-app/entrypoint.sh similarity index 100% rename from docker/frontends/desktop-app/entrypoint.sh rename to config/frontends/desktop-app/entrypoint.sh diff --git a/docker/frontends/desktop-app/health-check.sh b/config/frontends/desktop-app/health-check.sh similarity index 100% rename from docker/frontends/desktop-app/health-check.sh rename to config/frontends/desktop-app/health-check.sh diff --git a/docker/frontends/desktop-app/supervisord.conf b/config/frontends/desktop-app/supervisord.conf similarity index 100% rename from docker/frontends/desktop-app/supervisord.conf rename to config/frontends/desktop-app/supervisord.conf diff --git a/docker/frontends/web-app/Dockerfile b/config/frontends/web-app/Dockerfile similarity index 100% rename from docker/frontends/web-app/Dockerfile rename to config/frontends/web-app/Dockerfile diff --git a/docker/frontends/web-app/downloads/index.html b/config/frontends/web-app/downloads/index.html similarity index 100% rename from docker/frontends/web-app/downloads/index.html rename to config/frontends/web-app/downloads/index.html diff --git a/docker/frontends/web-app/nginx.conf b/config/frontends/web-app/nginx.conf similarity index 100% rename from docker/frontends/web-app/nginx.conf rename to config/frontends/web-app/nginx.conf diff --git a/.markdownlint.yaml b/config/lint/.markdownlint.yaml similarity index 100% rename from .markdownlint.yaml rename to config/lint/.markdownlint.yaml diff --git a/.markdownlintignore b/config/lint/.markdownlintignore similarity index 100% rename from .markdownlintignore rename to config/lint/.markdownlintignore diff --git a/.spectral.yaml b/config/lint/.spectral.yaml similarity index 100% rename from .spectral.yaml rename to config/lint/.spectral.yaml diff --git a/.vale.ini b/config/lint/.vale.ini similarity index 100% rename from .vale.ini rename to config/lint/.vale.ini diff --git a/config/monitoring/prometheus.dev.yml b/config/monitoring/prometheus.dev.yml deleted file mode 100644 index 24efcd8f..00000000 --- a/config/monitoring/prometheus.dev.yml +++ /dev/null @@ -1,185 +0,0 @@ -# =================================================================== -# Prometheus Development Configuration -# Enhanced monitoring for Meldestelle development environment -# =================================================================== - -global: - scrape_interval: 15s # More frequent scraping for development - evaluation_interval: 15s # Faster rule evaluation - external_labels: - cluster: 'meldestelle-dev' - environment: 'development' - -# Rule files for alerting (development-friendly) -rule_files: - - "/etc/prometheus/rules.yml" - -# Scrape configurations for development services -scrape_configs: - # =================================================================== - # Infrastructure Services - # =================================================================== - - # Prometheus self-monitoring - - job_name: 'prometheus' - static_configs: - - targets: ['localhost:9090'] - scrape_interval: 15s - metrics_path: '/metrics' - - # =================================================================== - # Application Services (Spring Boot) - # =================================================================== - - # API Gateway - - job_name: 'api-gateway' - static_configs: - - targets: ['api-gateway:8081'] - metrics_path: '/actuator/prometheus' - scrape_interval: 10s # More frequent for gateway - scrape_timeout: 5s - params: - format: ['prometheus'] - - # Auth Server - - job_name: 'auth-server' - static_configs: - - targets: ['auth-server:8081'] - metrics_path: '/actuator/prometheus' - scrape_interval: 15s - scrape_timeout: 5s - - # Monitoring Server (self-monitoring) - - job_name: 'monitoring-server' - static_configs: - - targets: ['monitoring-server:8083'] - metrics_path: '/actuator/prometheus' - scrape_interval: 15s - scrape_timeout: 5s - - # Ping Service - - job_name: 'ping-service' - static_configs: - - targets: ['ping-service:8082'] - metrics_path: '/actuator/prometheus' - scrape_interval: 10s # Frequent for testing - scrape_timeout: 3s - - # =================================================================== - # Infrastructure Monitoring - # =================================================================== - - # PostgreSQL Exporter (if deployed) - - job_name: 'postgres' - static_configs: - - targets: ['postgres-exporter:9187'] - scrape_interval: 30s - scrape_timeout: 10s - - # Redis Exporter (if deployed) - - job_name: 'redis' - static_configs: - - targets: ['redis-exporter:9121'] - scrape_interval: 30s - scrape_timeout: 10s - - # =================================================================== - # Container and Host Metrics - # =================================================================== - - # Docker container metrics via cAdvisor (if deployed) - - job_name: 'cadvisor' - static_configs: - - targets: ['cadvisor:8080'] - scrape_interval: 30s - scrape_timeout: 10s - - # Node Exporter for host metrics (if deployed) - - job_name: 'node-exporter' - static_configs: - - targets: ['node-exporter:9100'] - scrape_interval: 30s - scrape_timeout: 10s - - # =================================================================== - # Service Discovery (Consul Integration) - # =================================================================== - - # Consul service discovery for dynamic services - - job_name: 'consul-services' - consul_sd_configs: - - server: 'consul:8500' - services: [] - relabel_configs: - # Only scrape services that have prometheus.scrape=true - - source_labels: [__meta_consul_service_metadata_prometheus_scrape] - action: keep - regex: "true" - - # Use service name as job name - - source_labels: [__meta_consul_service] - target_label: job - - # Use custom metrics path if specified - - source_labels: [__meta_consul_service_metadata_prometheus_path] - target_label: __metrics_path__ - regex: "(.+)" - - # Use custom port if specified - - source_labels: [__address__, __meta_consul_service_metadata_prometheus_port] - target_label: __address__ - regex: "([^:]+)(?::\d+)?;(\d+)" - replacement: $1:$2 - - # =================================================================== - # Development-Specific Configurations - # =================================================================== - - # Health check endpoints monitoring - - job_name: 'health-checks' - static_configs: - - targets: - - 'api-gateway:8081' - - 'auth-server:8081' - - 'monitoring-server:8083' - - 'ping-service:8082' - metrics_path: '/actuator/health' - scrape_interval: 30s - scrape_timeout: 5s - - # JVM metrics (additional detail for development) - - job_name: 'jvm-metrics' - static_configs: - - targets: - - 'api-gateway:8081' - - 'auth-server:8081' - - 'monitoring-server:8083' - - 'ping-service:8082' - metrics_path: '/actuator/prometheus' - scrape_interval: 30s - params: - match[]: - - 'jvm_*' - - 'process_*' - - 'system_*' - -# =================================================================== -# Alerting Configuration (Development-friendly) -# =================================================================== -alerting: - alertmanagers: - - static_configs: - - targets: - # AlertManager not typically used in development - # - alertmanager:9093 - -# =================================================================== -# Remote Write Configuration (for development data persistence) -# =================================================================== -# Uncomment if you want to send metrics to external storage -# remote_write: -# - url: "http://prometheus-remote-write:8080/api/v1/write" -# queue_config: -# max_samples_per_send: 1000 -# max_shards: 200 -# capacity: 2500 diff --git a/config/monitoring/prometheus.prod.yml b/config/monitoring/prometheus.prod.yml deleted file mode 100644 index f84bad8e..00000000 --- a/config/monitoring/prometheus.prod.yml +++ /dev/null @@ -1,123 +0,0 @@ -# Prometheus Production Configuration -# ============================================================================= -# This configuration provides production-ready monitoring setup with -# security, performance optimizations, and comprehensive service discovery -# ============================================================================= - -global: - scrape_interval: 15s - evaluation_interval: 15s - external_labels: - monitor: 'meldestelle-prod' - environment: 'production' - -# Alertmanager configuration -alerting: - alertmanagers: - - static_configs: - - targets: - - alertmanager:9093 - -# Load rules once and periodically evaluate them according to the global 'evaluation_interval'. -rule_files: - - "alert_rules.yml" - - "recording_rules.yml" - -# Scrape configuration -scrape_configs: - # Prometheus itself - - job_name: 'prometheus' - static_configs: - - targets: ['localhost:9090'] - scrape_interval: 5s - metrics_path: /metrics - - # Application metrics - - job_name: 'meldestelle-api' - static_configs: - - targets: ['host.docker.internal:8081'] - scrape_interval: 10s - metrics_path: /actuator/prometheus - basic_auth: - username: 'admin' - password: 'CHANGE_ME_METRICS_PASSWORD' - - # PostgreSQL metrics (using postgres_exporter) - - job_name: 'postgres' - static_configs: - - targets: ['postgres-exporter:9187'] - scrape_interval: 30s - - # Redis metrics (using redis_exporter) - - job_name: 'redis' - static_configs: - - targets: ['redis-exporter:9121'] - scrape_interval: 30s - - # Kafka metrics (using kafka_exporter) - - job_name: 'kafka' - static_configs: - - targets: ['kafka-exporter:9308'] - scrape_interval: 30s - - # Zookeeper metrics (using zookeeper_exporter) - - job_name: 'zookeeper' - static_configs: - - targets: ['zookeeper-exporter:9141'] - scrape_interval: 30s - - # Keycloak metrics - - job_name: 'keycloak' - static_configs: - - targets: ['keycloak:8443'] - scrape_interval: 30s - metrics_path: /auth/realms/master/metrics - scheme: https - tls_config: - insecure_skip_verify: true - - # Nginx metrics (using nginx-prometheus-exporter) - - job_name: 'nginx' - static_configs: - - targets: ['nginx-exporter:9113'] - scrape_interval: 30s - - # Node exporter for system metrics - - job_name: 'node' - static_configs: - - targets: ['node-exporter:9100'] - scrape_interval: 30s - - # cAdvisor for container metrics - - job_name: 'cadvisor' - static_configs: - - targets: ['cadvisor:8080'] - scrape_interval: 30s - - # Grafana metrics - - job_name: 'grafana' - static_configs: - - targets: ['grafana:3000'] - scrape_interval: 30s - metrics_path: /metrics - - # Zipkin metrics - - job_name: 'zipkin' - static_configs: - - targets: ['zipkin:9411'] - scrape_interval: 30s - metrics_path: /actuator/prometheus - -# Remote write configuration (for long-term storage) -# remote_write: -# - url: "https://your-remote-storage/api/v1/write" -# basic_auth: -# username: "your-username" -# password: "your-password" - -# Storage configuration -storage: - tsdb: - retention.time: 30d - retention.size: 10GB - wal-compression: true diff --git a/config/monitoring/prometheus.yml b/config/monitoring/prometheus.yml deleted file mode 100644 index edf14ea7..00000000 --- a/config/monitoring/prometheus.yml +++ /dev/null @@ -1,41 +0,0 @@ -global: - scrape_interval: 15s - evaluation_interval: 15s - -# Alertmanager configuration -alerting: - alertmanagers: - - static_configs: - - targets: - - alertmanager:9093 - -# Load rules once and periodically evaluate them according to the global 'evaluation_interval'. -rule_files: - - "/etc/prometheus/rules/alerts.yml" - -# A scrape configuration containing exactly one endpoint to scrape: -scrape_configs: - # The job name is added as a label `job=` to any timeseries scraped from this config. - - job_name: "prometheus" - # metrics_path defaults to '/metrics' - # scheme defaults to 'http'. - static_configs: - - targets: ["localhost:9090"] - - # Scrape configuration for the Meldestelle application - - job_name: "meldestelle-api" - metrics_path: /actuator/prometheus - scrape_interval: 10s - basic_auth: - username: ${METRICS_USER:-metrics} - password: ${METRICS_PASSWORD:-metrics-password-dev} - static_configs: - - targets: ["server:8081"] - labels: - application: "meldestelle" - service: "api-gateway" - - # Node exporter for host metrics (if added later) - # - job_name: "node-exporter" - # static_configs: - # - targets: ["node-exporter:9100"] diff --git a/config/monitoring/prometheus/rules/alerts.yml b/config/monitoring/prometheus/rules/alerts.yml deleted file mode 100644 index f9a599d3..00000000 --- a/config/monitoring/prometheus/rules/alerts.yml +++ /dev/null @@ -1,62 +0,0 @@ -groups: - - name: meldestelle_alerts - rules: - # Alert for high memory usage - - alert: HighMemoryUsage - expr: (jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"}) * 100 > 85 - for: 5m - labels: - severity: warning - annotations: - summary: "High memory usage ({{ $value }}%)" - description: "JVM memory usage is above 85% for 5 minutes.\n Instance: {{ $labels.instance }}\n Service: {{ $labels.service }}" - - # Alert for high CPU usage - - alert: HighCpuUsage - expr: process_cpu_usage > 0.85 - for: 5m - labels: - severity: warning - annotations: - summary: "High CPU usage ({{ $value }})" - description: "CPU usage is above 85% for 5 minutes.\n Instance: {{ $labels.instance }}\n Service: {{ $labels.service }}" - - # Alert for high error rate - - alert: HighErrorRate - expr: sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) / sum(rate(http_server_requests_seconds_count[5m])) * 100 > 5 - for: 2m - labels: - severity: critical - annotations: - summary: "High error rate ({{ $value }}%)" - description: "Error rate is above 5% for 2 minutes.\n Instance: {{ $labels.instance }}\n Service: {{ $labels.service }}" - - # Alert for service unavailability - - alert: ServiceUnavailable - expr: up{job="meldestelle-server"} == 0 - for: 1m - labels: - severity: critical - annotations: - summary: "Service unavailable" - description: "Meldestelle service is down.\n Instance: {{ $labels.instance }}" - - # Alert for slow response time - - alert: SlowResponseTime - expr: http_server_requests_seconds_sum / http_server_requests_seconds_count > 1 - for: 5m - labels: - severity: warning - annotations: - summary: "Slow response time ({{ $value }}s)" - description: "Average response time is above 1 second for 5 minutes.\n Instance: {{ $labels.instance }}\n Path: {{ $labels.uri }}" - - # Alert for high GC pause time - - alert: HighGcPauseTime - expr: jvm_gc_pause_seconds_sum / jvm_gc_pause_seconds_count > 0.5 - for: 5m - labels: - severity: warning - annotations: - summary: "High GC pause time ({{ $value }}s)" - description: "Average GC pause time is above 0.5 seconds for 5 minutes.\n Instance: {{ $labels.instance }}" diff --git a/docker/versions.toml b/config/versions.toml similarity index 100% rename from docker/versions.toml rename to config/versions.toml diff --git a/docker/.env b/docker/.env deleted file mode 100644 index 5e831ef4..00000000 --- a/docker/.env +++ /dev/null @@ -1,63 +0,0 @@ -# ========================================== -# Meldestelle - Environment Configuration -# ========================================== -# Profil: DEVELOPMENT (Lokal) - -# --- PROJEKT EINSTELLUNGEN --- -COMPOSE_PROJECT_NAME=meldestelle -# Restart Policy: 'no' für Dev (Fehler sehen), 'always' für Prod -# RESTART_POLICY=no - -# --- POSTGRESQL (Datenbank) --- -POSTGRES_USER=pg-user -POSTGRES_PASSWORD=pg-password -POSTGRES_DB=meldestelle -# Port Mapping: Host:Container. -# Prod: 127.0.0.1:5432 (nur localhost) oder leer lassen -POSTGRES_PORT=5432:5432 - -# --- REDIS (Cache) --- -# Prod: 127.0.0.1:6379 oder leer lassen -REDIS_PORT=6379:6379 - -# --- KEYCLOAK (Identity Provider) --- -KC_ADMIN_USER=kc-admin -KC_ADMIN_PASSWORD=kc-password -KC_HOSTNAME=localhost -KC_PORT=8180:8080 - -# --- PGADMIN (DB GUI) --- -PGADMIN_EMAIL=user@domain.com -PGADMIN_PASSWORD=strong-password -PGADMIN_PORT=8888:80 - -# --- PROMETHEUS (Metriken) --- -PROMETHEUS_PORT=9090:9090 - -# --- GRAFANA (Monitoring GUI) --- -GF_ADMIN_USER=gf-admin -GF_ADMIN_PASSWORD=gf-password -GF_PORT=3000:3000 - -# --- SERVICE DISCOVERY (Consul) --- -CONSUL_PORT=8500:8500 - -# --- API GATEWAY --- -GATEWAY_PORT=8081:8081 -GATEWAY_DEBUG_PORT=5005:5005 -GATEWAY_SERVER_PORT=8081 - -# --- MICROSERVICES --- -PING_SERVICE_PORT=8082:8082 -PING_DEBUG_PORT=5006:5006 - -# --- WEB CLIENTS --- -# Web-App (Nginx inside container listens on 80) -WEB_APP_PORT=8080:80 - -# Desktop-App (VNC + noVNC) -DESKTOP_APP_VNC_PORT=5901:5901 -DESKTOP_APP_NOVNC_PORT=6080:6080 - -# Optional: Redis Passwort aktivieren (setzt --requirepass) -# REDIS_PASSWORD=change-me-strong diff --git a/docker/.env.example b/docker/.env.example deleted file mode 100644 index 7c70fdd5..00000000 --- a/docker/.env.example +++ /dev/null @@ -1,92 +0,0 @@ -<<<<<<< HEAD -# ========================================== -# Meldestelle – Docker Compose Environment -# Single Source of Truth (SSoT) -# ========================================== - -# --- PROJECT --- -COMPOSE_PROJECT_NAME=meldestelle - -# --- PORT MAPPINGS (host:container) --- -POSTGRES_PORT=5432:5432 -REDIS_PORT=6379:6379 -KC_PORT=8180:8080 -PGADMIN_PORT=8888:80 -PROMETHEUS_PORT=9090:9090 -GF_PORT=3000:3000 -CONSUL_PORT=8500:8500 -GATEWAY_PORT=8081:8081 -GATEWAY_DEBUG_PORT=5005:5005 -GATEWAY_SERVER_PORT=8081 -PING_SERVICE_PORT=8082:8082 -PING_DEBUG_PORT=5006:5006 -WEB_APP_PORT=4000:4000 -DESKTOP_APP_VNC_PORT=5901:5901 -DESKTOP_APP_NOVNC_PORT=6080:6080 - -# --- POSTGRES --- -======= -# Core project name used as prefix for container names -COMPOSE_PROJECT_NAME=meldestelle - -# Ports -POSTGRES_PORT=5432:5432 -REDIS_PORT=6379:6379 -KC_PORT=8180:8080 -CONSUL_PORT=8500:8500 -PROMETHEUS_PORT=9090:9090 -GF_PORT=3000:3000 -WEB_APP_PORT=4000:80 -PING_SERVICE_PORT=8082:8082 -PING_DEBUG_PORT=5006:5006 -GATEWAY_PORT=8081:8081 -GATEWAY_DEBUG_PORT=5005:5005 -GATEWAY_SERVER_PORT=8081 -DESKTOP_APP_VNC_PORT=5900:5900 -DESKTOP_APP_NOVNC_PORT=6080:6080 - -# Postgres ->>>>>>> origin/main -POSTGRES_USER=meldestelle -POSTGRES_PASSWORD=meldestelle -POSTGRES_DB=meldestelle - -<<<<<<< HEAD -# --- REDIS --- -# Optional password for Redis; leave empty to disable authentication in dev -REDIS_PASSWORD= - -# --- KEYCLOAK --- -======= -# Keycloak ->>>>>>> origin/main -KC_ADMIN_USER=admin -KC_ADMIN_PASSWORD=admin -KC_HOSTNAME=localhost - -<<<<<<< HEAD -# --- PGADMIN --- -PGADMIN_EMAIL=admin@example.com -PGADMIN_PASSWORD=admin - -# --- GRAFANA --- -GF_ADMIN_USER=admin -GF_ADMIN_PASSWORD=admin - -# --- DOCKER BUILD OVERRIDES (optional) --- -======= -# PgAdmin -PGADMIN_EMAIL=admin@example.com -PGADMIN_PASSWORD=admin - -# Grafana -GF_ADMIN_USER=admin -GF_ADMIN_PASSWORD=admin - -# Docker build versions (optional overrides) ->>>>>>> origin/main -DOCKER_GRADLE_VERSION=9.1.0 -DOCKER_JAVA_VERSION=21 -DOCKER_NODE_VERSION=22.21.0 -DOCKER_NGINX_VERSION=1.28.0-alpine -WEB_BUILD_PROFILE=dev diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml deleted file mode 100644 index fce1ac66..00000000 --- a/docker/docker-compose.yaml +++ /dev/null @@ -1,337 +0,0 @@ -name: ${COMPOSE_PROJECT_NAME:-meldestelle} - -services: - # ========================================== - # CORE INFRASTRUCTURE - # ========================================== - postgres: - image: postgres:16-alpine - container_name: ${COMPOSE_PROJECT_NAME}-postgres - restart: unless-stopped - ports: - - "${POSTGRES_PORT}" - environment: - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB} - volumes: - - postgres-data:/var/lib/postgresql/data - - ./core/postgres:/docker-entrypoint-initdb.d:Z - # Central postgres.conf from config (optional) - - ../config/postgres/postgresql.conf:/etc/postgresql/postgresql.conf:Z - # Use central postgresql.conf if present - command: ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"] - healthcheck: - test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" ] - interval: 5s - timeout: 5s - retries: 5 - start_period: 10s - networks: - meldestelle-network: - aliases: - - postgres - - redis: - image: redis:8.4-alpine - container_name: ${COMPOSE_PROJECT_NAME}-redis - restart: unless-stopped - ports: - - "${REDIS_PORT}" - volumes: - - redis-data:/data - # Central redis config - - ../config/redis/redis.conf:/usr/local/etc/redis/redis.conf:Z - # Use central redis.conf and optionally add --requirepass if REDIS_PASSWORD is set - command: ["sh", "-lc", "exec redis-server /usr/local/etc/redis/redis.conf ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}"] - healthcheck: - test: [ "CMD", "redis-cli" ] - interval: 5s - timeout: 5s - retries: 3 - networks: - meldestelle-network: - aliases: - - redis - - # ========================================== - # SECURITY - # ========================================== - keycloak: - image: quay.io/keycloak/keycloak:26.4 - container_name: ${COMPOSE_PROJECT_NAME}-keycloak - restart: unless-stopped - environment: - KC_HEALTH_ENABLED: true - KC_METRICS_ENABLED: true - # Admin Credentials aus .env - KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_ADMIN_USER} - KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD} - # DB Verbindung (Nutzt interne Docker-Namen, daher fest 'postgres') - KC_DB: postgres - KC_DB_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB} - KC_DB_USERNAME: ${POSTGRES_USER} - KC_DB_PASSWORD: ${POSTGRES_PASSWORD} - KC_HOSTNAME: ${KC_HOSTNAME} - ports: - - "${KC_PORT}" - depends_on: - postgres: - condition: service_healthy - volumes: - - ./core/keycloak:/opt/keycloak/data/import:Z - command: start-dev --import-realm - healthcheck: - test: [ "CMD-SHELL", "exec 3<>/dev/tcp/127.0.0.1/9000" ] - interval: 10s - timeout: 5s - retries: 5 - start_period: 60s - networks: - meldestelle-network: - aliases: - - keycloak - - # ========================================== - # MONITORING & TOOLS - # ========================================== - pgadmin: - image: dpage/pgadmin4:8 - container_name: ${COMPOSE_PROJECT_NAME}-pgadmin - restart: unless-stopped - ports: - - "${PGADMIN_PORT:-8888:80}" - environment: - PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL} - PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD} - volumes: - - pgadmin-data:/var/lib/pgadmin - networks: - meldestelle-network: - aliases: - - pgadmin - - prometheus: - image: prom/prometheus:v3.7.3 - container_name: ${COMPOSE_PROJECT_NAME}-prometheus - restart: unless-stopped - ports: - - "${PROMETHEUS_PORT}" - volumes: - - prometheus-data:/prometheus - # Use central config as single source of truth - - ../config/monitoring/prometheus:/etc/prometheus:Z - command: - - --config.file=/etc/prometheus/prometheus.yml - - --storage.tsdb.retention.time=15d - healthcheck: - test: [ "CMD", "wget", "--spider", "-q", "http://localhost:9090/-/healthy" ] - interval: 30s - timeout: 10s - retries: 3 - start_period: 30s - networks: - meldestelle-network: - aliases: - - prometheus - - grafana: - image: grafana/grafana:12.3 - container_name: ${COMPOSE_PROJECT_NAME}-grafana - restart: unless-stopped - environment: - GF_SECURITY_ADMIN_USER: ${GF_ADMIN_USER} - GF_SECURITY_ADMIN_PASSWORD: ${GF_ADMIN_PASSWORD} - ports: - - "${GF_PORT}" - volumes: - - grafana-data:/var/lib/grafana - # Provisioning (datasources/dashboards) from central config - - ../config/monitoring/grafana/provisioning:/etc/grafana/provisioning:Z - # Dashboards directory (referenced by provisioning file path: /var/lib/grafana/dashboards) - - ../config/monitoring/grafana/dashboards:/var/lib/grafana/dashboards:Z - depends_on: - - prometheus - healthcheck: - test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health" ] - interval: 30s - timeout: 10s - retries: 3 - start_period: 30s - networks: - meldestelle-network: - aliases: - - grafana - - # ========================================== - # APPLICATION GATEWAY - # ========================================== - - consul: - image: hashicorp/consul:1.22.1 - container_name: ${COMPOSE_PROJECT_NAME}-consul - restart: unless-stopped - ports: - - "${CONSUL_PORT}" - command: agent -server -bind=0.0.0.0 -client=0.0.0.0 -bootstrap-expect=1 -ui - healthcheck: - test: [ "CMD", "curl", "-f", "http://localhost:8500/v1/status/leader" ] - interval: 10s - timeout: 5s - retries: 3 - networks: - meldestelle-network: - aliases: - - consul - - api-gateway: - build: - context: .. - dockerfile: backend/infrastructure/gateway/Dockerfile - args: - # Build-Args aus deinen .env Dateien (werden hier statisch benötigt für den Build) - GRADLE_VERSION: 9.1.0 - JAVA_VERSION: 21 - VERSION: 1.0.0 - BUILD_DATE: "2025-11-29" - container_name: ${COMPOSE_PROJECT_NAME}-gateway - restart: no - ports: - - "${GATEWAY_PORT}" - - "${GATEWAY_DEBUG_PORT}" # Für Remote Debugging - environment: - SERVER_PORT: ${GATEWAY_SERVER_PORT} - SPRING_PROFILES_ACTIVE: docker - DEBUG: "true" - # --- VERBINDUNGEN --- - # Keycloak URL (INTERN im Docker Netzwerk!) - # Beachte: http://container-name:8080 (nicht localhost, nicht 8180) - SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: http://keycloak:8080/realms/meldestelle - SPRING_CLOUD_CONSUL_HOST: consul - SPRING_CLOUD_CONSUL_PORT: 8500 - # WICHTIG: Das Gateway muss wissen, wie es von anderen Containern erreicht wird (nicht localhost!) - SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME: api-gateway - # Postgres Verbindung (für Routes/Session, falls nötig) - SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB} - SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER} - SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD} - # Logging - LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_GATEWAY: DEBUG - LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_SECURITY: DEBUG - depends_on: - consul: - condition: service_healthy - postgres: - condition: service_healthy - keycloak: - condition: service_healthy - networks: - meldestelle-network: - aliases: - - api-gateway - - # ========================================== - # MICROSERVICES - # ========================================== - ping-service: - build: - context: .. - dockerfile: backend/services/ping/Dockerfile - args: - GRADLE_VERSION: 9.1.0 - JAVA_VERSION: 21 - VERSION: 1.0.0 - BUILD_DATE: "2025-11-29" - container_name: ${COMPOSE_PROJECT_NAME}-ping-service - restart: no # "${RESTART_POLICY:-unless-stopped}" - ports: - - "${PING_SERVICE_PORT}" - - "${PING_DEBUG_PORT}" - environment: - SPRING_PROFILES_ACTIVE: docker - DEBUG: "true" - SERVER_PORT: 8082 - - # --- CONSUL --- - SPRING_CLOUD_CONSUL_HOST: consul - SPRING_CLOUD_CONSUL_PORT: 8500 - SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME: ping-service - - # - DATENBANK VERBINDUNG - - SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB} - SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER} - SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD} - SPRING_JPA_HIBERNATE_DDL_AUTO: validate - - # --- REDIS --- - SPRING_DATA_REDIS_HOST: redis - SPRING_DATA_REDIS_PORT: 6379 - depends_on: - consul: - condition: service_healthy - postgres: - condition: service_healthy - keycloak: - condition: service_healthy - networks: - meldestelle-network: - aliases: - - ping-service - - # ========================================== - # CLIENT APPLICATIONS - # ========================================== - web-app: - build: - context: .. - dockerfile: docker/frontends/web-app/Dockerfile - args: - GRADLE_VERSION: ${DOCKER_GRADLE_VERSION:-9.1.0} - JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21} - NODE_VERSION: ${DOCKER_NODE_VERSION:-22.21.0} - NGINX_IMAGE_TAG: ${DOCKER_NGINX_VERSION:-1.28.0-alpine} - WEB_BUILD_PROFILE: ${WEB_BUILD_PROFILE:-dev} - container_name: ${COMPOSE_PROJECT_NAME}-web-app - restart: unless-stopped - ports: - - "${WEB_APP_PORT}" - volumes: - # Mount production nginx config (can be adjusted per env) - - ../config/nginx/nginx.prod.conf:/etc/nginx/nginx.conf:Z,ro - depends_on: - api-gateway: - condition: service_started - networks: - meldestelle-network: - aliases: - - web-app - - desktop-app: - build: - context: .. - dockerfile: docker/frontends/desktop-app/Dockerfile - container_name: ${COMPOSE_PROJECT_NAME}-desktop-app - restart: unless-stopped - environment: - API_BASE_URL: http://api-gateway:8081 - ports: - - "${DESKTOP_APP_VNC_PORT}" - - "${DESKTOP_APP_NOVNC_PORT}" - depends_on: - api-gateway: - condition: service_started - networks: - meldestelle-network: - aliases: - - desktop-app - -volumes: - postgres-data: - pgadmin-data: - redis-data: - prometheus-data: - grafana-data: - -networks: - meldestelle-network: - driver: bridge diff --git a/docker/monitoring/prometheus/prometheus.yml b/docker/monitoring/prometheus/prometheus.yml deleted file mode 100644 index 34db49bd..00000000 --- a/docker/monitoring/prometheus/prometheus.yml +++ /dev/null @@ -1,38 +0,0 @@ -# Prometheus configuration for Meldestelle project -# Basic configuration to enable service monitoring - -global: - scrape_interval: 15s - evaluation_interval: 15s - -rule_files: - # - "first_rules.yml" - # - "second_rules.yml" - -scrape_configs: - # The job name is added as a label `job=` to any timeseries scraped from this config. - - job_name: 'prometheus' - static_configs: - - targets: ['localhost:9090'] - - # Monitor API Gateway - - job_name: 'api-gateway' - metrics_path: '/actuator/prometheus' - static_configs: - - targets: ['api-gateway:8081'] - scrape_interval: 30s - - # Monitor other services if they expose metrics - - job_name: 'postgres-exporter' - static_configs: - - targets: ['postgres:5432'] - scrape_interval: 30s - metrics_path: '/metrics' - - # Add consul for service discovery monitoring - - job_name: 'consul' - static_configs: - - targets: ['consul:8500'] - metrics_path: '/v1/agent/metrics' - params: - format: ['prometheus']