diff --git a/.junie/guidelines/README.md b/.junie/guidelines/README.md new file mode 100644 index 00000000..ceb85ec3 --- /dev/null +++ b/.junie/guidelines/README.md @@ -0,0 +1,143 @@ +# Meldestelle Project Guidelines + +**Version:** 2.0.0 +**Last Updated:** 2025-09-13 +**Status:** Reorganized & AI-Optimized + +--- + +## 📋 Overview + +This directory contains the comprehensive development guidelines for the Meldestelle project. The guidelines have been restructured into a hierarchical, AI-assistant-optimized format for better navigation, maintainability, and usability. + +> **🤖 AI-Assistant Note:** +> All guidelines now include structured metadata headers and AI-specific hints for optimal assistant interaction: +> - **Metadata:** Each file has guideline_type, scope, audience, and dependencies +> - **AI Context:** Specific context information for better AI understanding +> - **Cross-References:** Consistent navigation links between related guidelines +> - **Quick Reference:** AI-optimized tables and checklists + +## 🗂️ Guidelines Structure + +### 📊 Master Guideline +- **[Master-Guideline](./master-guideline.md)** - Central project guidelines and architectural foundations + +### 🏗️ Project Standards +Core development standards and quality requirements: + +| Guideline | Scope | AI Context | +|-----------|-------|------------| +| [Coding Standards](./project-standards/coding-standards.md) | Code quality, naming conventions, patterns | Kotlin standards, Result pattern, value classes | +| [Testing Standards](./project-standards/testing-standards.md) | Test strategies, tools, coverage | Test pyramid, Testcontainers, debugging | +| [Documentation Standards](./project-standards/documentation-standards.md) | Documentation language, structure, API docs | German language rules, README templates | +| [Architecture Principles](./project-standards/architecture-principles.md) | Microservices, DDD, EDA, KMP | Clean Architecture, bounded contexts, MVVM | + +### 🔧 Technology Guides +Technology-specific implementation guidelines: + +#### Web Applications +- **[Web App Guideline](./technology-guides/web-app-guideline.md)** - Compose Multiplatform development for desktop and web clients + +#### Docker & Infrastructure +| Docker Module | Focus Area | AI Context | +|---------------|------------|------------| +| [Docker Overview](./technology-guides/docker/docker-overview.md) | Philosophy and principles | Container strategy, security-first approach | +| [Docker Architecture](./technology-guides/docker/docker-architecture.md) | Services and version management | Service categories, centralized versions | +| [Docker Development](./technology-guides/docker/docker-development.md) | Development workflow | Makefile commands, debugging, hot-reload | +| [Docker Production](./technology-guides/docker/docker-production.md) | Production deployment | Security hardening, SSL/TLS, monitoring | +| [Docker Monitoring](./technology-guides/docker/docker-monitoring.md) | Observability setup | Prometheus, Grafana, health checks | +| [Docker Troubleshooting](./technology-guides/docker/docker-troubleshooting.md) | Problem resolution | Common issues, best practices, workflows | + +### 🔄 Process Guides +Development process and workflow guidelines: + +- **[Trace Bullet Guideline](./process-guides/trace-bullet-guideline.md)** - End-to-end architecture validation cycle + +## 🎯 Quick Navigation for AI Assistants + +### Common Development Tasks + +| Task | Primary Guidelines | Supporting Guidelines | +|------|-------------------|----------------------| +| **New Feature Development** | Architecture Principles, Coding Standards | Testing Standards, Docker Development | +| **Frontend Development** | Web App Guideline | Architecture Principles, Coding Standards | +| **Backend Service Creation** | Architecture Principles, Coding Standards | Docker Development, Testing Standards | +| **Infrastructure Setup** | Docker Architecture, Docker Development | Docker Overview, Docker Monitoring | +| **Production Deployment** | Docker Production | Docker Architecture, Docker Monitoring | +| **Testing Implementation** | Testing Standards | Coding Standards, Docker Development | +| **Documentation Writing** | Documentation Standards | All related technical guidelines | +| **Troubleshooting Issues** | Docker Troubleshooting | Docker Development, Docker Monitoring | + +### Key Architectural Decisions + +1. **Microservices Architecture** - See [Architecture Principles](./project-standards/architecture-principles.md) +2. **Domain-Driven Design** - See [Architecture Principles](./project-standards/architecture-principles.md) +3. **Event-Driven Architecture** - See [Architecture Principles](./project-standards/architecture-principles.md) +4. **Kotlin Multiplatform** - See [Web App Guideline](./technology-guides/web-app-guideline.md) +5. **Docker-First Infrastructure** - See [Docker Overview](./technology-guides/docker/docker-overview.md) + +### Technology Stack Quick Reference + +| Layer | Technologies | Guidelines | +|-------|-------------|------------| +| **Frontend** | Kotlin Multiplatform, Compose Multiplatform | Web App Guideline | +| **Backend** | Spring Boot, Kotlin, Clean Architecture | Architecture Principles, Coding Standards | +| **Infrastructure** | Docker, PostgreSQL, Redis, Kafka, Consul | Docker Guides | +| **Monitoring** | Prometheus, Grafana, Zipkin | Docker Monitoring | +| **Testing** | JUnit 5, MockK, Testcontainers | Testing Standards | + +## 🚀 Getting Started + +### For Developers +1. Start with [Master-Guideline](./master-guideline.md) for project overview +2. Review [Architecture Principles](./project-standards/architecture-principles.md) for architectural foundations +3. Follow [Coding Standards](./project-standards/coding-standards.md) for development practices +4. Use [Docker Development](./technology-guides/docker/docker-development.md) for local setup + +### For AI Assistants +1. Each guideline includes structured metadata and AI context +2. Use the `ai_context` field for understanding guideline scope +3. Cross-reference related guidelines through navigation sections +4. Leverage quick reference tables for rapid information access + +### For Project Managers +1. [Trace Bullet Guideline](./process-guides/trace-bullet-guideline.md) for current development cycle +2. [Master-Guideline](./master-guideline.md) for project standards overview +3. Individual guidelines for specific team coordination + +## 📝 Guideline Metadata Format + +All guidelines follow this metadata structure for AI optimization: + +```yaml +--- +guideline_type: "project-standards" | "technology" | "process-guide" +scope: "specific-area-identifier" +audience: ["developers", "ai-assistants", "architects", "devops", "project-managers"] +last_updated: "YYYY-MM-DD" +dependencies: ["list-of-related-guidelines"] +related_files: ["relevant-project-files"] +ai_context: "Brief description for AI understanding" +--- +``` + +## 🔍 Guidelines Maintenance + +### Update Process +1. **Content Changes** → Update specific guideline file +2. **Structural Changes** → Update README.md navigation +3. **New Guidelines** → Add to appropriate category and update index +4. **Deprecated Guidelines** → Archive and update references + +### Quality Assurance +- All guidelines include AI-optimized metadata +- Cross-references are maintained and validated +- Navigation links are consistent across guidelines +- Content follows documentation standards + +--- + +**Last Restructuring:** 2025-09-13 - Complete hierarchical reorganization with AI optimization +**Next Review:** As needed based on project evolution + +**Questions or suggestions?** Update this README.md or reach out to the development team. diff --git a/.junie/guidelines/docker-guideline.md b/.junie/guidelines/docker-guideline.md index 6fe2345c..629b576b 100644 --- a/.junie/guidelines/docker-guideline.md +++ b/.junie/guidelines/docker-guideline.md @@ -1,9 +1,9 @@ # Docker-Guidelines für das Meldestelle-Projekt -> **Version:** 3.0.0 +> **Version:** 3.0.1 > **Datum:** 13. September 2025 > **Autor:** Meldestelle Development Team -> **Letzte Aktualisierung:** 🎯 ZENTRALE DOCKER-VERSIONSVERWALTUNG implementiert - Single Source of Truth für alle Build-Argumente, eliminiert Redundanz in 12+ Dockerfiles, automatisierte Build-Scripts und Version-Update-Utilities +> **Letzte Aktualisierung:** 🎯 ZENTRALE DOCKER-VERSIONSVERWALTUNG vollständig optimiert - Single Source of Truth mit neuesten Monitoring-Versionen (Prometheus v2.54.1, Grafana 11.3.0, Keycloak 26.0.7), erweiterte Script-Funktionalität und vollautomatisierte Version-Updates --- @@ -23,13 +23,18 @@ Das Meldestelle-Projekt implementiert eine **moderne, sicherheitsorientierte Con 1. [Architektur-Überblick](#architektur-überblick) 2. [Zentrale Docker-Versionsverwaltung](#zentrale-docker-versionsverwaltung) 🆕 -3. [Dockerfile-Standards](#dockerfile-standards) -4. [Docker-Compose Organisation](#docker-compose-organisation) -5. [Development-Workflow](#development-workflow) -6. [Production-Deployment](#production-deployment) -7. [Monitoring und Observability](#monitoring-und-observability) -8. [Troubleshooting](#troubleshooting) -9. [Best Practices](#best-practices) +3. [Zentrale Port-Verwaltung](#zentrale-port-verwaltung) 🆕 +4. [Environment-Overrides Vereinheitlichung](#environment-overrides-vereinheitlichung) 🆕 +5. [Docker-Compose Template-System](#docker-compose-template-system) 🆕 +6. [Validierung und Konsistenz-Checks](#validierung-und-konsistenz-checks) 🆕 +7. [IDE-Integration](#ide-integration) 🆕 +8. [Dockerfile-Standards](#dockerfile-standards) +9. [Docker-Compose Organisation](#docker-compose-organisation) +10. [Development-Workflow](#development-workflow) +11. [Production-Deployment](#production-deployment) +12. [Monitoring und Observability](#monitoring-und-observability) +13. [Troubleshooting](#troubleshooting) +14. [Best Practices](#best-practices) --- @@ -74,21 +79,20 @@ graph TB ### Service-Ports Matrix -| Service | Development | Production | Health Check | Debug Port | -|---------|------------|------------|--------------|------------| -| PostgreSQL | 5432 | Internal | pg_isready -U meldestelle -d meldestelle | - | -| Redis | 6379 | Internal | redis-cli ping | - | -| Keycloak | 8180 | 8443 (HTTPS) | /health/ready | - | -| Kafka | 9092 | Internal | kafka-topics --bootstrap-server localhost:9092 --list | - | -| Zookeeper | 2181 | Internal | nc -z localhost 2181 | - | -| Zipkin | 9411 | Internal | /health | - | -| Consul | 8500 | Internal | /v1/status/leader | - | -| Auth Server | 8081 | Internal | /actuator/health/readiness | 5005 | -| Ping Service | 8082 | Internal | /actuator/health/readiness | 5005 | -| Monitoring Server | 8083 | Internal | /actuator/health/readiness | 5005 | -| Prometheus | 9090 | Internal | /-/healthy | - | -| Grafana | 3000 | 3443 (HTTPS) | /api/health | - | -| Nginx | - | 80/443 | /health | - | +| Service | Development | Production | Health Check | Debug Port | Version | +|---------|------------|------------|--------------|------------|---------| +| PostgreSQL | 5432 | Internal | pg_isready -U meldestelle -d meldestelle | - | 16-alpine | +| Redis | 6379 | Internal | redis-cli ping | - | 7-alpine | +| Keycloak | 8180 | 8443 (HTTPS) | /health/ready | - | 26.0.7 | +| Kafka | 9092 | Internal | kafka-topics --bootstrap-server localhost:9092 --list | - | 7.4.0 | +| Zookeeper | 2181 | Internal | nc -z localhost 2181 | - | 7.4.0 | +| Consul | 8500 | Internal | /v1/status/leader | - | 1.15 | +| Auth Server | 8081 | Internal | /actuator/health/readiness | 5005 | 1.0.0 | +| Ping Service | 8082 | Internal | /actuator/health/readiness | 5005 | 1.0.0 | +| Monitoring Server | 8083 | Internal | /actuator/health/readiness | 5005 | 1.0.0 | +| Prometheus | 9090 | Internal | /-/healthy | - | v2.54.1 | +| Grafana | 3000 | 3443 (HTTPS) | /api/health | - | 11.3.0 | +| Nginx | - | 80/443 | /health | - | 1.25-alpine | --- @@ -115,8 +119,11 @@ ARG GRADLE_VERSION=9.0.0 [versions] gradle = "9.0.0" java = "21" -node = "20.11.0" +node = "20.12.0" nginx = "1.25-alpine" +prometheus = "v2.54.1" +grafana = "11.3.0" +keycloak = "26.0.7" ``` ### 🏗️ Architektur der zentralen Versionsverwaltung @@ -137,10 +144,23 @@ docker/ #### 1. **Globale Versionen** (`docker/build-args/global.env`) Verwendet von **allen** Dockerfiles: ```bash +# --- Build Tools --- GRADLE_VERSION=9.0.0 JAVA_VERSION=21 + +# --- Build Metadata --- BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') VERSION=1.0.0 + +# --- Common Base Images --- +ALPINE_VERSION=3.19 +ECLIPSE_TEMURIN_JDK_VERSION=21-jdk-alpine +ECLIPSE_TEMURIN_JRE_VERSION=21-jre-alpine + +# --- Monitoring & Infrastructure Services --- +DOCKER_PROMETHEUS_VERSION=v2.54.1 +DOCKER_GRAFANA_VERSION=11.3.0 +DOCKER_KEYCLOAK_VERSION=26.0.7 ``` #### 2. **Kategorie-spezifische Versionen** @@ -198,6 +218,15 @@ AUTH_SERVER_PORT=8087 # Gradle auf 9.1.0 upgraden ./scripts/docker-versions-update.sh update gradle 9.1.0 +# Prometheus auf neueste Version upgraden +./scripts/docker-versions-update.sh update prometheus v2.54.1 + +# Grafana auf neueste Version upgraden +./scripts/docker-versions-update.sh update grafana 11.3.0 + +# Keycloak auf neueste Version upgraden +./scripts/docker-versions-update.sh update keycloak 26.0.7 + # Alle Environment-Dateien synchronisieren ./scripts/docker-versions-update.sh sync ``` @@ -343,6 +372,560 @@ cp dockerfiles/templates/spring-boot-service.Dockerfile dockerfiles/services/my- --- +## 🔌 Zentrale Port-Verwaltung + +### Überblick + +Mit **Version 3.1.0** führen wir ein revolutionäres Feature ein: die **zentrale Port-Verwaltung** über `docker/versions.toml`. Dieses System eliminiert Port-Konflikte und schafft eine einheitliche Port-Registry für alle Services. + +### 🎯 Single Source of Truth für Ports + +```toml +# docker/versions.toml - Port-Registry +[service-ports] +# --- Infrastructure Services --- +api-gateway = 8081 +auth-server = 8087 +monitoring-server = 8088 + +# --- Application Services --- +ping-service = 8082 +members-service = 8083 +horses-service = 8084 +events-service = 8085 +masterdata-service = 8086 + +# --- External Services --- +postgres = 5432 +redis = 6379 +keycloak = 8180 +consul = 8500 +zookeeper = 2181 +kafka = 9092 + +# --- Monitoring Stack --- +prometheus = 9090 +grafana = 3000 + +# --- Client Applications --- +web-app = 4000 +desktop-app-vnc = 5901 +desktop-app-novnc = 6080 +``` + +### 🏗️ Port-Range-Management + +```toml +[port-ranges] +# --- Automatische Port-Zuweisung --- +infrastructure = "8081-8088" +services = "8082-8099" +monitoring = "9090-9099" +clients = "4000-4099" +vnc = "5901-5999" +debug = "5005-5009" + +# --- Reserved Ranges --- +system-reserved = "0-1023" +ephemeral = "32768-65535" +``` + +### ⚡ Automatische Port-Integration + +#### Docker-Compose Integration +```yaml +# Ports werden automatisch aus versions.toml gelesen +api-gateway: + ports: + - "${GATEWAY_PORT:-8081}:8081" + environment: + - SERVER_PORT=${GATEWAY_PORT:-8081} + +ping-service: + ports: + - "${PING_SERVICE_PORT:-8082}:8082" + environment: + - SERVER_PORT=${PING_SERVICE_PORT:-8082} +``` + +#### Script-basierte Port-Validierung +```bash +# scripts/validate-port-conflicts.sh +#!/bin/bash +validate_port_conflicts() { + local used_ports=($(grep -o '[0-9]\{4,5\}' docker/versions.toml | sort -n)) + + for port in "${used_ports[@]}"; do + if netstat -tulpn 2>/dev/null | grep -q ":$port "; then + echo "⚠️ Port $port ist bereits belegt!" + fi + done +} +``` + +### 📊 Port-Registry Vorteile + +1. **Keine Konflikte**: Automatische Port-Konflikt-Erkennung +2. **Skalierbarkeit**: Einfaches Hinzufügen neuer Services +3. **Dokumentation**: Selbst-dokumentierende Port-Zuweisungen +4. **Konsistenz**: Einheitliche Port-Konventionen +5. **Automatisierung**: Script-basierte Port-Verwaltung + +--- + +## ⚙️ Environment-Overrides Vereinheitlichung + +### Zentrale Environment-Konfiguration + +**Version 3.1.0** standardisiert Environment-Overrides für verschiedene Deployment-Szenarien: + +```toml +# docker/versions.toml - Environment-spezifische Konfigurationen +[environments.development] +spring-profiles = "dev" +debug-enabled = true +log-level = "DEBUG" +health-check-interval = "30s" +health-check-timeout = "5s" +health-check-retries = 3 +health-check-start-period = "40s" +resource-limits = false +jvm-debug-port = 5005 +hot-reload = true + +[environments.production] +spring-profiles = "prod" +debug-enabled = false +log-level = "INFO" +health-check-interval = "15s" +health-check-timeout = "3s" +health-check-retries = 3 +health-check-start-period = "30s" +resource-limits = true +jvm-debug-port = false +hot-reload = false +security-headers = true +tls-enabled = true + +[environments.testing] +spring-profiles = "test" +debug-enabled = true +log-level = "DEBUG" +health-check-interval = "10s" +health-check-timeout = "5s" +health-check-retries = 2 +health-check-start-period = "20s" +resource-limits = false +jvm-debug-port = 5005 +hot-reload = false +ephemeral-storage = true +test-containers = true +``` + +### 🚀 Environment-basierte Deployments + +#### Development Environment +```bash +# Development mit Hot-Reload und Debug +export DOCKER_ENVIRONMENT=development +docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d +``` + +#### Production Environment +```bash +# Production mit Security und Resource-Limits +export DOCKER_ENVIRONMENT=production +docker-compose -f docker-compose.prod.yml up -d +``` + +#### Testing Environment +```bash +# Testing mit schnellen Health-Checks +export DOCKER_ENVIRONMENT=testing +docker-compose -f docker-compose.test.yml up -d +``` + +### ⚙️ Automatische Environment-Anpassung + +```bash +# scripts/apply-environment.sh +#!/bin/bash +apply_environment_settings() { + local env=${1:-development} + + # Aus versions.toml lesen und anwenden + case $env in + "development") + export DEBUG=true + export LOG_LEVEL=DEBUG + export SPRING_PROFILES_ACTIVE=dev + ;; + "production") + export DEBUG=false + export LOG_LEVEL=INFO + export SPRING_PROFILES_ACTIVE=prod + ;; + "testing") + export DEBUG=true + export LOG_LEVEL=DEBUG + export SPRING_PROFILES_ACTIVE=test + ;; + esac +} +``` + +--- + +## 📝 Docker-Compose Template-System + +### Template-basierte Compose-Generierung + +**Version 3.1.0** führt ein mächtiges Template-System ein, das Docker-Compose-Dateien aus zentralen Konfigurationen generiert: + +```bash +# scripts/generate-compose-files.sh +#!/bin/bash +generate_service_definition() { + local service=$1 + local category=$2 + local port=$(get_service_port $service) + + cat << EOF + $service: + build: + context: . + dockerfile: dockerfiles/$category/$service/Dockerfile + args: +$(generate_build_args_for_category $category) + container_name: meldestelle-$service + ports: + - "$port:$port" + environment: +$(generate_environment_vars_for_service $service) + networks: + - meldestelle-network + healthcheck: + test: ["CMD", "curl", "--fail", "http://localhost:$port/actuator/health"] + interval: \${HEALTH_CHECK_INTERVAL:-15s} + timeout: \${HEALTH_CHECK_TIMEOUT:-3s} + retries: \${HEALTH_CHECK_RETRIES:-3} + start_period: \${HEALTH_CHECK_START_PERIOD:-30s} + restart: unless-stopped +EOF +} +``` + +### 🎯 Service-Kategorien Templates + +#### Services Template +```bash +generate_services_compose() { + local services=($(get_services_from_toml)) + + echo "# Generated from docker/versions.toml" + echo "services:" + + for service in "${services[@]}"; do + generate_service_definition "$service" "services" + done +} +``` + +#### Infrastructure Template +```bash +generate_infrastructure_compose() { + local infrastructure=($(get_infrastructure_from_toml)) + + for infra in "${infrastructure[@]}"; do + generate_service_definition "$infra" "infrastructure" + done +} +``` + +### 📊 Template-System Vorteile + +1. **DRY-Prinzip**: Keine Duplikation in Compose-Dateien +2. **Konsistenz**: Einheitliche Service-Definitionen +3. **Skalierbarkeit**: Einfaches Hinzufügen neuer Services +4. **Wartbarkeit**: Zentrale Template-Verwaltung +5. **Automatisierung**: Script-basierte Generierung + +--- + +## ✅ Validierung und Konsistenz-Checks + +### Automatisierte Docker-Konsistenz-Prüfung + +**Version 3.1.0** implementiert umfassende Validierungstools: + +```bash +# scripts/validate-docker-consistency.sh +#!/bin/bash +validate_dockerfile_args() { + echo "🔍 Validating Dockerfile ARG usage..." + + for dockerfile in $(find dockerfiles -name "Dockerfile"); do + echo "Checking $dockerfile..." + + # Prüfe ARG-Deklarationen + grep "^ARG " "$dockerfile" | while read arg_line; do + local arg_name=$(echo "$arg_line" | cut -d' ' -f2 | cut -d'=' -f1) + validate_arg_in_toml "$arg_name" "$dockerfile" + done + done +} + +validate_compose_versions() { + echo "🔍 Validating docker-compose version references..." + + for compose_file in docker-compose*.yml; do + echo "Checking $compose_file..." + + # Prüfe ${DOCKER_*_VERSION} Referenzen + grep -o '\${DOCKER_[^}]*}' "$compose_file" | sort -u | while read var_ref; do + validate_version_mapping "$var_ref" "$compose_file" + done + done +} + +validate_port_assignments() { + echo "🔍 Validating port assignments..." + + # Prüfe Port-Duplikate + local ports=($(grep -o '[0-9]\{4,5\}' docker/versions.toml | sort)) + local unique_ports=($(printf '%s\n' "${ports[@]}" | sort -u)) + + if [ ${#ports[@]} -ne ${#unique_ports[@]} ]; then + echo "❌ Duplicate ports found in versions.toml!" + return 1 + fi + + echo "✅ No port conflicts detected" +} +``` + +### 🏗️ Build-Validierung + +```bash +validate_build_consistency() { + echo "🔍 Validating build consistency..." + + # Template-Konsistenz prüfen + for template in dockerfiles/templates/*.Dockerfile; do + validate_template_args "$template" + done + + # Service-spezifische Dockerfiles prüfen + for service_dockerfile in dockerfiles/{services,infrastructure,clients}/*/Dockerfile; do + validate_service_dockerfile "$service_dockerfile" + done + + echo "✅ Build consistency validation complete" +} +``` + +### 🛠️ Kontinuierliche Validierung + +```bash +# .github/workflows/docker-validation.yml (Beispiel) +name: Docker Consistency Validation + +on: [push, pull_request] + +jobs: + validate-docker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Validate Docker Consistency + run: | + chmod +x scripts/validate-docker-consistency.sh + ./scripts/validate-docker-consistency.sh + - name: Validate Build Args + run: | + ./scripts/docker-versions-update.sh sync + git diff --exit-code docker/build-args/ +``` + +--- + +## 🔧 IDE-Integration + +### VS Code Integration + +**Version 3.1.0** bietet umfassende IDE-Unterstützung: + +**Datei:** `.vscode/settings.json` + +```json +{ + "yaml.schemas": { + "./docker/schemas/versions-schema.json": "docker/versions.toml" + }, + "files.associations": { + "docker/versions.toml": "toml", + "docker-compose*.yml": "dockercompose" + }, + "docker.defaultBuildArgs": { + "GRADLE_VERSION": "${config:docker.gradleVersion}", + "JAVA_VERSION": "${config:docker.javaVersion}" + }, + "docker.composeCommand": "docker-compose", + "docker.composeFiles": [ + "docker-compose.yml", + "docker-compose.services.yml", + "docker-compose.clients.yml" + ] +} +``` + +### 📋 JSON Schema für TOML-Validierung + +**Datei:** `docker/schemas/versions-schema.json` + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Docker Versions TOML Schema", + "type": "object", + "properties": { + "versions": { + "type": "object", + "properties": { + "gradle": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$", + "description": "Gradle version" + }, + "java": { + "type": "string", + "enum": ["17", "21", "22"], + "description": "Java LTS version" + }, + "prometheus": { + "type": "string", + "pattern": "^v[0-9]+\\.[0-9]+\\.[0-9]+$", + "description": "Prometheus version with 'v' prefix" + }, + "grafana": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$", + "description": "Grafana version" + } + }, + "required": ["gradle", "java"], + "additionalProperties": true + }, + "service-ports": { + "type": "object", + "patternProperties": { + ".*": { + "type": "integer", + "minimum": 1024, + "maximum": 65535 + } + } + }, + "environments": { + "type": "object", + "properties": { + "development": {"$ref": "#/definitions/environment"}, + "production": {"$ref": "#/definitions/environment"}, + "testing": {"$ref": "#/definitions/environment"} + } + } + }, + "definitions": { + "environment": { + "type": "object", + "properties": { + "spring-profiles": {"type": "string"}, + "debug-enabled": {"type": "boolean"}, + "log-level": {"enum": ["DEBUG", "INFO", "WARN", "ERROR"]}, + "resource-limits": {"type": "boolean"} + } + } + } +} +``` + +### 🚀 IntelliJ IDEA Integration + +```xml + + + + + + +``` + +### ⚡ Auto-Completion und Hints + +#### VS Code Tasks + +**Datei:** `.vscode/tasks.json` + +```json +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Docker: Show Versions", + "type": "shell", + "command": "./scripts/docker-versions-update.sh", + "args": ["show"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always" + } + }, + { + "label": "Docker: Validate Consistency", + "type": "shell", + "command": "./scripts/validate-docker-consistency.sh", + "group": "build" + }, + { + "label": "Docker: Build All Services", + "type": "shell", + "command": "./scripts/docker-build.sh", + "args": ["all"], + "group": "build" + } + ] +} +``` + +### 🔧 Development Shortcuts + +#### Command Palette Commands + +**Datei:** `.vscode/settings.json` (erweiterte Konfiguration) + +```json +{ + "workbench.commandPalette.history": 100, + "terminal.integrated.profiles.linux": { + "Docker Commands": { + "path": "bash", + "args": ["-c", "echo 'Docker utilities loaded'; bash"] + } + }, + "docker.enableDockerComposeLanguageService": true, + "docker.enableDockerfileLanguageService": true +} +``` + +--- + ## 🐳 Dockerfile-Standards ### Template-Struktur @@ -1214,6 +1797,169 @@ docker-compose logs -f --tail=50 SERVICE_NAME 4. **Documentation**: Aktuelle README-Dateien pro Service 5. **Testing**: Automatisierte Container-Tests +### 🎯 Zentrale Verwaltung Best Practices (Version 3.2.0) + +#### **Single Source of Truth Prinzipien** + +```bash +# ✅ RICHTIG - Zentrale Version-Updates +./scripts/docker-versions-update.sh update java 22 +./scripts/docker-versions-update.sh sync + +# ❌ FALSCH - Manuelle Bearbeitung von Dockerfiles +vim dockerfiles/services/ping-service/Dockerfile # Version hardcoden +``` + +#### **Port-Verwaltung Richtlinien** + +1. **Immer zentrale Port-Registry verwenden**: + ```toml + # docker/versions.toml - Port-Definitionen + [service-ports] + new-service = 8089 # Nächster verfügbarer Port + ``` + +2. **Port-Konflikte vor Deployment prüfen**: + ```bash + ./scripts/validate-docker-consistency.sh + ``` + +3. **Port-Ranges einhalten**: + - Infrastructure: 8081-8088 + - Services: 8082-8099 + - Monitoring: 9090-9099 + - Clients: 4000-4099 + +#### **Environment-Overrides Standards** + +1. **Environment-spezifische Konfigurationen nutzen**: + ```bash + # Development + export DOCKER_ENVIRONMENT=development + + # Production + export DOCKER_ENVIRONMENT=production + ``` + +2. **Konsistente Health-Check-Konfigurationen**: + ```toml + [environments.production] + health-check-interval = "15s" + health-check-timeout = "3s" + health-check-retries = 3 + ``` + +#### **Template-System Richtlinien** + +1. **Compose-Files aus Templates generieren**: + ```bash + # Automatische Generierung bevorzugen + ./scripts/generate-compose-files.sh + + # Manuelle Bearbeitung nur bei spezifischen Anpassungen + ``` + +2. **Service-Kategorien korrekt zuordnen**: + - `services/`: Domain-Services (ping, members, horses) + - `infrastructure/`: Platform-Services (gateway, auth, monitoring) + - `clients/`: Frontend-Anwendungen (web-app, desktop-app) + +#### **Validierung und Konsistenz** + +1. **Regelmäßige Konsistenz-Prüfungen**: + ```bash + # Bei jedem Build + ./scripts/validate-docker-consistency.sh + + # In CI/CD Pipeline integrieren + ``` + +2. **Build-Args Konsistenz**: + ```dockerfile + # ✅ RICHTIG - Zentrale Referenz + ARG GRADLE_VERSION + ARG JAVA_VERSION + + # ❌ FALSCH - Hardcodierte Versionen + ARG GRADLE_VERSION=9.0.0 + ``` + +#### **IDE-Integration Best Practices** + +1. **JSON Schema für Validierung aktivieren**: + ```json + { + "yaml.schemas": { + "./docker/schemas/versions-schema.json": "docker/versions.toml" + } + } + ``` + +2. **Automatisierte Tasks nutzen**: + - Docker: Show Versions + - Docker: Validate Consistency + - Docker: Build All Services + +### 🚀 Entwickler-Workflow Best Practices (Version 3.2.0) + +#### **Neuen Service hinzufügen** + +```bash +# 1. Port in versions.toml reservieren +echo "new-service = 8089" >> docker/versions.toml + +# 2. Template-basierten Service erstellen +cp dockerfiles/templates/spring-boot-service.Dockerfile \ + dockerfiles/services/new-service/Dockerfile + +# 3. Compose-Definition generieren +./scripts/generate-compose-files.sh + +# 4. Konsistenz validieren +./scripts/validate-docker-consistency.sh + +# 5. Build und Test +./scripts/docker-build.sh services +``` + +#### **Version-Updates Workflow** + +```bash +# 1. Zentrale Version aktualisieren +./scripts/docker-versions-update.sh update java 22 + +# 2. Environment-Files synchronisieren (automatisch) +# 3. Alle Services neu bauen +./scripts/docker-build.sh all + +# 4. Tests ausführen +docker-compose -f docker-compose.test.yml up -d +./gradlew test + +# 5. Commit und Deploy +git add docker/versions.toml docker/build-args/ +git commit -m "Update Java to version 22" +``` + +#### **Production-Deployment Workflow** + +```bash +# 1. Environment auf Production setzen +export DOCKER_ENVIRONMENT=production + +# 2. Production-spezifische Validierung +./scripts/validate-docker-consistency.sh + +# 3. Security-Konfiguration anwenden +./scripts/apply-environment.sh production + +# 4. Production-Build +docker-compose -f docker-compose.prod.yml build + +# 5. Health-Check-basiertes Deployment +docker-compose -f docker-compose.prod.yml up -d +``` + ### 📦 Build Best Practices ```dockerfile @@ -1269,6 +2015,27 @@ brew install ctop # Container-Monitoring-Tool | Version | Datum | Änderungen | |---------|-------|------------| +| 3.2.0 | 2025-09-13 | **Vollständiges "Single Source of Truth" System implementiert:** | +| | | • **🔌 Zentrale Port-Verwaltung:** Port-Registry in docker/versions.toml mit automatischer Konflikt-Erkennung | +| | | • **⚙️ Environment-Overrides Vereinheitlichung:** Zentrale Konfiguration für dev/test/prod Umgebungen | +| | | • **📝 Docker-Compose Template-System:** Automatische Generierung von Compose-Files aus TOML-Konfiguration | +| | | • **✅ Validierung und Konsistenz-Checks:** Umfassende Docker-Konsistenz-Prüfung mit scripts/validate-docker-consistency.sh | +| | | • **🔧 IDE-Integration:** VS Code/IntelliJ Unterstützung mit JSON Schema, Tasks und Auto-Completion | +| | | • **📊 Port-Range-Management:** Automatische Port-Zuweisung mit definierten Bereichen für Service-Kategorien | +| | | • **🚀 Entwickler-Workflow Optimierung:** Template-basierte Service-Erstellung und automatisierte Workflows | +| | | • **🎯 Best Practices erweitert:** Umfassende Richtlinien für zentrale Verwaltung und Entwickler-Workflows | +| | | • **📋 JSON Schema Validierung:** Vollständige TOML-Struktur-Validierung mit IDE-Integration | +| | | • **⚡ Template-System:** Service-Kategorien-basierte Compose-Generierung mit automatischer Build-Args-Integration | +| 3.0.1 | 2025-09-13 | **Zentrale Docker-Versionsverwaltung - Vollständige Optimierung:** | +| | | • **Monitoring-Tool-Updates:** Prometheus v2.54.1, Grafana 11.3.0, Keycloak 26.0.7 | +| | | • **Erweiterte Script-Funktionalität:** docker-versions-update.sh unterstützt alle Monitoring-Tools | +| | | • **Automatisierte Version-Synchronisation:** Environment-Dateien mit neuen Monitoring-Versionen | +| | | • **Vollautomatisierte Version-Updates:** Single-Command-Updates für alle Infrastructure-Services | +| | | • **Service-Ports-Matrix erweitert:** Versions-Spalte mit aktuellen Tool-Versionen hinzugefügt | +| | | • **Build-Args-Architektur vervollständigt:** global.env mit Monitoring & Infrastructure Services | +| | | • **Docker-Compose zentrale Versionsverwaltung:** Alle Services nutzen ${DOCKER_*_VERSION} | +| | | • **Entwickler-Workflow optimiert:** Beispiele für Prometheus, Grafana, Keycloak Updates | +| 3.0.0 | 2025-09-13 | **Zentrale Docker-Versionsverwaltung implementiert** | | 1.1.0 | 2025-08-16 | **Umfassende Überarbeitung und Optimierung:** | | | | • Aktualisierung aller Dockerfile-Templates auf aktuelle Implementierung | | | | • Integration von BuildKit Cache Mounts für optimale Build-Performance | diff --git a/.junie/guidelines/master-guideline.md b/.junie/guidelines/master-guideline.md index 30120aba..29480a92 100644 --- a/.junie/guidelines/master-guideline.md +++ b/.junie/guidelines/master-guideline.md @@ -20,162 +20,79 @@ Unsere Architektur basiert auf **vier Säulen**: --- -## 2. Coding Conventions & Code-Qualität +## 2. Coding Standards & Code-Qualität -### 2.1. Sprach- und Stilstandards +Detaillierte Coding-Standards und Qualitätsrichtlinien finden Sie in: +**→ [Coding Standards](./project-standards/coding-standards.md)** -* **Primärsprache:** Kotlin (JVM/Multiplatform) -* **Java-Kompatibilität:** Ziel ist Java 21+ -* **Code-Stil:** Offizielle Kotlin Coding Conventions, durch `Detekt` geprüft. - -### 2.2. Namenskonventionen - -* **Klassen & Interfaces:** `PascalCase` (z.B. `MemberService`, `EventRepository`) -* **Funktionen & Variablen:** `camelCase` (z.B. `authenticateUser`, `memberRepository`) -* **Testmethoden:** Beschreibend mit Backticks (z.B. `` `should return Success for valid credentials` ``) -* **Konstanten:** `SCREAMING_SNAKE_CASE` (z.B. `MAX_RETRY_ATTEMPTS`) -* **Enums:** `PascalCase` für Werte (z.B. `MemberStatus.ACTIVE`) - -### 2.3. Value Classes für Typsicherheit - -Primitive Typen (UUID, String, Long) für IDs oder spezifische Werte müssen in typsichere `value class`-Wrapper gekapselt -werden. - -```kotlin - @JvmInline -value class MemberId(val value: UUID) { - companion object { - fun of(value: String): Result = - runCatching { UUID.fromString(value) } - .map { MemberId(it) } - .mapError { ValidationError.INVALID_UUID } - } -} -``` - -### 2.4. Error-Handling & Logging - -* **`Result`-Pattern:** Für erwartbare Geschäftsfehler ist das `Result`-Pattern zu verwenden. Exceptions sind für - unerwartete, technische Fehler reserviert. - -* **Fehler-Hierarchie:** Wir verwenden eine `sealed class`-Hierarchie, um Fehlerarten klar zu kategorisieren ( - `DomainError`, `ValidationError`, `BusinessError`, `TechnicalError`). - -* **Structured Logging:** Logs müssen strukturiert sein und eine Korrelations-ID enthalten, um Anfragen über - Service-Grenzen hinweg zu verfolgen. - -```kotlin - logger.info { - "Creating member" with mapOf( - "memberId" to command.memberId.value, - "correlationId" to MDC.get("correlationId") - ) -} -``` +Kernpunkte: +- **Primärsprache:** Kotlin (JVM/Multiplatform) mit Java 21+ Kompatibilität +- **Namenskonventionen:** PascalCase für Klassen, camelCase für Funktionen +- **Value Classes:** Typsichere Wrapper für primitive Typen +- **Result-Pattern:** Für erwartbare Geschäftsfehler +- **Structured Logging:** Mit Korrelations-IDs --- -## 3. Backend-Entwicklungsrichtlinien +## 3. Architecture Principles & Backend-Entwicklung -### 3.1. Microservice-Struktur (Clean Architecture) +Detaillierte Architektur-Prinzipien und Backend-Entwicklungsrichtlinien finden Sie in: +**→ [Architecture Principles](./project-standards/architecture-principles.md)** -Jeder fachliche Microservice folgt der 4-Layer-Struktur (`api`, `application`, `domain`, `infrastructure`). - -### 3.2. Repository-Pattern - -Jede Repository-Methode muss das `Result`-Pattern verwenden. - -```kotlin - interface MemberRepository { - suspend fun findById(id: MemberId): Result - suspend fun save(member: Member): Result -} -``` - -### 3.3. Messaging & Event-Naming - -* **Event-Naming Convention:** Domänen-Events folgen dem Muster `{Domain}{Entity}{Action}Event`. - -```kotlin - data class MemberPersonalDataUpdatedEvent(...) : DomainEvent(...) -``` +Kernpunkte: +- **Clean Architecture:** 4-Layer-Struktur (api, application, domain, infrastructure) +- **DDD:** Domain-Driven Design mit Bounded Contexts +- **EDA:** Event-Driven Architecture mit Kafka +- **Repository-Pattern:** Alle Methoden verwenden Result-Pattern --- -## 4. Frontend-Entwicklungsrichtlinien +## 4. Frontend-Entwicklung & Multiplatform -Das Frontend folgt konsequent dem **Model-View-ViewModel (MVVM)**-Muster und der **Kotlin Multiplatform (KMP)** --Strategie. Der UI-Code wird nach **fachlichen Features** (vertikale Schnitte) strukturiert. +Detaillierte Frontend-Entwicklungsrichtlinien finden Sie in: +**→ [Web App Guideline](./technology-guides/web-app-guideline.md)** + +Kernpunkte: +- **MVVM-Pattern:** Model-View-ViewModel für UI-Struktur +- **Kotlin Multiplatform:** Code-Sharing zwischen Desktop und Web +- **Compose Multiplatform:** Deklarative UI mit @Composable-Funktionen +- **Feature-basierte Struktur:** Vertikale Schnitte nach Fachlichkeit --- -## 5. Testing +## 5. Testing Standards -Tests sind ein integraler Bestandteil jedes Features und müssen einen hohen Standard erfüllen. +Detaillierte Testing-Standards finden Sie in: +**→ [Testing Standards](./project-standards/testing-standards.md)** -### 5.1. Test-Pyramide & Werkzeuge - -* **Unit-Tests (80 %+ Abdeckung):** Für Domänen- und Anwendungslogik (JUnit 5, MockK). - -* **Integrationstests:** Decken alle Repository-Implementierungen und externen Integrationen ab. - -* **Testcontainers als Goldstandard:** Jede Interaktion mit externer Infrastruktur (DB, Cache, Broker) **muss** mit - **Testcontainers** getestet werden. - -### 5.2. Debugging - -Debug-Ausgaben im Test-Code müssen mit `[DEBUG_LOG]` beginnen, um sie leicht identifizieren und filtern zu können. +Kernpunkte: +- **Test-Pyramide:** 80%+ Unit-Tests, Integrationstests für externe Systeme +- **Testcontainers:** Goldstandard für Infrastruktur-Tests +- **Result-Pattern:** Tests für Success- und Failure-Cases +- **Debug-Logs:** `[DEBUG_LOG]`-Präfix für Test-Ausgaben --- -## 6. Infrastruktur- & Betriebs-Spezifikationen +## 6. Docker & Infrastructure -### 6.1. Kafka-Konfiguration +Detaillierte Docker- und Infrastruktur-Richtlinien finden Sie in: +**→ [Docker Guidelines](./technology-guides/docker/)** -Die Konfiguration muss auf maximale Zuverlässigkeit ausgelegt sein: - -```yaml - # in application.yml - kafka: - producer: - acks: all - enable-idempotence: true - max-in-flight-requests-per-connection: 1 - consumer: - group-id-prefix: "meldestelle-${spring.application.name}" - auto-offset-reset: earliest - enable-auto-commit: false -``` - -### 6.2. Datenbank-Migrationen (Flyway) - -Migrations-Skripte müssen einer klaren Namenskonvention folgen. - -* **Pattern:** `V{version}__{description}.sql` (z.B., `V001__Create_member_tables.sql`) - -* **Repeatable:** `R__{description}.sql` (z.B., `R__Update_member_view.sql`) - -### 6.3. API-Dokumentation (OpenAPI) - -Alle öffentlichen REST-Endpunkte müssen mit OpenAPI-Annotationen (`@Operation`, `@ApiResponse`) dokumentiert werden, um -eine klare und interaktive API-Dokumentation zu generieren. +Kernpunkte: +- **Docker-Architektur:** Microservices mit Service Discovery +- **Zentrale Versionsverwaltung:** Single Source of Truth +- **Monitoring:** Prometheus & Grafana +- **Security:** Non-Root-Container, SSL/TLS everywhere --- -## 7. Dokumentationsstandards +## 7. Documentation Standards -### 7.1. Sprache für Dokumentation +Detaillierte Dokumentationsstandards finden Sie in: +**→ [Documentation Standards](./project-standards/documentation-standards.md)** -* **README-Dateien:** Alle README-Dokumentationen im Projekt müssen in **deutscher Sprache** verfasst werden. - Dies gewährleistet Konsistenz und Zugänglichkeit für das deutsche Entwicklungsteam. - -* **Code-Kommentare:** Komplexe Geschäftslogik und fachliche Zusammenhänge sollen in deutscher Sprache kommentiert werden. - -* **API-Dokumentation:** OpenAPI-Beschreibungen und -Beispiele sind bevorzugt in deutscher Sprache zu verfassen, - sofern keine internationalen Anforderungen bestehen. - -### 7.2. Dokumentationsstruktur - -* README-Dateien sollen eine einheitliche Struktur befolgen: Überblick, Architektur, Entwicklung, Tests, Deployment. - -* Technische Begriffe dürfen in englischer Originalform verwendet werden, wenn keine etablierte deutsche Übersetzung existiert. +Kernpunkte: +- **Sprache:** README-Dateien auf Deutsch, Code-Kommentare je nach Kontext +- **Struktur:** Einheitliche README-Template +- **API-Docs:** OpenAPI-Annotationen mit deutschen Beschreibungen +- **Versionierung:** Dokumentation wird mit Code versioniert diff --git a/.junie/guidelines/trace-bullet-guideline.md b/.junie/guidelines/process-guides/trace-bullet-guideline.md similarity index 81% rename from .junie/guidelines/trace-bullet-guideline.md rename to .junie/guidelines/process-guides/trace-bullet-guideline.md index 05be3b1f..318c271e 100644 --- a/.junie/guidelines/trace-bullet-guideline.md +++ b/.junie/guidelines/process-guides/trace-bullet-guideline.md @@ -1,9 +1,26 @@ # Guideline: Zyklus "Tracer Bullet" +--- +guideline_type: "process-guide" +scope: "trace-bullet-development-cycle" +audience: ["developers", "ai-assistants", "project-managers"] +last_updated: "2025-09-13" +dependencies: ["master-guideline.md", "web-app-guideline.md"] +related_files: ["docker-compose.yml", "temp/ping-service/**", "client/**"] +ai_context: "End-to-end architecture validation cycle, infrastructure testing, ping service implementation" +--- + * **Zyklus-Start:** 15. August 2025 * **Status:** In Arbeit -* **Basis:** Diese Guideline erweitert die [Master-Guideline](./master-guideline.md) -* **Frontend-Standard:** Alle Web-Frontend-Entwicklung erfolgt gemäß der [`web-app-guideline.md`](./web-app-guideline.md), die ab sofort der verbindliche Standard ist. +* **Basis:** Diese Guideline erweitert die [Master-Guideline](../master-guideline.md) +* **Frontend-Standard:** Alle Web-Frontend-Entwicklung erfolgt gemäß der [Web-App-Guideline](../technology-guides/web-app-guideline.md), die ab sofort der verbindliche Standard ist. + +> **🤖 AI-Assistant Hinweis:** +> Der Tracer Bullet Zyklus validiert die End-to-End-Architektur: +> - **Ziel:** Technische Infrastruktur von Client bis Backend testen +> - **Ping-Service:** Minimaler Test-Service für Architektur-Validierung +> - **MVVM:** Client folgt strikt dem MVVM-Pattern mit Compose Multiplatform +> - **Definition of Done:** Vollständiger E2E-Test muss erfolgreich sein ## 1. Ziel des Zyklus @@ -108,3 +125,12 @@ Dieser Zyklus ist abgeschlossen, wenn **alle** der folgenden Kriterien erfüllt - [ ] Was hat gut funktioniert? - [ ] Was würden wir beim nächsten Zyklus anders machen? - [ ] Welche Standards müssen in die Master-Guideline übernommen werden? + +--- + +**Navigation:** +- [Master-Guideline](../master-guideline.md) - Übergeordnete Projektrichtlinien +- [Web-App-Guideline](../technology-guides/web-app-guideline.md) - Frontend-Entwicklungsstandard +- [Architecture-Principles](../project-standards/architecture-principles.md) - Architektur-Grundsätze +- [Docker Guidelines](../technology-guides/docker/) - Infrastructure und Deployment +- [Testing-Standards](../project-standards/testing-standards.md) - Test-Qualitätssicherung diff --git a/.junie/guidelines/project-standards/architecture-principles.md b/.junie/guidelines/project-standards/architecture-principles.md new file mode 100644 index 00000000..2cdf827e --- /dev/null +++ b/.junie/guidelines/project-standards/architecture-principles.md @@ -0,0 +1,508 @@ +# Architecture Principles und Grundsätze + +--- +guideline_type: "project-standards" +scope: "architecture-principles" +audience: ["developers", "architects", "ai-assistants"] +last_updated: "2025-09-13" +dependencies: ["master-guideline.md"] +related_files: ["build.gradle.kts", "settings.gradle.kts", "docker-compose.yml"] +ai_context: "Architectural foundations, microservices patterns, DDD principles, event-driven architecture, and multiplatform strategy" +--- + +## 🏗️ Vision & Architektonische Grundpfeiler + +Dieses Dokument definiert die verbindlichen technischen Richtlinien und Qualitätsstandards für das Projekt "Meldestelle_Pro". Ziel ist die Schaffung einer modernen, skalierbaren und wartbaren Plattform für den Pferdesport. + +> **🤖 AI-Assistant Hinweis:** +> Die Architektur basiert auf vier Kernsäulen: +> - **Microservices:** Modularität & Skalierbarkeit +> - **DDD:** Fachlichkeit im Code +> - **EDA:** Ereignisgesteuerte Entkopplung +> - **KMP:** Kotlin Multiplatform für Effizienz + +### Die vier Säulen der Architektur + +1. **Modularität & Skalierbarkeit** durch eine **Microservices-Architektur** +2. **Fachlichkeit im Code** durch **Domain-Driven Design (DDD)** +3. **Entkopplung & Resilienz** durch eine **ereignisgesteuerte Architektur (EDA)** +4. **Effizienz & Konsistenz** durch eine **Multiplattform-Client-Strategie (KMP)** + +> **Grundsatz:** Jede Code-Änderung muss diese vier Grundprinzipien respektieren. + +## 🎯 AI-Assistenten: Architektur-Schnellreferenz + +### Architektur-Säulen im Detail + +| Säule | Technologie | Zweck | Umsetzung | +|-------|------------|-------|-----------| +| Microservices | Spring Boot, Docker | Modularität & Skalierbarkeit | Service-per-Domain-Pattern | +| DDD | Kotlin, Clean Architecture | Fachlichkeit im Code | Bounded Contexts, Domain Events | +| EDA | Kafka, Events | Entkopplung & Resilienz | Asynchrone Kommunikation | +| KMP | Kotlin Multiplatform | Effizienz & Konsistenz | Shared Business Logic | + +## 🔧 Backend-Entwicklungsrichtlinien + +### Microservice-Struktur (Clean Architecture) + +Jeder fachliche Microservice folgt der 4-Layer-Struktur (`api`, `application`, `domain`, `infrastructure`). + +``` +service-name/ +├── service-name-api/ # REST-Endpoints, DTOs +├── service-name-application/ # Use Cases, Commands, Queries +├── service-name-domain/ # Domain Models, Events, Services +└── service-name-infrastructure/ # Repositories, External Services +``` + +#### Layer-Verantwortlichkeiten + +**API Layer (`-api`):** +```kotlin +@RestController +@RequestMapping("/api/v1/members") +class MemberController( + private val memberService: MemberService +) { + @PostMapping + fun createMember(@RequestBody request: CreateMemberRequest): ResponseEntity { + val command = CreateMemberCommand( + name = request.name, + email = request.email, + licenseNumber = request.licenseNumber + ) + + return when (val result = memberService.createMember(command)) { + is Result.Success -> ResponseEntity.ok(result.value.toResponse()) + is Result.Failure -> ResponseEntity.badRequest().body(result.error.toErrorResponse()) + } + } +} +``` + +**Application Layer (`-application`):** +```kotlin +@Service +class MemberService( + private val memberRepository: MemberRepository, + private val eventPublisher: EventPublisher +) { + suspend fun createMember(command: CreateMemberCommand): Result { + // Validation + val validationResult = validateCreateMemberCommand(command) + if (validationResult is Result.Failure) { + return validationResult + } + + // Business Logic + val member = Member.create( + name = command.name, + email = command.email, + licenseNumber = command.licenseNumber + ) + + // Persistence + return memberRepository.save(member).map { + // Event Publishing + eventPublisher.publish(MemberCreatedEvent(member)) + member + } + } +} +``` + +**Domain Layer (`-domain`):** +```kotlin +@JvmInline +value class MemberId(val value: UUID) { + companion object { + fun generate(): MemberId = MemberId(UUID.randomUUID()) + } +} + +data class Member private constructor( + val id: MemberId, + val name: String, + val email: Email, + val licenseNumber: LicenseNumber, + val status: MemberStatus = MemberStatus.PENDING +) { + companion object { + fun create( + name: String, + email: String, + licenseNumber: String + ): Result { + return Result.Success( + Member( + id = MemberId.generate(), + name = name, + email = Email.of(email).getOrThrow(), + licenseNumber = LicenseNumber.of(licenseNumber).getOrThrow() + ) + ) + } + } + + fun activate(): Member = copy(status = MemberStatus.ACTIVE) + fun suspend(): Member = copy(status = MemberStatus.SUSPENDED) +} +``` + +**Infrastructure Layer (`-infrastructure`):** +```kotlin +@Repository +class PostgresMemberRepository( + private val jdbcTemplate: JdbcTemplate +) : MemberRepository { + + override suspend fun save(member: Member): Result { + return try { + jdbcTemplate.update( + "INSERT INTO members (id, name, email, license_number, status) VALUES (?, ?, ?, ?, ?)", + member.id.value, + member.name, + member.email.value, + member.licenseNumber.value, + member.status.name + ) + Result.Success(Unit) + } catch (e: DataAccessException) { + Result.Failure(RepositoryError.DATABASE_ERROR) + } + } + + override suspend fun findById(id: MemberId): Result { + return try { + val member = jdbcTemplate.queryForObject( + "SELECT * FROM members WHERE id = ?", + arrayOf(id.value) + ) { rs, _ -> + Member( + id = MemberId(UUID.fromString(rs.getString("id"))), + name = rs.getString("name"), + email = Email.of(rs.getString("email")).getOrThrow(), + licenseNumber = LicenseNumber.of(rs.getString("license_number")).getOrThrow(), + status = MemberStatus.valueOf(rs.getString("status")) + ) + } + Result.Success(member) + } catch (e: EmptyResultDataAccessException) { + Result.Success(null) + } catch (e: DataAccessException) { + Result.Failure(RepositoryError.DATABASE_ERROR) + } + } +} +``` + +### Repository-Pattern + +Jede Repository-Methode muss das `Result`-Pattern verwenden. + +```kotlin +interface MemberRepository { + suspend fun findById(id: MemberId): Result + suspend fun save(member: Member): Result + suspend fun findByEmail(email: Email): Result + suspend fun findByLicenseNumber(licenseNumber: LicenseNumber): Result + suspend fun findAll(pageable: Pageable): Result, RepositoryError> +} +``` + +### Messaging & Event-Naming + +Event-Naming Convention: Domänen-Events folgen dem Muster `{Domain}{Entity}{Action}Event`. + +```kotlin +data class MemberPersonalDataUpdatedEvent( + val memberId: MemberId, + val oldName: String, + val newName: String, + val oldEmail: Email, + val newEmail: Email, + val updatedAt: Instant = Instant.now(), + val correlationId: String = MDC.get("correlationId") ?: UUID.randomUUID().toString() +) : DomainEvent { + override val eventType: String = "member.personal-data.updated" + override val aggregateId: String = memberId.value.toString() + override val version: Int = 1 +} +``` + +## 📱 Frontend-Entwicklungsrichtlinien + +Das Frontend folgt konsequent dem **Model-View-ViewModel (MVVM)**-Muster und der **Kotlin Multiplatform (KMP)**-Strategie. Der UI-Code wird nach **fachlichen Features** (vertikale Schnitte) strukturiert. + +### Multiplatform-Struktur + +``` +client/ +├── src/commonMain/kotlin/ # Shared Business Logic +│ ├── domain/ # Domain Models +│ ├── data/ # Repositories, API-Clients +│ ├── presentation/ # ViewModels, UI-States +│ └── ui/ # Shared UI-Components +├── src/jvmMain/kotlin/ # Desktop-spezifischer Code +│ └── ui/ # Desktop UI-Adaptierungen +└── src/wasmJsMain/kotlin/ # Web-spezifischer Code + └── ui/ # Web UI-Adaptierungen +``` + +### MVVM-Implementation + +**Shared ViewModel (commonMain):** +```kotlin +class MemberListViewModel( + private val memberRepository: MemberRepository +) : ViewModel() { + + private val _uiState = MutableStateFlow(MemberListUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + fun loadMembers() { + viewModelScope.launch { + _uiState.value = _uiState.value.copy(isLoading = true) + + when (val result = memberRepository.getAllMembers()) { + is Result.Success -> { + _uiState.value = _uiState.value.copy( + isLoading = false, + members = result.value, + error = null + ) + } + is Result.Failure -> { + _uiState.value = _uiState.value.copy( + isLoading = false, + error = result.error.message + ) + } + } + } + } +} + +data class MemberListUiState( + val isLoading: Boolean = false, + val members: List = emptyList(), + val error: String? = null +) +``` + +**Shared UI-Component (commonMain):** +```kotlin +@Composable +fun MemberListScreen( + viewModel: MemberListViewModel = viewModel() +) { + val uiState by viewModel.uiState.collectAsState() + + LaunchedEffect(Unit) { + viewModel.loadMembers() + } + + Column { + if (uiState.isLoading) { + CircularProgressIndicator() + } + + uiState.error?.let { error -> + Text( + text = error, + color = MaterialTheme.colorScheme.error + ) + } + + LazyColumn { + items(uiState.members) { member -> + MemberCard( + member = member, + onMemberClick = { /* Handle click */ } + ) + } + } + } +} +``` + +## 🎯 Domain-Driven Design (DDD) Patterns + +### Bounded Contexts + +``` +Meldestelle-Domain/ +├── member-context/ # Mitgliederverwaltung +├── tournament-context/ # Turnierverwaltung +├── horse-context/ # Pferdeverwaltung +├── registration-context/ # Anmeldungen +└── payment-context/ # Zahlungsabwicklung +``` + +### Aggregate Design + +```kotlin +class Tournament private constructor( + val id: TournamentId, + val name: String, + val startDate: LocalDate, + val endDate: LocalDate, + val maxParticipants: Int, + private val registrations: MutableList = mutableListOf() +) { + companion object { + fun create( + name: String, + startDate: LocalDate, + endDate: LocalDate, + maxParticipants: Int + ): Result { + // Business rules validation + if (startDate.isAfter(endDate)) { + return Result.Failure(ValidationError.INVALID_DATE_RANGE) + } + + return Result.Success( + Tournament( + id = TournamentId.generate(), + name = name, + startDate = startDate, + endDate = endDate, + maxParticipants = maxParticipants + ) + ) + } + } + + fun registerMember(memberId: MemberId): Result { + // Business rules + if (registrations.size >= maxParticipants) { + return Result.Failure(BusinessError.TOURNAMENT_FULL) + } + + if (registrations.any { it.memberId == memberId }) { + return Result.Failure(BusinessError.ALREADY_REGISTERED) + } + + val registration = TournamentRegistration( + id = TournamentRegistrationId.generate(), + tournamentId = id, + memberId = memberId, + registrationDate = LocalDateTime.now() + ) + + registrations.add(registration) + + return Result.Success( + TournamentRegistrationCreatedEvent( + tournamentId = id, + memberId = memberId, + registrationId = registration.id + ) + ) + } +} +``` + +### Infrastructure & Betrieb + +#### Kafka-Konfiguration + +Die Konfiguration muss auf maximale Zuverlässigkeit ausgelegt sein: + +```yaml +# application.yml +kafka: + producer: + acks: all + enable-idempotence: true + max-in-flight-requests-per-connection: 1 + consumer: + group-id-prefix: "meldestelle-${spring.application.name}" + auto-offset-reset: earliest + enable-auto-commit: false +``` + +#### Datenbank-Migrationen (Flyway) + +Migrations-Skripte müssen einer klaren Namenskonvention folgen: + +* **Pattern:** `V{version}__{description}.sql` (z.B., `V001__Create_member_tables.sql`) +* **Repeatable:** `R__{description}.sql` (z.B., `R__Update_member_view.sql`) + +#### API-Dokumentation (OpenAPI) + +Alle öffentlichen REST-Endpunkte müssen mit OpenAPI-Annotationen (`@Operation`, `@ApiResponse`) dokumentiert werden, um eine klare und interaktive API-Dokumentation zu generieren. + +```kotlin +@Operation( + summary = "Neues Mitglied erstellen", + description = "Erstellt ein neues Mitglied mit den angegebenen Daten" +) +@ApiResponses( + value = [ + ApiResponse( + responseCode = "201", + description = "Mitglied erfolgreich erstellt" + ), + ApiResponse( + responseCode = "400", + description = "Ungültige Eingabedaten" + ) + ] +) +@PostMapping +fun createMember(@RequestBody request: CreateMemberRequest): ResponseEntity +``` + +## 🚀 Architektur-Entscheidungen (ADRs) + +### ADR-001: Microservices mit Domain-Driven Design + +**Status:** Akzeptiert + +**Kontext:** Skalierbare und wartbare Architektur für Pferdesport-Plattform + +**Entscheidung:** Microservices-Architektur mit DDD-Bounded-Contexts + +**Konsequenzen:** +- ✅ Unabhängige Entwicklung und Deployment +- ✅ Fachliche Kapselung durch Bounded Contexts +- ❌ Komplexität bei Service-zu-Service-Kommunikation +- ❌ Eventual Consistency zwischen Services + +### ADR-002: Event-Driven Architecture mit Kafka + +**Status:** Akzeptiert + +**Kontext:** Entkopplung und Resilienz zwischen Services + +**Entscheidung:** Kafka als zentraler Event-Broker + +**Konsequenzen:** +- ✅ Lose Kopplung zwischen Services +- ✅ Audit-Log durch Event-Store +- ❌ Komplexität bei Event-Schema-Evolution +- ❌ Eventually Consistent State + +### ADR-003: Kotlin Multiplatform für Client + +**Status:** Akzeptiert + +**Kontext:** Code-Sharing zwischen Desktop und Web + +**Entscheidung:** KMP mit Compose Multiplatform + +**Konsequenzen:** +- ✅ Geteilte Business-Logic +- ✅ Einheitliche UI-Patterns +- ❌ Plattform-spezifische Optimierungen schwieriger +- ❌ Abhängigkeit von Kotlin/JetBrains-Ökosystem + +--- + +**Navigation:** +- [Master-Guideline](../master-guideline.md) - Übergeordnete Projektrichtlinien +- [Coding-Standards](./coding-standards.md) - Code-Qualitätsstandards +- [Testing-Standards](./testing-standards.md) - Test-Qualitätssicherung +- [Documentation-Standards](./documentation-standards.md) - Dokumentationsrichtlinien diff --git a/.junie/guidelines/project-standards/coding-standards.md b/.junie/guidelines/project-standards/coding-standards.md new file mode 100644 index 00000000..36dd3075 --- /dev/null +++ b/.junie/guidelines/project-standards/coding-standards.md @@ -0,0 +1,216 @@ +# Coding Standards und Code-Qualität + +--- +guideline_type: "project-standards" +scope: "coding-standards" +audience: ["developers", "ai-assistants"] +last_updated: "2025-09-13" +dependencies: ["master-guideline.md"] +related_files: ["build.gradle.kts", "detekt.yml", "*.kt"] +ai_context: "Coding conventions, naming standards, type safety, error handling, and logging practices" +--- + +## 📋 Coding Conventions & Code-Qualität + +### Sprach- und Stilstandards + +* **Primärsprache:** Kotlin (JVM/Multiplatform) +* **Java-Kompatibilität:** Ziel ist Java 21+ +* **Code-Stil:** Offizielle Kotlin Coding Conventions, durch `Detekt` geprüft. + +> **🤖 AI-Assistant Hinweis:** +> Alle Kotlin-Code muss den offiziellen Kotlin Coding Conventions entsprechen: +> - **Detekt-Validierung:** Automatische Code-Style-Prüfung +> - **Java 21+ Kompatibilität:** Nutze moderne Java-Features wo sinnvoll +> - **Multiplatform:** Code sollte plattformübergreifend funktionieren + +### Namenskonventionen + +* **Klassen & Interfaces:** `PascalCase` (z.B. `MemberService`, `EventRepository`) +* **Funktionen & Variablen:** `camelCase` (z.B. `authenticateUser`, `memberRepository`) +* **Testmethoden:** Beschreibend mit Backticks (z.B. `` `should return Success for valid credentials` ``) +* **Konstanten:** `SCREAMING_SNAKE_CASE` (z.B. `MAX_RETRY_ATTEMPTS`) +* **Enums:** `PascalCase` für Werte (z.B. `MemberStatus.ACTIVE`) + +### Value Classes für Typsicherheit + +Primitive Typen (UUID, String, Long) für IDs oder spezifische Werte müssen in typsichere `value class`-Wrapper gekapselt werden. + +```kotlin +@JvmInline +value class MemberId(val value: UUID) { + companion object { + fun of(value: String): Result = + runCatching { UUID.fromString(value) } + .map { MemberId(it) } + .mapError { ValidationError.INVALID_UUID } + } +} +``` + +### Error-Handling & Logging + +* **`Result`-Pattern:** Für erwartbare Geschäftsfehler ist das `Result`-Pattern zu verwenden. Exceptions sind für unerwartete, technische Fehler reserviert. + +* **Fehler-Hierarchie:** Wir verwenden eine `sealed class`-Hierarchie, um Fehlerarten klar zu kategorisieren (`DomainError`, `ValidationError`, `BusinessError`, `TechnicalError`). + +* **Structured Logging:** Logs müssen strukturiert sein und eine Korrelations-ID enthalten, um Anfragen über Service-Grenzen hinweg zu verfolgen. + +```kotlin +logger.info { + "Creating member" with mapOf( + "memberId" to command.memberId.value, + "correlationId" to MDC.get("correlationId") + ) +} +``` + +## 🎯 AI-Assistenten: Coding-Standards-Schnellreferenz + +### Namenskonventionen-Übersicht + +| Element | Convention | Beispiel | +|---------|------------|----------| +| Klassen/Interfaces | PascalCase | `MemberService`, `EventRepository` | +| Funktionen/Variablen | camelCase | `authenticateUser`, `memberRepository` | +| Konstanten | SCREAMING_SNAKE_CASE | `MAX_RETRY_ATTEMPTS` | +| Test-Methoden | Backticks beschreibend | `` `should return Success for valid credentials` `` | +| Enum-Werte | PascalCase | `MemberStatus.ACTIVE` | + +### Code-Qualitäts-Checkliste + +- [ ] **Detekt-Prüfung:** Code-Stil entspricht Kotlin Conventions +- [ ] **Value Classes:** Primitive Typen sind in typsichere Wrapper gekapselt +- [ ] **Result-Pattern:** Geschäftsfehler verwenden Result statt Exceptions +- [ ] **Structured Logging:** Logs enthalten Korrelations-IDs +- [ ] **Error-Hierarchie:** Sealed Classes für Fehlerkategorisierung + +### Häufige Code-Patterns + +#### Typsichere IDs +```kotlin +@JvmInline +value class EntityId(val value: UUID) { + companion object { + fun generate(): EntityId = EntityId(UUID.randomUUID()) + fun of(value: String): Result = + runCatching { UUID.fromString(value) } + .map { EntityId(it) } + .mapError { ValidationError.INVALID_UUID } + } +} +``` + +#### Error-Handling mit Result +```kotlin +interface EntityRepository { + suspend fun findById(id: EntityId): Result + suspend fun save(entity: Entity): Result +} + +// Verwendung +when (val result = repository.findById(entityId)) { + is Result.Success -> processEntity(result.value) + is Result.Failure -> handleError(result.error) +} +``` + +#### Structured Logging +```kotlin +class EntityService { + private val logger = LoggerFactory.getLogger(EntityService::class.java) + + suspend fun processEntity(command: ProcessEntityCommand): Result { + val correlationId = MDC.get("correlationId") + + logger.info { + "Processing entity" with mapOf( + "entityId" to command.entityId.value, + "correlationId" to correlationId, + "operation" to "process" + ) + } + + return try { + // Processing logic + Result.Success(Unit) + } catch (e: Exception) { + logger.error { + "Entity processing failed" with mapOf( + "entityId" to command.entityId.value, + "correlationId" to correlationId, + "error" to e.message + ) + } + Result.Failure(ProcessingError.TECHNICAL_ERROR) + } + } +} +``` + +#### Sealed Class Hierarchie für Fehler +```kotlin +sealed interface DomainError { + val message: String + val code: String +} + +sealed interface ValidationError : DomainError { + data object INVALID_UUID : ValidationError { + override val message = "Invalid UUID format" + override val code = "VALIDATION_INVALID_UUID" + } + + data object REQUIRED_FIELD_MISSING : ValidationError { + override val message = "Required field is missing" + override val code = "VALIDATION_REQUIRED_FIELD_MISSING" + } +} + +sealed interface BusinessError : DomainError { + data object ENTITY_NOT_FOUND : BusinessError { + override val message = "Entity not found" + override val code = "BUSINESS_ENTITY_NOT_FOUND" + } +} + +sealed interface TechnicalError : DomainError { + data object DATABASE_CONNECTION_FAILED : TechnicalError { + override val message = "Database connection failed" + override val code = "TECHNICAL_DATABASE_CONNECTION_FAILED" + } +} +``` + +### Detekt-Konfiguration + +Wichtige Detekt-Regeln für das Projekt: + +```yaml +# detekt.yml +style: + MaxLineLength: + maxLineLength: 120 + FunctionNaming: + functionPattern: '^[a-z][a-zA-Z0-9]*$' + ClassNaming: + classPattern: '^[A-Z][a-zA-Z0-9]*$' + +complexity: + ComplexMethod: + threshold: 15 + LongParameterList: + functionThreshold: 6 + +potential-bugs: + UnsafeCallOnNullableType: + active: true +``` + +--- + +**Navigation:** +- [Master-Guideline](../master-guideline.md) - Übergeordnete Projektrichtlinien +- [Testing-Standards](./testing-standards.md) - Test-Qualitätsstandards +- [Documentation-Standards](./documentation-standards.md) - Dokumentationsrichtlinien +- [Architecture-Principles](./architecture-principles.md) - Architektur-Grundsätze diff --git a/.junie/guidelines/project-standards/documentation-standards.md b/.junie/guidelines/project-standards/documentation-standards.md new file mode 100644 index 00000000..4e9b5952 --- /dev/null +++ b/.junie/guidelines/project-standards/documentation-standards.md @@ -0,0 +1,326 @@ +# Documentation Standards + +--- +guideline_type: "project-standards" +scope: "documentation-standards" +audience: ["developers", "ai-assistants", "technical-writers"] +last_updated: "2025-09-13" +dependencies: ["master-guideline.md"] +related_files: ["README*.md", "docs/**", "*.md", "openapi.yaml"] +ai_context: "Documentation language standards, README structure, API documentation, and technical writing guidelines" +--- + +## 📝 Dokumentationsstandards + +### Sprache für Dokumentation + +* **README-Dateien:** Alle README-Dokumentationen im Projekt müssen in **deutscher Sprache** verfasst werden. Dies gewährleistet Konsistenz und Zugänglichkeit für das deutsche Entwicklungsteam. + +* **Code-Kommentare:** Komplexe Geschäftslogik und fachliche Zusammenhänge sollen in deutscher Sprache kommentiert werden. + +* **API-Dokumentation:** OpenAPI-Beschreibungen und -Beispiele sind bevorzugt in deutscher Sprache zu verfassen, sofern keine internationalen Anforderungen bestehen. + +> **🤖 AI-Assistant Hinweis:** +> Dokumentationssprache-Regeln: +> - **README-Dateien:** Immer Deutsch +> - **Code-Kommentare:** Deutsch für Geschäftslogik, Englisch für technische Details +> - **API-Docs:** Deutsch bevorzugt, Englisch bei internationalen APIs +> - **Technische Begriffe:** Englische Originalform wenn keine deutsche Übersetzung etabliert + +### Dokumentationsstruktur + +* README-Dateien sollen eine einheitliche Struktur befolgen: Überblick, Architektur, Entwicklung, Tests, Deployment. + +* Technische Begriffe dürfen in englischer Originalform verwendet werden, wenn keine etablierte deutsche Übersetzung existiert. + +## 🎯 AI-Assistenten: Documentation-Schnellreferenz + +### README-Template-Struktur + +```markdown +# [Projekt/Modul Name] + +## Überblick +[Kurze Beschreibung des Zwecks und der Funktionalität] + +## Architektur +[Architektonische Entscheidungen und Komponenten-Übersicht] + +## Entwicklung +[Setup-Anweisungen für lokale Entwicklung] + +### Voraussetzungen +[Erforderliche Tools und Versionen] + +### Installation +[Schritt-für-Schritt Setup-Anleitung] + +### Konfiguration +[Wichtige Konfigurationsoptionen] + +## Tests +[Test-Ausführung und Test-Strategie] + +## Deployment +[Deployment-Anweisungen für verschiedene Umgebungen] + +## API-Dokumentation +[Links zu API-Docs oder eingebettete Dokumentation] + +## Troubleshooting +[Häufige Probleme und Lösungen] +``` + +### Code-Kommentar-Standards + +#### Deutsche Geschäftslogik-Kommentare +```kotlin +/** + * Prüft, ob ein Mitglied für die Anmeldung zu einem Turnier berechtigt ist. + * + * Ein Mitglied ist berechtigt, wenn: + * - Der Mitgliedsstatus AKTIV ist + * - Die Lizenz gültig und nicht suspendiert ist + * - Keine offenen Zahlungen vorliegen + */ +fun isEligibleForTournament(member: Member, tournament: Tournament): Result { + // Mitgliedsstatus prüfen + if (member.status != MemberStatus.ACTIVE) { + return Result.Failure(ValidationError.MEMBER_NOT_ACTIVE) + } + + // Lizenzvalidierung durchführen + return validateLicense(member, tournament) +} +``` + +#### Englische technische Kommentare +```kotlin +/** + * Cache implementation using Redis with TTL support + * Performance: O(1) for get/set operations + */ +class RedisCache( + private val redisClient: RedisClient, + private val ttl: Duration = Duration.ofHours(1) +) : Cache { + + override suspend fun get(key: String): T? { + // Use Redis GET command with automatic deserialization + return redisClient.get(key)?.let { + jsonMapper.readValue(it, typeRef()) + } + } +} +``` + +### OpenAPI-Dokumentation Standards + +#### Deutsche API-Beschreibungen +```yaml +openapi: 3.0.0 +info: + title: Meldestelle API + description: REST API für die Verwaltung von Pferdesport-Meldungen + version: 1.0.0 + +paths: + /members: + post: + summary: Neues Mitglied anlegen + description: | + Erstellt ein neues Mitglied in der Datenbank. + Validiert alle Pflichtfelder und prüft auf Duplikate. + requestBody: + description: Mitgliedsdaten für die Erstellung + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateMemberRequest' + example: + name: "Max Mustermann" + email: "max.mustermann@example.com" + licenseNumber: "12345" + responses: + '201': + description: Mitglied erfolgreich erstellt + content: + application/json: + schema: + $ref: '#/components/schemas/Member' + '400': + description: Ungültige Eingabedaten + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + +components: + schemas: + Member: + type: object + description: Repräsentiert ein Mitglied im System + properties: + id: + type: string + format: uuid + description: Eindeutige Mitglieds-ID + example: "550e8400-e29b-41d4-a716-446655440000" + name: + type: string + description: Vollständiger Name des Mitglieds + example: "Max Mustermann" + email: + type: string + format: email + description: E-Mail-Adresse des Mitglieds + example: "max.mustermann@example.com" +``` + +### Dokumentations-Checkliste + +#### README-Dateien +- [ ] **Struktur:** Folgt dem Standard-Template +- [ ] **Sprache:** Auf Deutsch verfasst +- [ ] **Aktualität:** Entspricht dem aktuellen Code-Stand +- [ ] **Vollständigkeit:** Alle erforderlichen Abschnitte vorhanden +- [ ] **Beispiele:** Konkrete Code-Beispiele und Kommandos +- [ ] **Links:** Funktionierende Verweise auf verwandte Dokumentation + +#### API-Dokumentation +- [ ] **OpenAPI-Spezifikation:** Vollständig und valide +- [ ] **Deutsche Beschreibungen:** Für alle Endpunkte und Schemas +- [ ] **Beispiele:** Realistische Request/Response-Beispiele +- [ ] **Error-Handling:** Dokumentierte Fehlerfälle +- [ ] **Authentifizierung:** Sicherheitsanforderungen dokumentiert + +#### Code-Kommentare +- [ ] **Geschäftslogik:** Deutsche Kommentare für fachliche Aspekte +- [ ] **Technische Details:** Englische Kommentare für Framework-/Library-Code +- [ ] **Komplexität:** Komplexe Algorithmen sind erklärt +- [ ] **TODOs:** Mit Ticket-Referenzen versehen +- [ ] **Javadoc/KDoc:** Für öffentliche APIs vollständig + +### Dokumentations-Patterns + +#### Architektur-Diagramme +```markdown +## System-Architektur + +```mermaid +graph TB + subgraph "Client Layer" + WEB[Web App] + MOBILE[Mobile App] + end + + subgraph "API Gateway" + GW[API Gateway] + end + + subgraph "Service Layer" + MS[Member Service] + TS[Tournament Service] + NS[Notification Service] + end + + subgraph "Data Layer" + PG[(PostgreSQL)] + RD[(Redis)] + end + + WEB --> GW + MOBILE --> GW + GW --> MS + GW --> TS + GW --> NS + MS --> PG + TS --> PG + NS --> RD +``` +``` + +#### Feature-Dokumentation +```markdown +## Feature: Turnier-Anmeldung + +### Fachlicher Überblick +Die Turnier-Anmeldung ermöglicht es Mitgliedern, sich für Turniere zu registrieren. + +### User Stories +- Als Mitglied möchte ich mich für ein Turnier anmelden können +- Als Turnierleiter möchte ich Anmeldungen verwalten können + +### Technische Umsetzung + +#### API-Endpunkte +- `POST /tournaments/{id}/registrations` - Anmeldung erstellen +- `GET /tournaments/{id}/registrations` - Anmeldungen abrufen +- `DELETE /registrations/{id}` - Anmeldung stornieren + +#### Domain-Events +- `TournamentRegistrationCreated` - Bei erfolgreicher Anmeldung +- `TournamentRegistrationCancelled` - Bei Stornierung + +### Business Rules +1. Anmeldung nur für aktive Mitglieder möglich +2. Anmeldeschluss muss beachtet werden +3. Maximale Teilnehmerzahl darf nicht überschritten werden +``` + +#### Troubleshooting-Dokumentation +```markdown +## Häufige Probleme + +### Problem: Service startet nicht +**Symptome:** Container bleibt im Status "Restarting" + +**Ursachen:** +- Datenbankverbindung fehlgeschlagen +- Fehlende Environment-Variablen +- Port bereits belegt + +**Lösung:** +1. Logs prüfen: `docker-compose logs service-name` +2. Environment-Variablen validieren +3. Port-Konflikte lösen: `netstat -tulpn | grep :8080` + +### Problem: Langsame API-Antworten +**Symptome:** Response-Zeiten > 2 Sekunden + +**Debugging:** +```bash +# Database-Performance prüfen +docker-compose exec postgres psql -c "SELECT * FROM pg_stat_activity;" + +# Redis-Performance prüfen +docker-compose exec redis redis-cli info stats +``` + +**Optimierung:** +- Database-Indizes überprüfen +- Query-Performance analysieren +- Cache-Hit-Rate optimieren +``` + +### Versionierung und Updates + +#### Dokumentations-Versionierung +- README-Dateien werden mit dem Code versioniert +- API-Dokumentation folgt Semantic Versioning +- Changelog wird für breaking changes geführt + +#### Update-Prozess +1. **Code-Änderungen** → README aktualisieren +2. **API-Änderungen** → OpenAPI-Spec anpassen +3. **Architektur-Änderungen** → Diagramme überarbeiten +4. **Deployment-Änderungen** → Deployment-Docs aktualisieren + +--- + +**Navigation:** +- [Master-Guideline](../master-guideline.md) - Übergeordnete Projektrichtlinien +- [Coding-Standards](./coding-standards.md) - Code-Qualitätsstandards +- [Testing-Standards](./testing-standards.md) - Test-Qualitätssicherung +- [Architecture-Principles](./architecture-principles.md) - Architektur-Grundsätze diff --git a/.junie/guidelines/project-standards/testing-standards.md b/.junie/guidelines/project-standards/testing-standards.md new file mode 100644 index 00000000..ab8626d9 --- /dev/null +++ b/.junie/guidelines/project-standards/testing-standards.md @@ -0,0 +1,379 @@ +# Testing Standards und Qualitätssicherung + +--- +guideline_type: "project-standards" +scope: "testing-standards" +audience: ["developers", "ai-assistants"] +last_updated: "2025-09-13" +dependencies: ["master-guideline.md", "coding-standards.md"] +related_files: ["build.gradle.kts", "src/test/**", "testcontainers.properties"] +ai_context: "Testing strategies, test pyramid, tools, coverage requirements, and debugging practices" +--- + +## 🧪 Testing Standards + +Tests sind ein integraler Bestandteil jedes Features und müssen einen hohen Standard erfüllen. + +> **🤖 AI-Assistant Hinweis:** +> Testing-Prinzipien für das Meldestelle-Projekt: +> - **Test-Pyramide:** 80%+ Unit-Tests, Integrationstests für externe Systeme +> - **Testcontainers:** Goldstandard für Infrastruktur-Tests +> - **Debug-Logs:** Präfix `[DEBUG_LOG]` für Test-Ausgaben +> - **Result-Pattern:** Tests müssen auch Error-Handling validieren + +### Test-Pyramide & Werkzeuge + +#### Unit-Tests (80 %+ Abdeckung) + +Für Domänen- und Anwendungslogik (JUnit 5, MockK). + +```kotlin +class MemberServiceTest { + private val memberRepository = mockk() + private val eventPublisher = mockk() + private val memberService = MemberService(memberRepository, eventPublisher) + + @Test + fun `should return Success when member is created successfully`() { + // Given + val command = CreateMemberCommand( + memberId = MemberId.generate(), + name = "Max Mustermann", + email = "max@example.com" + ) + + every { memberRepository.save(any()) } returns Result.Success(Unit) + every { eventPublisher.publish(any()) } returns Result.Success(Unit) + + // When + val result = memberService.createMember(command) + + // Then + assertThat(result).isInstanceOf>() + verify { memberRepository.save(any()) } + verify { eventPublisher.publish(ofType()) } + } + + @Test + fun `should return Failure when repository save fails`() { + // Given + val command = CreateMemberCommand( + memberId = MemberId.generate(), + name = "Max Mustermann", + email = "max@example.com" + ) + + every { memberRepository.save(any()) } returns Result.Failure(RepositoryError.DATABASE_ERROR) + + // When + val result = memberService.createMember(command) + + // Then + assertThat(result).isInstanceOf>() + verify { memberRepository.save(any()) } + verify(exactly = 0) { eventPublisher.publish(any()) } + } +} +``` + +#### Integrationstests + +Decken alle Repository-Implementierungen und externen Integrationen ab. + +```kotlin +@Testcontainers +class MemberRepositoryIntegrationTest { + + @Container + private val postgresContainer = PostgreSQLContainer("postgres:16-alpine") + .withDatabaseName("testdb") + .withUsername("test") + .withPassword("test") + + private lateinit var memberRepository: MemberRepository + + @BeforeEach + fun setup() { + val dataSource = HikariDataSource().apply { + jdbcUrl = postgresContainer.jdbcUrl + username = postgresContainer.username + password = postgresContainer.password + } + + // Run migrations + Flyway.configure() + .dataSource(dataSource) + .locations("db/migration") + .load() + .migrate() + + memberRepository = PostgresMemberRepository(dataSource) + } + + @Test + fun `should save and retrieve member successfully`() { + // Given + val member = Member( + id = MemberId.generate(), + name = "Integration Test Member", + email = "integration@test.com" + ) + + // When + val saveResult = runBlocking { memberRepository.save(member) } + val findResult = runBlocking { memberRepository.findById(member.id) } + + // Then + assertThat(saveResult).isInstanceOf>() + assertThat(findResult).isInstanceOf>() + + val retrievedMember = (findResult as Result.Success).value + assertThat(retrievedMember?.id).isEqualTo(member.id) + assertThat(retrievedMember?.name).isEqualTo(member.name) + assertThat(retrievedMember?.email).isEqualTo(member.email) + } +} +``` + +#### Testcontainers als Goldstandard + +Jede Interaktion mit externer Infrastruktur (DB, Cache, Broker) **muss** mit **Testcontainers** getestet werden. + +```kotlin +@Testcontainers +class EventStoreIntegrationTest { + + companion object { + @Container + @JvmStatic + private val redisContainer = GenericContainer("redis:7-alpine") + .withExposedPorts(6379) + + @Container + @JvmStatic + private val kafkaContainer = KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.4.0")) + } + + @Test + fun `should store and retrieve events from Redis`() { + println("[DEBUG_LOG] Testing Redis event storage") + + // Given + val eventStore = RedisEventStore( + redisHost = redisContainer.host, + redisPort = redisContainer.getMappedPort(6379) + ) + + val event = MemberCreatedEvent( + memberId = MemberId.generate(), + name = "Test Member", + timestamp = Instant.now() + ) + + // When + val storeResult = runBlocking { eventStore.store(event) } + val retrieveResult = runBlocking { eventStore.getEvents(event.memberId) } + + // Then + assertThat(storeResult).isInstanceOf>() + assertThat(retrieveResult).isInstanceOf>>() + + val events = (retrieveResult as Result.Success).value + assertThat(events).hasSize(1) + assertThat(events.first()).isInstanceOf() + + println("[DEBUG_LOG] Successfully stored and retrieved ${events.size} events") + } +} +``` + +### Debugging in Tests + +Debug-Ausgaben im Test-Code müssen mit `[DEBUG_LOG]` beginnen, um sie leicht identifizieren und filtern zu können. + +```kotlin +@Test +fun `should handle complex business scenario`() { + println("[DEBUG_LOG] Starting complex business scenario test") + + // Test implementation + + println("[DEBUG_LOG] Member created with ID: ${member.id}") + println("[DEBUG_LOG] Published ${events.size} domain events") + println("[DEBUG_LOG] Test completed successfully") +} +``` + +## 🎯 AI-Assistenten: Testing-Schnellreferenz + +### Test-Kategorien und Werkzeuge + +| Test-Typ | Coverage-Ziel | Werkzeuge | Verwendung | +|----------|---------------|-----------|------------| +| Unit-Tests | 80%+ | JUnit 5, MockK, AssertJ | Domänen- & Anwendungslogik | +| Integrationstests | Alle Repositories | Testcontainers, JUnit 5 | Externe Integrationen | +| End-to-End Tests | Kritische User-Journeys | Testcontainers, REST Assured | Vollständige Workflows | + +### Testcontainer-Konfiguration + +#### PostgreSQL +```kotlin +@Container +private val postgresContainer = PostgreSQLContainer("postgres:16-alpine") + .withDatabaseName("testdb") + .withUsername("test") + .withPassword("test") + .withInitScript("test-data.sql") +``` + +#### Redis +```kotlin +@Container +private val redisContainer = GenericContainer("redis:7-alpine") + .withExposedPorts(6379) + .withCommand("redis-server", "--appendonly", "yes") +``` + +#### Kafka +```kotlin +@Container +private val kafkaContainer = KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.4.0")) + .withEnv("KAFKA_AUTO_CREATE_TOPICS_ENABLE", "true") +``` + +#### Keycloak +```kotlin +@Container +private val keycloakContainer = KeycloakContainer("quay.io/keycloak/keycloak:26.0.7") + .withRealmImportFile("test-realm.json") + .withAdminUsername("admin") + .withAdminPassword("admin") +``` + +### Test-Patterns für Result-Handling + +```kotlin +// Success-Case testen +@Test +fun `should return Success when operation succeeds`() { + // Given + every { dependency.operation() } returns Result.Success(expectedValue) + + // When + val result = serviceUnderTest.performOperation() + + // Then + assertThat(result).isInstanceOf>() + assertThat((result as Result.Success).value).isEqualTo(expectedValue) +} + +// Failure-Case testen +@Test +fun `should return Failure when dependency fails`() { + // Given + every { dependency.operation() } returns Result.Failure(ExpectedError.SOME_ERROR) + + // When + val result = serviceUnderTest.performOperation() + + // Then + assertThat(result).isInstanceOf>() + assertThat((result as Result.Failure).error).isEqualTo(ExpectedError.SOME_ERROR) +} +``` + +### Mock-Setup für Services + +```kotlin +class ServiceTest { + private val repository = mockk() + private val eventPublisher = mockk() + private val externalService = mockk() + + private val serviceUnderTest = Service(repository, eventPublisher, externalService) + + @BeforeEach + fun setup() { + clearAllMocks() + + // Default mocks + every { eventPublisher.publish(any()) } returns Result.Success(Unit) + } + + @AfterEach + fun cleanup() { + confirmVerified(repository, eventPublisher, externalService) + } +} +``` + +### Testdaten-Builder + +```kotlin +class MemberTestDataBuilder { + private var id: MemberId = MemberId.generate() + private var name: String = "Test Member" + private var email: String = "test@example.com" + private var status: MemberStatus = MemberStatus.ACTIVE + + fun withId(id: MemberId) = apply { this.id = id } + fun withName(name: String) = apply { this.name = name } + fun withEmail(email: String) = apply { this.email = email } + fun withStatus(status: MemberStatus) = apply { this.status = status } + + fun build() = Member( + id = id, + name = name, + email = email, + status = status + ) +} + +// Verwendung in Tests +@Test +fun `should validate member data`() { + val member = MemberTestDataBuilder() + .withName("Max Mustermann") + .withEmail("max@meldestelle.at") + .withStatus(MemberStatus.PENDING) + .build() + + // Test implementation +} +``` + +### Performance-Tests + +```kotlin +@Test +fun `should handle high load efficiently`() { + println("[DEBUG_LOG] Starting performance test with 1000 concurrent operations") + + val operations = (1..1000).map { + async { + serviceUnderTest.performOperation( + TestCommand(id = MemberId.generate()) + ) + } + } + + val results = runBlocking { + operations.awaitAll() + } + + val successCount = results.count { it is Result.Success } + val failureCount = results.count { it is Result.Failure } + + println("[DEBUG_LOG] Performance test completed: $successCount successes, $failureCount failures") + + assertThat(successCount).isGreaterThan(950) // 95% success rate minimum +} +``` + +--- + +**Navigation:** +- [Master-Guideline](../master-guideline.md) - Übergeordnete Projektrichtlinien +- [Coding-Standards](./coding-standards.md) - Code-Qualitätsstandards +- [Documentation-Standards](./documentation-standards.md) - Dokumentationsrichtlinien +- [Architecture-Principles](./architecture-principles.md) - Architektur-Grundsätze diff --git a/.junie/guidelines/technology-guides/docker/docker-architecture.md b/.junie/guidelines/technology-guides/docker/docker-architecture.md new file mode 100644 index 00000000..94306c6c --- /dev/null +++ b/.junie/guidelines/technology-guides/docker/docker-architecture.md @@ -0,0 +1,247 @@ +# Docker-Architektur und Services + +--- +guideline_type: "technology" +scope: "docker-architecture" +audience: ["developers", "ai-assistants", "devops"] +last_updated: "2025-09-13" +dependencies: ["docker-overview.md", "master-guideline.md"] +related_files: ["docker-compose.yml", "docker/versions.toml", "scripts/docker-versions-update.sh"] +ai_context: "Docker container architecture, service definitions, and centralized version management" +--- + +## 🏗️ Architektur-Überblick + +### Container-Kategorien + +```mermaid +graph TB + subgraph "Infrastructure Services" + PG[PostgreSQL] + RD[Redis] + KC[Keycloak] + KF[Kafka+Zookeeper] + CS[Consul] + end + + subgraph "Application Services" + GW[API Gateway] + AS[Auth Server] + MS[Monitoring Server] + PS[Ping Service] + end + + subgraph "Client Applications" + WA[Web App] + DA[Desktop App - Native] + end + + subgraph "Monitoring Stack" + PR[Prometheus] + GR[Grafana] + ZK[Zipkin] + NX[Nginx - Prod] + end + + Infrastructure --> Application + Application --> Client + Monitoring --> Infrastructure + Monitoring --> Application +``` + +### Service-Ports Matrix + +| Service | Development | Production | Health Check | Debug Port | Version | +|---------|------------|------------|--------------|------------|---------| +| PostgreSQL | 5432 | Internal | pg_isready -U meldestelle -d meldestelle | - | 16-alpine | +| Redis | 6379 | Internal | redis-cli ping | - | 7-alpine | +| Keycloak | 8180 | 8443 (HTTPS) | /health/ready | - | 26.0.7 | +| Kafka | 9092 | Internal | kafka-topics --bootstrap-server localhost:9092 --list | - | 7.4.0 | +| Zookeeper | 2181 | Internal | nc -z localhost 2181 | - | 7.4.0 | +| Consul | 8500 | Internal | /v1/status/leader | - | 1.15 | +| Auth Server | 8081 | Internal | /actuator/health/readiness | 5005 | 1.0.0 | +| Ping Service | 8082 | Internal | /actuator/health/readiness | 5005 | 1.0.0 | +| Monitoring Server | 8083 | Internal | /actuator/health/readiness | 5005 | 1.0.0 | +| Prometheus | 9090 | Internal | /-/healthy | - | v2.54.1 | +| Grafana | 3000 | 3443 (HTTPS) | /api/health | - | 11.3.0 | +| Nginx | - | 80/443 | /health | - | 1.25-alpine | + +## 🎯 Zentrale Docker-Versionsverwaltung + +> **🤖 AI-Assistant Hinweis:** +> Das Versionssystem folgt dem Single Source of Truth Prinzip: +> - **Zentrale Datei:** `docker/versions.toml` definiert alle Versionen +> - **Build-Args:** Automatisch generierte `.env`-Dateien in `docker/build-args/` +> - **Updates:** Via `./scripts/docker-versions-update.sh` + +### Überblick und Motivation + +**Version 3.0.0** führt eine revolutionäre Änderung in der Docker-Versionsverwaltung ein: die **zentrale Verwaltung aller Build-Argumente** analog zum bewährten `gradle/libs.versions.toml` System. + +#### Das Problem vor Version 3.0.0 + +```dockerfile +# BEFORE: Redundante Hardcodierung in 12+ Dockerfiles +ARG GRADLE_VERSION=9.0.0 +ARG GRADLE_VERSION=9.0.0 +ARG GRADLE_VERSION=9.0.0 +# ... 9 weitere Male identisch wiederholt! +``` + +#### Die Lösung: Single Source of Truth + +```toml +# docker/versions.toml - SINGLE SOURCE OF TRUTH +[versions] +gradle = "9.0.0" +java = "21" +node = "20.12.0" +nginx = "1.25-alpine" +prometheus = "v2.54.1" +grafana = "11.3.0" +keycloak = "26.0.7" +``` + +### 🏗️ Architektur der zentralen Versionsverwaltung + +``` +docker/ +├── versions.toml # 🎯 Single Source of Truth +├── build-args/ # Auto-generierte Environment Files +│ ├── global.env # Globale Build-Argumente +│ ├── services.env # dockerfiles/services/* +│ ├── clients.env # dockerfiles/clients/* +│ └── infrastructure.env # dockerfiles/infrastructure/* +└── README.md # Dokumentation +``` + +### 📊 Hierarchische Versionsverwaltung + +#### 1. **Globale Versionen** (`docker/build-args/global.env`) +Verwendet von **allen** Dockerfiles: +```bash +# --- Build Tools --- +GRADLE_VERSION=9.0.0 +JAVA_VERSION=21 + +# --- Build Metadata --- +BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') +VERSION=1.0.0 + +# --- Common Base Images --- +ALPINE_VERSION=3.19 +ECLIPSE_TEMURIN_JDK_VERSION=21-jdk-alpine +ECLIPSE_TEMURIN_JRE_VERSION=21-jre-alpine + +# --- Monitoring & Infrastructure Services --- +DOCKER_PROMETHEUS_VERSION=v2.54.1 +DOCKER_GRAFANA_VERSION=11.3.0 +DOCKER_KEYCLOAK_VERSION=26.0.7 +``` + +#### 2. **Kategorie-spezifische Versionen** + +**Services** (`docker/build-args/services.env`): +```bash +SPRING_PROFILES_ACTIVE=docker +SERVICE_PORT=8080 +PING_SERVICE_PORT=8082 +MEMBERS_SERVICE_PORT=8083 +``` + +**Clients** (`docker/build-args/clients.env`): +```bash +NODE_VERSION=20.11.0 +NGINX_VERSION=1.25-alpine +WEB_APP_PORT=4000 +DESKTOP_APP_VNC_PORT=5901 +``` + +**Infrastructure** (`docker/build-args/infrastructure.env`): +```bash +SPRING_PROFILES_ACTIVE=default +GATEWAY_PORT=8081 +AUTH_SERVER_PORT=8087 +``` + +### 🛠️ Verwendung der zentralen Versionsverwaltung + +#### Automatisierte Builds mit `scripts/docker-build.sh` + +```bash +# Alle Services mit zentralen Versionen bauen +./scripts/docker-build.sh services + +# Client-Anwendungen bauen +./scripts/docker-build.sh clients + +# Komplettes System bauen +./scripts/docker-build.sh all + +# Aktuelle Versionen anzeigen +./scripts/docker-build.sh --versions +``` + +#### Versionen aktualisieren mit `scripts/docker-versions-update.sh` + +```bash +# Aktuelle Versionen anzeigen +./scripts/docker-versions-update.sh show + +# Java auf Version 22 upgraden +./scripts/docker-versions-update.sh update java 22 + +# Gradle auf 9.1.0 upgraden +./scripts/docker-versions-update.sh update gradle 9.1.0 + +# Prometheus auf neueste Version upgraden +./scripts/docker-versions-update.sh update prometheus v2.54.1 + +# Grafana auf neueste Version upgraden +./scripts/docker-versions-update.sh update grafana 11.3.0 + +# Keycloak auf neueste Version upgraden +./scripts/docker-versions-update.sh update keycloak 26.0.7 + +# Alle Environment-Dateien synchronisieren +./scripts/docker-versions-update.sh sync +``` + +## 🎯 Für AI-Assistenten: Architektur-Schnellreferenz + +### Service-Kategorien +- **Infrastructure:** PostgreSQL, Redis, Keycloak, Kafka, Zookeeper, Consul +- **Application:** API Gateway, Auth Server, Monitoring Server, Ping Service +- **Clients:** Web App (Port 3000), Desktop App +- **Monitoring:** Prometheus (9090), Grafana (3000), Zipkin, Nginx + +### Wichtige Befehle +```bash +# Service-Status prüfen +docker-compose ps + +# Logs eines Services anzeigen +docker-compose logs + +# Versionen aktualisieren +./scripts/docker-versions-update.sh show +./scripts/docker-versions-update.sh update + +# Services neu starten +docker-compose restart +``` + +### Zentrale Konfigurationsdateien +- `docker/versions.toml` - Alle Versionen +- `docker-compose.yml` - Haupt-Services +- `docker-compose.clients.yml` - Client-Anwendungen +- `docker/build-args/*.env` - Generierte Build-Argumente + +--- + +**Navigation:** +- [Docker-Overview](./docker-overview.md) - Grundlagen und Philosophie +- [Docker-Development](./docker-development.md) - Entwicklungsworkflow +- [Docker-Production](./docker-production.md) - Production-Deployment +- [Docker-Monitoring](./docker-monitoring.md) - Observability +- [Docker-Troubleshooting](./docker-troubleshooting.md) - Problemlösung diff --git a/.junie/guidelines/technology-guides/docker/docker-development.md b/.junie/guidelines/technology-guides/docker/docker-development.md new file mode 100644 index 00000000..775f1107 --- /dev/null +++ b/.junie/guidelines/technology-guides/docker/docker-development.md @@ -0,0 +1,181 @@ +# Docker-Development Workflow + +--- +guideline_type: "technology" +scope: "docker-development" +audience: ["developers", "ai-assistants"] +last_updated: "2025-09-13" +dependencies: ["docker-overview.md", "docker-architecture.md"] +related_files: ["docker-compose.yml", "docker-compose.override.yml", "Makefile"] +ai_context: "Development workflow, debugging, and local development setup with Docker" +--- + +## 🛠️ Development-Workflow + +### Schnellstart-Befehle + +```bash +# 🚀 Komplettes Development-Setup +make dev-up # Startet alle Development-Services +make dev-down # Stoppt alle Services +make dev-logs # Zeigt Logs aller Services +make dev-restart # Neustart aller Services + +# 🔧 Service-spezifische Befehle +make service-build SERVICE=ping-service # Service neu bauen +make service-logs SERVICE=ping-service # Service-Logs anzeigen +make service-restart SERVICE=ping-service # Service neustarten +``` + +> **🤖 AI-Assistant Hinweis:** +> Für Development verwende die Makefile-Befehle oder direkt docker-compose: +> - **Alles starten:** `make dev-up` oder `docker-compose up -d` +> - **Logs ansehen:** `make dev-logs` oder `docker-compose logs -f` +> - **Service debuggen:** `docker-compose exec sh` + +**Makefile-Beispiel:** + +```makefile +# Development commands +.PHONY: dev-up dev-down dev-logs dev-restart + +dev-up: + docker-compose -f docker-compose.yml -f docker-compose.services.yml up -d + @echo "🚀 Development environment started" + @echo "📊 Grafana: http://localhost:3000 (admin/admin)" + @echo "🔍 Prometheus: http://localhost:9090" + @echo "🚪 API Gateway: http://localhost:8080" + +dev-down: + docker-compose -f docker-compose.yml -f docker-compose.services.yml down + +dev-logs: + docker-compose -f docker-compose.yml -f docker-compose.services.yml logs -f + +dev-restart: + $(MAKE) dev-down + $(MAKE) dev-up + +# Service-specific commands +service-build: + @test -n "$(SERVICE)" || (echo "❌ SERVICE parameter required"; exit 1) + docker-compose -f docker-compose.yml -f docker-compose.services.yml build $(SERVICE) + +service-logs: + @test -n "$(SERVICE)" || (echo "❌ SERVICE parameter required"; exit 1) + docker-compose logs -f $(SERVICE) + +service-restart: + @test -n "$(SERVICE)" || (echo "❌ SERVICE parameter required"; exit 1) + docker-compose -f docker-compose.yml -f docker-compose.services.yml restart $(SERVICE) +``` + +### Hot-Reload Development + +**docker-compose.override.yml** für optimierte Entwicklung: + +```yaml +# Development overrides für Hot-Reload +version: '3.8' + +services: + web-client: + volumes: + - ./client/web-app/src:/app/src:ro + - ./client/common-ui/src:/app/common-ui/src:ro + environment: + - NODE_ENV=development + command: npm run dev + + ping-service: + environment: + - DEBUG=true + - SPRING_DEVTOOLS_RESTART_ENABLED=true + ports: + - "5005:5005" # Debug-Port + volumes: + - ./temp/ping-service/src:/workspace/src:ro +``` + +### Debugging von Services + +```bash +# Service im Debug-Modus starten +docker-compose -f docker-compose.yml up -d ping-service +docker-compose exec ping-service sh + +# Logs in Echtzeit verfolgen +docker-compose logs -f ping-service api-gateway + +# Health-Check Status prüfen +curl -s http://localhost:8082/actuator/health | jq +curl -s http://localhost:8080/actuator/health | jq +``` + +## 🎯 AI-Assistenten: Development-Schnellreferenz + +### Häufige Entwicklungsaufgaben + +| Aufgabe | Befehl | Beschreibung | +|---------|---------|--------------| +| Umgebung starten | `make dev-up` | Alle Services für Development | +| Service debuggen | `docker-compose exec sh` | Shell im Container | +| Logs verfolgen | `docker-compose logs -f ` | Live-Logs anzeigen | +| Service neu bauen | `make service-build SERVICE=` | Einzelnen Service rebuilden | +| Health-Check | `curl localhost:/actuator/health` | Service-Status prüfen | + +### Development-URLs +- **Grafana:** http://localhost:3000 (admin/admin) +- **Prometheus:** http://localhost:9090 +- **API Gateway:** http://localhost:8080 +- **Consul:** http://localhost:8500 +- **Keycloak:** http://localhost:8180 + +### Debug-Ports +- **Spring-Services:** 5005 (Standard Java Debug) +- **Web-App:** Hot-Reload über Volume-Mapping +- **Client-Apps:** Port 4000 (Web), 5901 (Desktop VNC) + +### Troubleshooting Development + +#### Container startet nicht +```bash +# Container-Status prüfen +docker-compose ps + +# Container-Logs anzeigen +docker-compose logs + +# Container neu starten +docker-compose restart + +# Image neu bauen +docker-compose build --no-cache +``` + +#### Port-Konflikte +```bash +# Ports prüfen +netstat -tulpn | grep : + +# Service mit anderem Port starten +docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d +``` + +#### Volume-Probleme +```bash +# Volumes prüfen +docker volume ls + +# Volume-Inhalt anzeigen +docker-compose exec ls -la /path/to/volume +``` + +--- + +**Navigation:** +- [Docker-Overview](./docker-overview.md) - Grundlagen und Philosophie +- [Docker-Architecture](./docker-architecture.md) - Container-Services und Struktur +- [Docker-Production](./docker-production.md) - Production-Deployment +- [Docker-Monitoring](./docker-monitoring.md) - Observability +- [Docker-Troubleshooting](./docker-troubleshooting.md) - Problemlösung diff --git a/.junie/guidelines/technology-guides/docker/docker-monitoring.md b/.junie/guidelines/technology-guides/docker/docker-monitoring.md new file mode 100644 index 00000000..3eee263e --- /dev/null +++ b/.junie/guidelines/technology-guides/docker/docker-monitoring.md @@ -0,0 +1,252 @@ +# Docker-Monitoring und Observability + +--- +guideline_type: "technology" +scope: "docker-monitoring" +audience: ["developers", "devops", "ai-assistants"] +last_updated: "2025-09-13" +dependencies: ["docker-overview.md", "docker-architecture.md"] +related_files: ["docker-compose.yml", "config/monitoring/*", "config/grafana/*", "config/prometheus/*"] +ai_context: "Monitoring setup, Prometheus metrics, Grafana dashboards, health checks, and log aggregation" +--- + +## 📊 Monitoring und Observability + +### Prometheus Metrics + +Alle Services exposieren standardisierte Metrics: + +```yaml +# Service-Labels für Prometheus Autodiscovery +labels: + - "prometheus.scrape=true" + - "prometheus.port=8080" + - "prometheus.path=/actuator/prometheus" + - "prometheus.service=${SERVICE_NAME}" +``` + +> **🤖 AI-Assistant Hinweis:** +> Monitoring-Stack Zugriff: +> - **Grafana:** http://localhost:3000 (admin/admin) +> - **Prometheus:** http://localhost:9090 +> - **Metrics-Endpoints:** `/actuator/prometheus` für Spring-Services +> - **Health-Checks:** `/actuator/health` für Readiness-Probes + +### Grafana Dashboards + +**Vorgefertigte Dashboards:** + +- **Infrastructure Overview**: CPU, Memory, Disk, Network +- **Spring Boot Services**: JVM Metrics, HTTP Requests, Circuit Breaker +- **Database Performance**: PostgreSQL Connections, Query Performance +- **Message Queue**: Kafka Consumer Lag, Throughput +- **Business Metrics**: Application-spezifische KPIs + +### Health Check Matrix + +| Service | Endpoint | Erwartung | Timeout | +|---------|----------|-----------|---------| +| API Gateway | `/actuator/health` | `{"status":"UP"}` | 15s | +| Ping Service | `/actuator/health/readiness` | HTTP 200 | 3s | +| PostgreSQL | `pg_isready` | Connection OK | 5s | +| Redis | `redis-cli ping` | PONG | 5s | +| Keycloak | `/health/ready` | HTTP 200 | 5s | + +### Log Aggregation + +```bash +# Centralized logging mit ELK Stack (optional) +docker-compose -f docker-compose.yml -f docker-compose.logging.yml up -d + +# Log-Parsing für strukturierte Logs +docker-compose logs --follow --tail=100 api-gateway | jq -r '.message' +``` + +## 🎯 AI-Assistenten: Monitoring-Schnellreferenz + +### Monitoring-URLs +- **Grafana Dashboard:** http://localhost:3000 (admin/admin) +- **Prometheus Targets:** http://localhost:9090/targets +- **Prometheus Metrics:** http://localhost:9090/metrics +- **Service Health:** http://localhost:/actuator/health + +### Wichtige Metrics + +| Metric-Typ | Beispiel | Beschreibung | +|------------|----------|--------------| +| JVM Memory | `jvm_memory_used_bytes` | Speicherverbrauch Java-Services | +| HTTP Requests | `http_requests_total` | API-Request-Zähler | +| Database Connections | `hikaricp_connections` | Pool-Verbindungen | +| Kafka Lag | `kafka_consumer_lag` | Consumer-Verzögerung | +| Custom Business | `meldestelle_registrations_total` | Fachliche KPIs | + +### Health-Check Befehle + +```bash +# Alle Services prüfen +docker-compose ps + +# Service-spezifische Health-Checks +curl -s http://localhost:8082/actuator/health | jq '.status' +curl -s http://localhost:8081/actuator/health | jq '.status' + +# Infrastructure Health-Checks +docker-compose exec postgres pg_isready -U meldestelle -d meldestelle +docker-compose exec redis redis-cli ping +curl -s http://localhost:8180/health/ready +``` + +### Log-Analyse + +```bash +# Service-Logs in Echtzeit +docker-compose logs -f + +# Error-Logs filtern +docker-compose logs | grep ERROR + +# JSON-Logs strukturiert anzeigen +docker-compose logs api-gateway | jq -r '. | select(.level=="ERROR") | .message' + +# Performance-Logs analysieren +docker-compose logs api-gateway | grep -i "took\|duration\|time" +``` + +### Dashboard-Setup + +#### Infrastructure-Dashboard +```json +{ + "dashboard": { + "title": "Meldestelle Infrastructure", + "panels": [ + { + "title": "CPU Usage", + "targets": [ + { + "expr": "rate(container_cpu_usage_seconds_total[5m]) * 100" + } + ] + }, + { + "title": "Memory Usage", + "targets": [ + { + "expr": "container_memory_usage_bytes / container_spec_memory_limit_bytes * 100" + } + ] + } + ] + } +} +``` + +#### Application-Dashboard +```json +{ + "dashboard": { + "title": "Meldestelle Services", + "panels": [ + { + "title": "HTTP Requests/sec", + "targets": [ + { + "expr": "rate(http_requests_total[1m])" + } + ] + }, + { + "title": "Response Time", + "targets": [ + { + "expr": "histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))" + } + ] + } + ] + } +} +``` + +### Alerting-Regeln + +```yaml +# prometheus/alerts.yml +groups: + - name: meldestelle.rules + rules: + - alert: ServiceDown + expr: up == 0 + for: 1m + labels: + severity: critical + annotations: + summary: "Service {{ $labels.instance }} is down" + + - alert: HighMemoryUsage + expr: (container_memory_usage_bytes / container_spec_memory_limit_bytes) > 0.8 + for: 5m + labels: + severity: warning + annotations: + summary: "High memory usage on {{ $labels.instance }}" + + - alert: DatabaseConnectionsFull + expr: hikaricp_connections_active >= hikaricp_connections_max * 0.8 + for: 2m + labels: + severity: warning + annotations: + summary: "Database connection pool nearly exhausted" +``` + +### Monitoring-Wartung + +```bash +# Prometheus-Konfiguration neu laden +curl -X POST http://localhost:9090/-/reload + +# Grafana-Dashboards exportieren +curl -s -H "Authorization: Bearer " \ + http://localhost:3000/api/dashboards/uid/ > dashboard_backup.json + +# Monitoring-Data bereinigen +docker-compose exec prometheus rm -rf /prometheus/data +docker-compose restart prometheus + +# Log-Rotation für Monitoring-Services +docker-compose exec grafana find /var/log -name "*.log" -exec truncate -s 0 {} \; +``` + +### Performance-Tuning + +```yaml +# prometheus.yml - Optimierte Konfiguration +global: + scrape_interval: 15s + evaluation_interval: 15s + +rule_files: + - "/etc/prometheus/alerts.yml" + +scrape_configs: + - job_name: 'spring-boot' + metrics_path: '/actuator/prometheus' + static_configs: + - targets: ['api-gateway:8080', 'ping-service:8082'] + scrape_interval: 10s + + - job_name: 'infrastructure' + static_configs: + - targets: ['postgres:5432', 'redis:6379'] + scrape_interval: 30s +``` + +--- + +**Navigation:** +- [Docker-Overview](./docker-overview.md) - Grundlagen und Philosophie +- [Docker-Architecture](./docker-architecture.md) - Container-Services und Struktur +- [Docker-Development](./docker-development.md) - Entwicklungsworkflow +- [Docker-Production](./docker-production.md) - Production-Deployment +- [Docker-Troubleshooting](./docker-troubleshooting.md) - Problemlösung diff --git a/.junie/guidelines/technology-guides/docker/docker-overview.md b/.junie/guidelines/technology-guides/docker/docker-overview.md new file mode 100644 index 00000000..37678e38 --- /dev/null +++ b/.junie/guidelines/technology-guides/docker/docker-overview.md @@ -0,0 +1,68 @@ +# Docker-Overview und Philosophie + +--- +guideline_type: "technology" +scope: "docker-overview" +audience: ["developers", "ai-assistants"] +last_updated: "2025-09-13" +dependencies: ["master-guideline.md"] +related_files: ["docker-compose.yml", "docker/versions.toml"] +ai_context: "Docker philosophy and general principles for Meldestelle project" +--- + +## 🚀 Überblick und Philosophie + +Das Meldestelle-Projekt implementiert eine **moderne, sicherheitsorientierte Containerisierungsstrategie** basierend auf bewährten DevOps-Praktiken und Production-Ready-Standards. Unsere Docker-Architektur ist darauf ausgelegt: + +- **Sicherheit first**: Alle Container laufen als Non-Root-User +- **Optimale Performance**: Multi-stage Builds mit Layer-Caching +- **Observability**: Umfassendes Monitoring und Health-Checks +- **Skalierbarkeit**: Microservices-ready mit Service Discovery +- **Wartbarkeit**: Standardisierte Templates und klare Konventionen + +## 🎯 Für AI-Assistenten: Wichtige Konzepte + +> **🤖 AI-Assistant Hinweis:** +> Diese Sektion enthält die Grundphilosophie des Docker-Setups. +> - Alle Versionsinformationen sind in `docker/versions.toml` zentralisiert +> - Services sind in `docker-compose.yml` definiert +> - Monitoring läuft unter `http://localhost:3001` (Grafana) + +### Zentrale Dateien für AI-Referenz +- `docker/versions.toml` - Single Source of Truth für alle Versionen +- `docker-compose.yml` - Haupt-Service-Orchestrierung +- `scripts/docker-versions-update.sh` - Automatische Version-Updates +- `scripts/validate-docker-consistency.sh` - Konsistenz-Validierung + +## 📋 Docker-Guidelines Navigation + +Für spezifische Docker-Themen siehe: +- [Docker-Architektur](./docker-architecture.md) - Container-Services und Struktur +- [Docker-Development](./docker-development.md) - Entwicklungsworkflow +- [Docker-Production](./docker-production.md) - Production-Deployment +- [Docker-Monitoring](./docker-monitoring.md) - Observability und Überwachung +- [Docker-Troubleshooting](./docker-troubleshooting.md) - Problemlösung + +## Grundprinzipien + +### Sicherheitsaspekte +- **Non-Root-Container**: Alle Container laufen mit dediziertem User +- **Minimale Base-Images**: Verwendung schlanker Images (Alpine, Distroless) +- **Security-Scans**: Regelmäßige Vulnerability-Checks +- **Network-Segmentierung**: Isolierte Docker-Networks + +### Performance-Optimierung +- **Multi-Stage-Builds**: Schlanke Production-Images +- **Layer-Caching**: Optimale Build-Performance +- **Resource-Limits**: Definierte CPU/Memory-Constraints +- **Health-Checks**: Proaktive Service-Überwachung + +### Wartbarkeit +- **Standardisierte Templates**: Konsistente Dockerfile-Struktur +- **Zentrale Konfiguration**: Environment-basierte Konfiguration +- **Dokumentation**: Umfassende README-Dateien pro Service +- **Versionierung**: Semantische Versionierung aller Images + +--- + +> **Basis-Prinzipien:** Diese Guidelines erweitern die [Master-Guideline](../../master-guideline.md) um Docker-spezifische Aspekte und folgen den allgemeinen Projektstandards. diff --git a/.junie/guidelines/technology-guides/docker/docker-production.md b/.junie/guidelines/technology-guides/docker/docker-production.md new file mode 100644 index 00000000..f098a455 --- /dev/null +++ b/.junie/guidelines/technology-guides/docker/docker-production.md @@ -0,0 +1,226 @@ +# Docker-Production Deployment + +--- +guideline_type: "technology" +scope: "docker-production" +audience: ["developers", "devops", "ai-assistants"] +last_updated: "2025-09-13" +dependencies: ["docker-overview.md", "docker-architecture.md"] +related_files: ["docker-compose.yml", "config/nginx/nginx.prod.conf", "config/ssl/*"] +ai_context: "Production deployment, security hardening, SSL/TLS configuration, and resource management" +--- + +## 🚀 Production-Deployment + +### Security Hardening + +Unsere Production-Konfiguration implementiert umfassende Sicherheitsmaßnahmen: + +#### 🔒 SSL/TLS Everywhere + +```bash +# TLS-Zertifikate vorbereiten +mkdir -p config/ssl/{postgres,redis,keycloak,grafana,prometheus,nginx} + +# Let's Encrypt Zertifikate generieren +certbot certonly --dns-route53 -d api.meldestelle.at +certbot certonly --dns-route53 -d auth.meldestelle.at +certbot certonly --dns-route53 -d monitor.meldestelle.at +``` + +#### 🛡️ Environment Variables + +> **🤖 AI-Assistant Hinweis:** +> Alle Passwörter werden in der Produktion mit starker Verschlüsselung generiert: +> - **PostgreSQL/Redis:** `openssl rand -base64 32` +> - **Keycloak:** Separate Admin-Credentials +> - **Monitoring:** Grafana/Prometheus Admin-Access + +**Erforderliche Production-Variablen:** + +```bash +# Datenschutz und Sicherheit +export POSTGRES_USER=meldestelle_prod +export POSTGRES_PASSWORD=$(openssl rand -base64 32) +export POSTGRES_DB=meldestelle_prod +export REDIS_PASSWORD=$(openssl rand -base64 32) + +# Keycloak Admin +export KEYCLOAK_ADMIN=admin +export KEYCLOAK_ADMIN_PASSWORD=$(openssl rand -base64 32) +export KC_DB_PASSWORD=${POSTGRES_PASSWORD} +export KC_HOSTNAME=auth.meldestelle.at + +# Monitoring +export GF_SECURITY_ADMIN_USER=admin +export GF_SECURITY_ADMIN_PASSWORD=$(openssl rand -base64 32) +export GRAFANA_HOSTNAME=monitor.meldestelle.at +export PROMETHEUS_HOSTNAME=metrics.meldestelle.at + +# Kafka Security +export KAFKA_BROKER_ID=1 +export KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 +``` + +#### 🌐 Reverse Proxy Configuration + +**nginx.prod.conf** Beispiel: + +```nginx +upstream api_backend { + server api-gateway:8080; + keepalive 32; +} + +upstream auth_backend { + server keycloak:8443; + keepalive 32; +} + +upstream monitoring_backend { + server grafana:3443; + keepalive 32; +} + +server { + listen 443 ssl http2; + server_name api.meldestelle.at; + + ssl_certificate /etc/ssl/nginx/api.meldestelle.at.crt; + ssl_certificate_key /etc/ssl/nginx/api.meldestelle.at.key; + + # Security headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options DENY always; + add_header X-Content-Type-Options nosniff always; + add_header Referrer-Policy strict-origin-when-cross-origin always; + + location / { + proxy_pass http://api_backend; + 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; + } +} +``` + +### Resource Limits + +Alle Production-Services haben definierte Resource-Limits: + +```yaml +# Beispiel für Resource-Management +services: + postgres: + deploy: + resources: + limits: + memory: 1G + cpus: '0.5' + reservations: + memory: 512M + cpus: '0.25' + + api-gateway: + deploy: + resources: + limits: + memory: 512M + cpus: '0.5' + reservations: + memory: 256M + cpus: '0.25' +``` + +## 🎯 AI-Assistenten: Production-Schnellreferenz + +### Production-Domains +- **API:** api.meldestelle.at (HTTPS) +- **Auth:** auth.meldestelle.at (HTTPS) +- **Monitoring:** monitor.meldestelle.at (HTTPS) +- **Metrics:** metrics.meldestelle.at (HTTPS) + +### Security-Checkliste +- [ ] SSL/TLS-Zertifikate installiert und gültig +- [ ] Alle Passwörter mit `openssl rand -base64 32` generiert +- [ ] Nginx Security Headers konfiguriert +- [ ] Resource Limits für alle Services definiert +- [ ] Firewall-Regeln nur für notwendige Ports +- [ ] Container laufen als non-root User + +### Production-Befehle + +| Aufgabe | Befehl | Beschreibung | +|---------|---------|--------------| +| Zertifikat erneuern | `certbot renew` | Let's Encrypt Zertifikate | +| SSL-Status prüfen | `openssl s_client -connect api.meldestelle.at:443` | SSL-Verbindung testen | +| Resource-Usage | `docker stats` | Container-Ressourcen | +| Security-Scan | `docker scan ` | Vulnerability Check | +| Log-Rotation | `docker system prune -f` | Alte Logs bereinigen | + +### Environment-Variablen Validierung + +```bash +# Production-Variablen prüfen +echo "Postgres User: $POSTGRES_USER" +echo "Keycloak Hostname: $KC_HOSTNAME" +echo "Grafana Hostname: $GRAFANA_HOSTNAME" + +# Passwort-Stärke prüfen (sollte 32+ Zeichen haben) +echo ${#POSTGRES_PASSWORD} # Sollte 44+ ausgeben +echo ${#KEYCLOAK_ADMIN_PASSWORD} # Sollte 44+ ausgeben +``` + +### Deployment-Workflow + +```bash +# 1. Environment-Variablen setzen +source .env.production + +# 2. SSL-Zertifikate prüfen +certbot certificates + +# 3. Services mit Production-Konfiguration starten +docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d + +# 4. Health-Checks durchführen +curl -f https://api.meldestelle.at/actuator/health +curl -f https://auth.meldestelle.at/health/ready +curl -f https://monitor.meldestelle.at/api/health + +# 5. SSL-Konfiguration validieren +curl -I https://api.meldestelle.at | grep -i security +``` + +### Backup-Strategie + +```bash +# Datenbank-Backup +docker-compose exec postgres pg_dump -U $POSTGRES_USER $POSTGRES_DB > backup_$(date +%Y%m%d).sql + +# Konfigurationsdateien sichern +tar -czf config_backup_$(date +%Y%m%d).tar.gz config/ + +# Docker-Volumes sichern +docker run --rm -v postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres_backup_$(date +%Y%m%d).tar.gz /data +``` + +### Monitoring-Integration + +```bash +# Prometheus-Targets prüfen +curl -s https://metrics.meldestelle.at/api/v1/targets | jq '.data.activeTargets[].health' + +# Grafana-Dashboard Status +curl -s https://monitor.meldestelle.at/api/health | jq '.database' +``` + +--- + +**Navigation:** +- [Docker-Overview](./docker-overview.md) - Grundlagen und Philosophie +- [Docker-Architecture](./docker-architecture.md) - Container-Services und Struktur +- [Docker-Development](./docker-development.md) - Entwicklungsworkflow +- [Docker-Monitoring](./docker-monitoring.md) - Observability +- [Docker-Troubleshooting](./docker-troubleshooting.md) - Problemlösung diff --git a/.junie/guidelines/technology-guides/docker/docker-troubleshooting.md b/.junie/guidelines/technology-guides/docker/docker-troubleshooting.md new file mode 100644 index 00000000..2920c23c --- /dev/null +++ b/.junie/guidelines/technology-guides/docker/docker-troubleshooting.md @@ -0,0 +1,299 @@ +# Docker-Troubleshooting und Best Practices + +--- +guideline_type: "technology" +scope: "docker-troubleshooting" +audience: ["developers", "devops", "ai-assistants"] +last_updated: "2025-09-13" +dependencies: ["docker-overview.md", "docker-architecture.md", "docker-development.md"] +related_files: ["docker-compose.yml", "scripts/validate-docker-consistency.sh", "scripts/docker-versions-update.sh"] +ai_context: "Troubleshooting common Docker issues, debug commands, and comprehensive best practices" +--- + +## 🔧 Troubleshooting + +### Häufige Probleme und Lösungen + +#### 🚫 Port-Konflikte + +```bash +# Überprüfe, welche Ports verwendet werden +netstat -tulpn | grep :8080 +lsof -i :8080 + +# Stoppe konfligierende Services +docker-compose down +sudo systemctl stop apache2 # Falls Apache läuft +``` + +#### 🐌 Langsame Startup-Zeiten + +```bash +# Überprüfe Container-Ressourcen +docker stats + +# Health-Check Logs analysieren +docker-compose logs ping-service | grep health + +# Java Startup optimieren +export JAVA_OPTS="$JAVA_OPTS -XX:TieredStopAtLevel=1 -noverify" +``` + +#### 💾 Disk-Space Probleme + +```bash +# Docker-Cleanup +docker system prune -a --volumes +docker volume prune + +# Log-Rotation für Container +docker-compose logs --tail=1000 > /dev/null # Truncate logs +``` + +#### 🌐 Service Discovery Issues + +```bash +# Consul Status prüfen +curl -s http://localhost:8500/v1/health/state/any | jq + +# Service Registration überprüfen +curl -s http://localhost:8500/v1/catalog/services | jq + +# DNS-Resolution testen +docker-compose exec api-gateway nslookup ping-service +``` + +### Debug-Kommandos + +```bash +# Container introspection +docker-compose exec SERVICE_NAME sh +docker-compose exec postgres psql -U meldestelle -d meldestelle + +# Live-Monitoring +docker-compose top +watch -n 1 'docker-compose ps' + +# Memory und CPU-Usage +docker stats $(docker-compose ps -q) + +# Detailed service logs +docker-compose logs -f --tail=50 SERVICE_NAME +``` + +## 🎯 AI-Assistenten: Troubleshooting-Schnellreferenz + +### Häufige Befehle + +| Problem | Befehl | Beschreibung | +|---------|---------|--------------| +| Port belegt | `netstat -tulpn \| grep :` | Port-Nutzung prüfen | +| Service startet nicht | `docker-compose logs ` | Service-Logs anzeigen | +| Container hängt | `docker stats` | Ressourcenverbrauch | +| DNS-Probleme | `docker-compose exec nslookup ` | DNS-Resolution testen | +| Disk voll | `docker system prune -a --volumes` | Cleanup durchführen | + +### Debug-Workflows + +#### Service startet nicht +1. `docker-compose ps` - Status prüfen +2. `docker-compose logs ` - Logs analysieren +3. `docker-compose exec sh` - Container inspizieren +4. Health-Check-Endpoint testen + +#### Performance-Probleme +1. `docker stats` - Ressourcenverbrauch +2. `docker-compose top` - Prozess-Übersicht +3. JVM-Parameter optimieren +4. Resource-Limits anpassen + +#### Netzwerk-Probleme +1. `docker network ls` - Netzwerke auflisten +2. `docker-compose exec ping ` - Connectivity testen +3. Consul Service-Discovery prüfen +4. DNS-Resolution validieren + +## ✅ Best Practices + +### 🔐 Security Best Practices + +1. **Non-Root Users**: Alle Container laufen mit dedizierten Non-Root-Usern +2. **Minimal Base Images**: Alpine Linux für kleinste Angriffsfläche +3. **Secrets Management**: Externe Secret-Stores für Production +4. **Network Isolation**: Dedizierte Docker-Networks +5. **Regular Updates**: Automatische Security-Updates für Base Images + +### ⚡ Performance Best Practices + +1. **Multi-Stage Builds**: Minimale Runtime-Images +2. **Layer Caching**: Optimale COPY-Reihenfolge in Dockerfiles +3. **Resource Limits**: Definierte Memory und CPU-Limits +4. **Health Checks**: Proaktive Container-Health-Überwachung +5. **JVM Tuning**: Container-aware JVM-Settings + +### 🧹 Wartung Best Practices + +1. **Version Pinning**: Explizite Image-Versionen in Production +2. **Backup Strategies**: Automatische Volume-Backups +3. **Log Rotation**: Begrenzte Log-Datei-Größen +4. **Documentation**: Aktuelle README-Dateien pro Service +5. **Testing**: Automatisierte Container-Tests + +### 🎯 Zentrale Verwaltung Best Practices + +#### Single Source of Truth Prinzipien + +```bash +# ✅ RICHTIG - Zentrale Version-Updates +./scripts/docker-versions-update.sh update java 22 +./scripts/docker-versions-update.sh sync + +# ❌ FALSCH - Manuelle Bearbeitung von Dockerfiles +vim dockerfiles/services/ping-service/Dockerfile # Version hardcoden +``` + +> **🤖 AI-Assistant Hinweis:** +> Verwende immer das zentrale Versionssystem: +> - **Updates:** `./scripts/docker-versions-update.sh update ` +> - **Validierung:** `./scripts/validate-docker-consistency.sh` +> - **Template-Updates:** `./scripts/generate-compose-files.sh` + +#### Port-Verwaltung Richtlinien + +1. **Immer zentrale Port-Registry verwenden**: + ```toml + # docker/versions.toml - Port-Definitionen + [service-ports] + new-service = 8089 # Nächster verfügbarer Port + ``` + +2. **Port-Konflikte vor Deployment prüfen**: + ```bash + ./scripts/validate-docker-consistency.sh + ``` + +3. **Port-Ranges einhalten**: + - Infrastructure: 8081-8088 + - Services: 8082-8099 + - Monitoring: 9090-9099 + - Clients: 4000-4099 + +#### Environment-Overrides Standards + +1. **Environment-spezifische Konfigurationen nutzen**: + ```bash + # Development + export DOCKER_ENVIRONMENT=development + + # Production + export DOCKER_ENVIRONMENT=production + ``` + +2. **Konsistente Health-Check-Konfigurationen**: + ```toml + [environments.production] + health-check-interval = "15s" + health-check-timeout = "3s" + health-check-retries = 3 + ``` + +#### Template-System Richtlinien + +1. **Compose-Files aus Templates generieren**: + ```bash + # Automatische Generierung bevorzugen + ./scripts/generate-compose-files.sh + + # Manuelle Bearbeitung nur bei spezifischen Anpassungen + ``` + +2. **Service-Kategorien korrekt zuordnen**: + - `services/`: Domain-Services (ping, members, horses) + - `infrastructure/`: Platform-Services (gateway, auth, monitoring) + - `clients/`: Frontend-Anwendungen (web-app, desktop-app) + +#### Validierung und Konsistenz + +1. **Regelmäßige Konsistenz-Prüfungen**: + ```bash + # Bei jedem Build + ./scripts/validate-docker-consistency.sh + + # In CI/CD Pipeline integrieren + ``` + +2. **Build-Args Konsistenz**: + ```dockerfile + # ✅ RICHTIG - Zentrale Referenz + ARG GRADLE_VERSION + ARG JAVA_VERSION + + # ❌ FALSCH - Hardcodierte Versionen + ARG GRADLE_VERSION=9.0.0 + ``` + +#### IDE-Integration Best Practices + +1. **JSON Schema für Validierung aktivieren**: + ```json + { + "yaml.schemas": { + "./docker/schemas/versions-schema.json": "docker/versions.toml" + } + } + ``` + +2. **Automatisierte Tasks nutzen**: + - Docker: Show Versions + - Docker: Validate Consistency + - Docker: Build All Services + +### 🚀 Entwickler-Workflow Best Practices + +#### Neuen Service hinzufügen + +```bash +# 1. Port in versions.toml reservieren +echo "new-service = 8089" >> docker/versions.toml + +# 2. Template-basierten Service erstellen +./scripts/generate-compose-files.sh + +# 3. Dockerfile aus Template erstellen +cp dockerfiles/templates/spring-boot-service.Dockerfile \ + dockerfiles/services/new-service/Dockerfile + +# 4. Build-Args und Environment synchronisieren +./scripts/docker-versions-update.sh sync + +# 5. Konsistenz validieren +./scripts/validate-docker-consistency.sh +``` + +#### Version-Updates durchführen + +```bash +# 1. Aktuelle Versionen prüfen +./scripts/docker-versions-update.sh show + +# 2. Spezifische Version aktualisieren +./scripts/docker-versions-update.sh update java 22 + +# 3. Alle Build-Args synchronisieren +./scripts/docker-versions-update.sh sync + +# 4. Services neu bauen +docker-compose build --no-cache + +# 5. System-Tests durchführen +docker-compose up -d && make test +``` + +--- + +**Navigation:** +- [Docker-Overview](./docker-overview.md) - Grundlagen und Philosophie +- [Docker-Architecture](./docker-architecture.md) - Container-Services und Struktur +- [Docker-Development](./docker-development.md) - Entwicklungsworkflow +- [Docker-Production](./docker-production.md) - Production-Deployment +- [Docker-Monitoring](./docker-monitoring.md) - Observability diff --git a/.junie/guidelines/web-app-guideline.md b/.junie/guidelines/technology-guides/web-app-guideline.md similarity index 86% rename from .junie/guidelines/web-app-guideline.md rename to .junie/guidelines/technology-guides/web-app-guideline.md index a0e65216..7ad29442 100644 --- a/.junie/guidelines/web-app-guideline.md +++ b/.junie/guidelines/technology-guides/web-app-guideline.md @@ -1,11 +1,28 @@ # Client-App-Richtlinie (Compose Multiplatform) +--- +guideline_type: "technology" +scope: "web-app-multiplatform" +audience: ["developers", "ai-assistants", "frontend-developers"] +last_updated: "2025-09-13" +dependencies: ["master-guideline.md", "architecture-principles.md"] +related_files: ["client/build.gradle.kts", "client/src/commonMain/**", "client/src/wasmJsMain/**", "client/src/jvmMain/**"] +ai_context: "Compose Multiplatform development, MVVM pattern, KMP architecture, desktop and web client development" +--- + ## 1. Einleitung Diese Richtlinie beschreibt die Architektur und die Best Practices für die Entwicklung der Client-Anwendungen für das "Meldestelle"-Projekt. Die Client-Anwendungen werden mit **Compose Multiplatform** für Desktop und Web entwickelt. Das Hauptziel ist die maximale Wiederverwendung von Code zwischen den Desktop- und Web-Plattformen durch die konsequente Nutzung des `commonMain`-Source-Sets von Kotlin Multiplatform (KMP). Die Anwendung läuft sowohl als native Desktop-Anwendung (JVM) als auch als Web-Anwendung (WebAssembly). +> **🤖 AI-Assistant Hinweis:** +> Compose Multiplatform Entwicklung folgt diesen Kernprinzipien: +> - **commonMain:** Geteilte UI-Logik und Business-Logic +> - **MVVM-Pattern:** ViewModels in commonMain, UI-Components plattformübergreifend +> - **@Composable-Funktionen:** Deklarative UI mit State Hoisting +> - **expect/actual:** Plattformspezifische Implementierungen nur wo nötig + ## 2. Grundprinzipien ### Deklarative UI mit Composables @@ -171,7 +188,11 @@ Das Docker-Image für die Web-Produktion (`Dockerfile` im `client`-Verzeichnis) - **DON'T**: Annahmen über die Zielplattform in `commonMain` machen. --- -_Letzte Aktualisierung: 2025-01-10_ -Diese Richtlinie bietet eine solide Grundlage für die Entwicklung Ihrer Desktop- und Web-Anwendungen mit Compose Multiplatform und stellt sicher, dass neue Teammitglieder die Multiplatform-Architektur und die erwarteten Konventionen schnell verstehen. +**Navigation:** +- [Master-Guideline](../master-guideline.md) - Übergeordnete Projektrichtlinien +- [Architecture-Principles](../project-standards/architecture-principles.md) - Architektur-Grundsätze +- [Coding-Standards](../project-standards/coding-standards.md) - Code-Qualitätsstandards +- [Testing-Standards](../project-standards/testing-standards.md) - Test-Qualitätssicherung +- [Trace-Bullet-Guideline](../process-guides/trace-bullet-guideline.md) - Entwicklungszyklus diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..e55fa263 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,126 @@ +{ + "yaml.schemas": { + "./docker/schemas/versions-schema.json": "docker/versions.toml" + }, + "files.associations": { + "docker/versions.toml": "toml", + "*.toml": "toml", + "docker-compose*.yml": "dockercompose", + "Dockerfile*": "dockerfile" + }, + "toml.schema.enabled": true, + "toml.schema.associations": { + "docker/versions.toml": "./docker/schemas/versions-schema.json" + }, + "editor.quickSuggestions": { + "other": "on", + "comments": "off", + "strings": "on" + }, + "editor.suggest.insertMode": "replace", + "editor.acceptSuggestionOnCommitCharacter": true, + "editor.acceptSuggestionOnEnter": "on", + "docker.defaultRegistry": "", + "docker.commands.build": "${workspaceFolder}/scripts/docker-build.sh", + "docker.commands.compose": "docker-compose", + "yaml.format.enable": true, + "yaml.validate": true, + "yaml.completion": true, + "yaml.hover": true, + "dockerfile.format.instructionCase": "upper", + "dockerfile.format.instructionCasing": "upper", + "files.exclude": { + "**/node_modules": true, + "**/.gradle": true, + "**/build": true, + "**/.git": true, + "**/*.class": true, + "**/*.jar": false, + "**/kotlin-js-store": true + }, + "search.exclude": { + "**/node_modules": true, + "**/.gradle": true, + "**/build": true, + "**/kotlin-js-store": true, + "**/*.jar": true + }, + "[toml]": { + "editor.defaultFormatter": "tamasfe.even-better-toml", + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit" + } + }, + "[dockercompose]": { + "editor.defaultFormatter": "ms-azuretools.vscode-docker", + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.formatOnSave": true + }, + "[dockerfile]": { + "editor.defaultFormatter": "ms-azuretools.vscode-docker", + "editor.tabSize": 4, + "editor.insertSpaces": true, + "editor.formatOnSave": true + }, + "[yaml]": { + "editor.defaultFormatter": "redhat.vscode-yaml", + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.formatOnSave": true + }, + "tasks.version": "2.0.0", + "terminal.integrated.cwd": "${workspaceFolder}", + "terminal.integrated.env.linux": { + "DOCKER_BUILDKIT": "1" + }, + "terminal.integrated.env.osx": { + "DOCKER_BUILDKIT": "1" + }, + "terminal.integrated.env.windows": { + "DOCKER_BUILDKIT": "1" + }, + "extensions.recommendations": [ + "tamasfe.even-better-toml", + "ms-azuretools.vscode-docker", + "redhat.vscode-yaml", + "ms-vscode.vscode-json", + "ms-kubernetes-tools.vscode-kubernetes-tools", + "formulahendry.docker-explorer" + ], + "json.validate.enable": true, + "json.schemas": [ + { + "fileMatch": [ + "docker/versions.toml" + ], + "url": "./docker/schemas/versions-schema.json" + } + ], + "git.ignoreLimitWarning": true, + "git.detectSubmodules": false, + "shellcheck.enable": true, + "shellcheck.executablePath": "shellcheck", + "shellcheck.run": "onType", + "editor.snippetSuggestions": "top", + "files.autoSave": "afterDelay", + "files.autoSaveDelay": 1000, + "breadcrumbs.enabled": true, + "breadcrumbs.showFiles": true, + "breadcrumbs.showModules": true, + "problems.decorations.enabled": true, + "security.workspace.trust.untrustedFiles": "open", + "command-runner.commands": { + "docker-versions-show": "scripts/docker-versions-update.sh show", + "docker-versions-sync": "scripts/docker-versions-update.sh sync", + "docker-validate": "scripts/validate-docker-consistency.sh", + "docker-generate-compose": "scripts/generate-compose-files.sh all development", + "docker-build-all": "scripts/docker-build.sh all", + "docker-up-dev": "docker-compose -f docker-compose.yml -f docker-compose.services.yml up -d", + "docker-down": "docker-compose -f docker-compose.yml -f docker-compose.services.yml down", + "docker-logs": "docker-compose -f docker-compose.yml -f docker-compose.services.yml logs -f" + } +} diff --git a/docker-compose.yml b/docker-compose.yml index da13fc59..0ff1090a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -57,7 +57,7 @@ services: # Authentifizierung # =================================================================== keycloak: - image: quay.io/keycloak/keycloak:25.0.6 + image: quay.io/keycloak/keycloak:${DOCKER_KEYCLOAK_VERSION:-26.0.7} container_name: meldestelle-keycloak environment: KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN:-admin} @@ -153,7 +153,7 @@ services: # Monitoring (Prometheus & Grafana) # =================================================================== prometheus: - image: prom/prometheus:v2.47.0 + image: prom/prometheus:${DOCKER_PROMETHEUS_VERSION:-v2.54.1} container_name: meldestelle-prometheus ports: - "${PROMETHEUS_PORT:-9090}:9090" @@ -178,7 +178,7 @@ services: restart: unless-stopped grafana: - image: grafana/grafana:10.1.0 + image: grafana/grafana:${DOCKER_GRAFANA_VERSION:-11.3.0} container_name: meldestelle-grafana environment: GF_SECURITY_ADMIN_USER: ${GF_SECURITY_ADMIN_USER:-admin} diff --git a/docker/build-args/clients.env b/docker/build-args/clients.env index 58f4430d..4880961a 100644 --- a/docker/build-args/clients.env +++ b/docker/build-args/clients.env @@ -1,7 +1,7 @@ # =================================================================== # Clients Docker Build Arguments - dockerfiles/clients/* # Source: docker/versions.toml [categories.clients] -# Last updated: 2025-09-13 12:51:22 UTC +# Last updated: 2025-09-13 18:33:34 UTC # =================================================================== # --- Include Global Arguments --- diff --git a/docker/build-args/global.env b/docker/build-args/global.env index af5dd096..1dac6b97 100644 --- a/docker/build-args/global.env +++ b/docker/build-args/global.env @@ -1,7 +1,7 @@ # =================================================================== # Global Docker Build Arguments - Used by all categories # Source: docker/versions.toml -# Last updated: 2025-09-13 12:51:22 UTC +# Last updated: 2025-09-13 18:33:34 UTC # =================================================================== # --- Build Tools --- @@ -17,3 +17,8 @@ DOCKER_APP_VERSION ALPINE_VERSION=3.19 ECLIPSE_TEMURIN_JDK_VERSION=21-jdk-alpine ECLIPSE_TEMURIN_JRE_VERSION=21-jre-alpine + +# --- Monitoring & Infrastructure Services --- +DOCKER_PROMETHEUS_VERSION=v2.54.1 +DOCKER_GRAFANA_VERSION=11.3.0 +DOCKER_KEYCLOAK_VERSION=26.0.7 diff --git a/docker/build-args/infrastructure.env b/docker/build-args/infrastructure.env index 4436f3ab..0d89fc36 100644 --- a/docker/build-args/infrastructure.env +++ b/docker/build-args/infrastructure.env @@ -1,7 +1,7 @@ # =================================================================== # Infrastructure Docker Build Arguments - dockerfiles/infrastructure/* # Source: docker/versions.toml [categories.infrastructure] -# Last updated: 2025-09-13 12:51:22 UTC +# Last updated: 2025-09-13 18:33:34 UTC # =================================================================== # --- Include Global Arguments --- diff --git a/docker/build-args/services.env b/docker/build-args/services.env index 4bfee021..7950eabd 100644 --- a/docker/build-args/services.env +++ b/docker/build-args/services.env @@ -1,7 +1,7 @@ # =================================================================== # Services Docker Build Arguments - dockerfiles/services/* # Source: docker/versions.toml [categories.services] -# Last updated: 2025-09-13 12:51:22 UTC +# Last updated: 2025-09-13 18:33:34 UTC # =================================================================== # --- Include Global Arguments --- diff --git a/docker/schemas/versions-schema.json b/docker/schemas/versions-schema.json new file mode 100644 index 00000000..f8256d20 --- /dev/null +++ b/docker/schemas/versions-schema.json @@ -0,0 +1,619 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://meldestelle.at/schemas/docker-versions.json", + "title": "Docker Versions TOML Schema", + "description": "Schema for docker/versions.toml - centralized Docker version management", + "type": "object", + "properties": { + "versions": { + "type": "object", + "description": "Central version definitions for all Docker components", + "properties": { + "gradle": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$", + "description": "Gradle version for build tools", + "examples": ["9.0.0", "8.14.0"] + }, + "java": { + "type": "string", + "pattern": "^[0-9]+$", + "description": "Java version (LTS recommended)", + "examples": ["21", "17", "11"] + }, + "node": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$", + "description": "Node.js version for client builds", + "examples": ["20.12.0", "18.19.0"] + }, + "nginx": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+-alpine$", + "description": "Nginx version with Alpine base", + "examples": ["1.25-alpine", "1.24-alpine"] + }, + "alpine": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+$", + "description": "Alpine Linux base image version", + "examples": ["3.19", "3.18"] + }, + "eclipse-temurin-jdk": { + "type": "string", + "pattern": "^[0-9]+-jdk-alpine$", + "description": "Eclipse Temurin JDK image tag", + "examples": ["21-jdk-alpine", "17-jdk-alpine"] + }, + "eclipse-temurin-jre": { + "type": "string", + "pattern": "^[0-9]+-jre-alpine$", + "description": "Eclipse Temurin JRE image tag", + "examples": ["21-jre-alpine", "17-jre-alpine"] + }, + "prometheus": { + "type": "string", + "pattern": "^v[0-9]+\\.[0-9]+\\.[0-9]+$", + "description": "Prometheus monitoring version", + "examples": ["v2.54.1", "v2.47.0"] + }, + "grafana": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$", + "description": "Grafana visualization version", + "examples": ["11.3.0", "10.1.0"] + }, + "keycloak": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$", + "description": "Keycloak authentication version", + "examples": ["26.0.7", "25.0.6"] + }, + "spring-profiles-default": { + "type": "string", + "enum": ["default", "dev", "test", "prod"], + "description": "Default Spring profile for infrastructure services" + }, + "spring-profiles-docker": { + "type": "string", + "enum": ["docker", "dev", "test", "prod"], + "description": "Spring profile for Docker containers" + }, + "spring-profiles-prod": { + "type": "string", + "enum": ["prod", "production"], + "description": "Spring profile for production environment" + }, + "app-version": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$", + "description": "Application version for all services", + "examples": ["1.0.0", "2.1.3"] + } + }, + "required": [ + "gradle", + "java", + "node", + "nginx", + "alpine", + "prometheus", + "grafana", + "keycloak", + "app-version" + ], + "additionalProperties": false + }, + "service-ports": { + "type": "object", + "description": "Centralized port definitions for all services", + "properties": { + "api-gateway": { + "type": "integer", + "minimum": 8081, + "maximum": 8081, + "description": "API Gateway port" + }, + "auth-server": { + "type": "integer", + "minimum": 8087, + "maximum": 8087, + "description": "Authentication server port" + }, + "monitoring-server": { + "type": "integer", + "minimum": 8088, + "maximum": 8088, + "description": "Monitoring server port" + }, + "ping-service": { + "type": "integer", + "minimum": 8082, + "maximum": 8082, + "description": "Ping service port" + }, + "members-service": { + "type": "integer", + "minimum": 8083, + "maximum": 8083, + "description": "Members service port" + }, + "horses-service": { + "type": "integer", + "minimum": 8084, + "maximum": 8084, + "description": "Horses service port" + }, + "events-service": { + "type": "integer", + "minimum": 8085, + "maximum": 8085, + "description": "Events service port" + }, + "masterdata-service": { + "type": "integer", + "minimum": 8086, + "maximum": 8086, + "description": "Masterdata service port" + }, + "postgres": { + "type": "integer", + "minimum": 5432, + "maximum": 5432, + "description": "PostgreSQL database port" + }, + "redis": { + "type": "integer", + "minimum": 6379, + "maximum": 6379, + "description": "Redis cache port" + }, + "keycloak": { + "type": "integer", + "minimum": 8180, + "maximum": 8180, + "description": "Keycloak authentication port" + }, + "consul": { + "type": "integer", + "minimum": 8500, + "maximum": 8500, + "description": "Consul service discovery port" + }, + "zookeeper": { + "type": "integer", + "minimum": 2181, + "maximum": 2181, + "description": "Zookeeper coordination port" + }, + "kafka": { + "type": "integer", + "minimum": 9092, + "maximum": 9092, + "description": "Kafka messaging port" + }, + "prometheus": { + "type": "integer", + "minimum": 9090, + "maximum": 9090, + "description": "Prometheus monitoring port" + }, + "grafana": { + "type": "integer", + "minimum": 3000, + "maximum": 3000, + "description": "Grafana visualization port" + }, + "web-app": { + "type": "integer", + "minimum": 4000, + "maximum": 4000, + "description": "Web application port" + }, + "desktop-app-vnc": { + "type": "integer", + "minimum": 5901, + "maximum": 5901, + "description": "Desktop app VNC port" + }, + "desktop-app-novnc": { + "type": "integer", + "minimum": 6080, + "maximum": 6080, + "description": "Desktop app noVNC web port" + } + }, + "required": [ + "api-gateway", + "auth-server", + "monitoring-server", + "ping-service", + "postgres", + "redis", + "keycloak", + "prometheus", + "grafana", + "web-app" + ], + "additionalProperties": false + }, + "port-ranges": { + "type": "object", + "description": "Port range definitions for service categories", + "properties": { + "infrastructure": { + "type": "string", + "pattern": "^[0-9]+-[0-9]+$", + "description": "Port range for infrastructure services", + "examples": ["8081-8088"] + }, + "services": { + "type": "string", + "pattern": "^[0-9]+-[0-9]+$", + "description": "Port range for application services", + "examples": ["8082-8099"] + }, + "monitoring": { + "type": "string", + "pattern": "^[0-9]+-[0-9]+$", + "description": "Port range for monitoring services", + "examples": ["9090-9099"] + }, + "clients": { + "type": "string", + "pattern": "^[0-9]+-[0-9]+$", + "description": "Port range for client applications", + "examples": ["4000-4099"] + }, + "vnc": { + "type": "string", + "pattern": "^[0-9]+-[0-9]+$", + "description": "Port range for VNC connections", + "examples": ["5901-5999"] + }, + "debug": { + "type": "string", + "pattern": "^[0-9]+-[0-9]+$", + "description": "Port range for debug connections", + "examples": ["5005-5009"] + }, + "system-reserved": { + "type": "string", + "pattern": "^[0-9]+-[0-9]+$", + "description": "System reserved port range", + "examples": ["0-1023"] + }, + "ephemeral": { + "type": "string", + "pattern": "^[0-9]+-[0-9]+$", + "description": "Ephemeral port range", + "examples": ["32768-65535"] + } + }, + "required": [ + "infrastructure", + "services", + "monitoring", + "clients", + "debug" + ], + "additionalProperties": false + }, + "build-args": { + "type": "object", + "description": "Build argument categories for different service types", + "properties": { + "global": { + "type": "array", + "description": "Global build arguments used by all services", + "items": { + "type": "string", + "enum": [ + "GRADLE_VERSION", + "JAVA_VERSION", + "BUILD_DATE", + "VERSION" + ] + }, + "uniqueItems": true + }, + "spring-services": { + "type": "array", + "description": "Spring Boot service-specific build arguments", + "items": { + "type": "string", + "enum": [ + "SPRING_PROFILES_ACTIVE", + "SERVICE_PATH", + "SERVICE_NAME", + "SERVICE_PORT" + ] + }, + "uniqueItems": true + }, + "web-clients": { + "type": "array", + "description": "Web client-specific build arguments", + "items": { + "type": "string", + "enum": [ + "NODE_VERSION", + "NGINX_VERSION", + "CLIENT_PATH", + "CLIENT_MODULE", + "CLIENT_NAME" + ] + }, + "uniqueItems": true + } + }, + "required": ["global"], + "additionalProperties": false + }, + "categories": { + "type": "object", + "description": "Service category configurations", + "properties": { + "services": { + "type": "object", + "properties": { + "default-spring-profile": { + "type": "string", + "enum": ["docker", "dev", "test", "prod"] + }, + "default-port-start": { + "type": "integer", + "minimum": 8082, + "maximum": 8099 + }, + "services": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "ping-service", + "members-service", + "horses-service", + "events-service", + "masterdata-service" + ] + }, + "uniqueItems": true + } + }, + "required": ["services"], + "additionalProperties": false + }, + "infrastructure": { + "type": "object", + "properties": { + "default-spring-profile": { + "type": "string", + "enum": ["default", "dev", "test", "prod"] + }, + "services": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "gateway", + "auth-server", + "monitoring-server" + ] + }, + "uniqueItems": true + } + }, + "required": ["services"], + "additionalProperties": false + }, + "clients": { + "type": "object", + "properties": { + "default-node-version": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" + }, + "default-nginx-version": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+-alpine$" + }, + "clients": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "web-app", + "desktop-app" + ] + }, + "uniqueItems": true + } + }, + "required": ["clients"], + "additionalProperties": false + } + }, + "required": ["services", "infrastructure", "clients"], + "additionalProperties": false + }, + "environment-mapping": { + "type": "object", + "description": "Maps internal version names to environment variable names", + "properties": { + "gradle-version": { + "type": "string", + "enum": ["DOCKER_GRADLE_VERSION"] + }, + "java-version": { + "type": "string", + "enum": ["DOCKER_JAVA_VERSION"] + }, + "node-version": { + "type": "string", + "enum": ["DOCKER_NODE_VERSION"] + }, + "nginx-version": { + "type": "string", + "enum": ["DOCKER_NGINX_VERSION"] + }, + "prometheus-version": { + "type": "string", + "enum": ["DOCKER_PROMETHEUS_VERSION"] + }, + "grafana-version": { + "type": "string", + "enum": ["DOCKER_GRAFANA_VERSION"] + }, + "keycloak-version": { + "type": "string", + "enum": ["DOCKER_KEYCLOAK_VERSION"] + }, + "spring-profiles-default": { + "type": "string", + "enum": ["DOCKER_SPRING_PROFILES_DEFAULT"] + }, + "spring-profiles-docker": { + "type": "string", + "enum": ["DOCKER_SPRING_PROFILES_DOCKER"] + }, + "app-version": { + "type": "string", + "enum": ["DOCKER_APP_VERSION"] + } + }, + "required": [ + "gradle-version", + "java-version", + "node-version", + "nginx-version", + "prometheus-version", + "grafana-version", + "keycloak-version", + "app-version" + ], + "additionalProperties": false + }, + "environments": { + "type": "object", + "description": "Environment-specific configurations", + "properties": { + "development": { + "$ref": "#/definitions/environment-config" + }, + "production": { + "$ref": "#/definitions/environment-config" + }, + "testing": { + "$ref": "#/definitions/environment-config" + } + }, + "required": ["development", "production", "testing"], + "additionalProperties": false + } + }, + "required": [ + "versions", + "service-ports", + "port-ranges", + "build-args", + "categories", + "environment-mapping", + "environments" + ], + "additionalProperties": false, + "definitions": { + "environment-config": { + "type": "object", + "description": "Environment-specific configuration settings", + "properties": { + "spring-profiles": { + "type": "string", + "enum": ["dev", "test", "prod", "docker"], + "description": "Default Spring profiles for this environment" + }, + "debug-enabled": { + "type": "boolean", + "description": "Whether debug mode is enabled" + }, + "log-level": { + "type": "string", + "enum": ["TRACE", "DEBUG", "INFO", "WARN", "ERROR"], + "description": "Default log level for services" + }, + "health-check-interval": { + "type": "string", + "pattern": "^[0-9]+s$", + "description": "Health check interval (e.g., '30s')" + }, + "health-check-timeout": { + "type": "string", + "pattern": "^[0-9]+s$", + "description": "Health check timeout (e.g., '5s')" + }, + "health-check-retries": { + "type": "integer", + "minimum": 1, + "maximum": 10, + "description": "Number of health check retries" + }, + "health-check-start-period": { + "type": "string", + "pattern": "^[0-9]+s$", + "description": "Health check start period (e.g., '40s')" + }, + "resource-limits": { + "type": "boolean", + "description": "Whether to enforce resource limits" + }, + "jvm-debug-port": { + "oneOf": [ + { + "type": "integer", + "minimum": 5005, + "maximum": 5009 + }, + { + "type": "boolean", + "enum": [false] + } + ], + "description": "JVM debug port (5005-5009) or false to disable" + }, + "hot-reload": { + "type": "boolean", + "description": "Whether hot reload is enabled for development" + }, + "security-headers": { + "type": "boolean", + "description": "Whether to add security headers (production)" + }, + "tls-enabled": { + "type": "boolean", + "description": "Whether TLS/SSL is enabled (production)" + }, + "ephemeral-storage": { + "type": "boolean", + "description": "Whether to use ephemeral storage (testing)" + }, + "test-containers": { + "type": "boolean", + "description": "Whether test containers are used (testing)" + } + }, + "required": [ + "spring-profiles", + "debug-enabled", + "log-level", + "health-check-interval", + "health-check-timeout", + "health-check-retries", + "health-check-start-period", + "resource-limits", + "jvm-debug-port", + "hot-reload" + ], + "additionalProperties": false + } + } +} diff --git a/docker/versions.toml b/docker/versions.toml index dba9a143..d6482597 100644 --- a/docker/versions.toml +++ b/docker/versions.toml @@ -17,6 +17,11 @@ alpine = "3.19" eclipse-temurin-jdk = "21-jdk-alpine" eclipse-temurin-jre = "21-jre-alpine" +# --- Monitoring & Infrastructure Services --- +prometheus = "v2.54.1" +grafana = "11.3.0" +keycloak = "26.0.7" + # --- Spring Configuration --- spring-profiles-default = "default" spring-profiles-docker = "docker" @@ -25,6 +30,52 @@ spring-profiles-prod = "prod" # --- Application Versions --- app-version = "1.0.0" +# --- Zentrale Port-Verwaltung --- +# Single Source of Truth für alle Service-Ports + +[service-ports] +# --- Infrastructure Services --- +api-gateway = 8081 +auth-server = 8087 +monitoring-server = 8088 + +# --- Application Services --- +ping-service = 8082 +members-service = 8083 +horses-service = 8084 +events-service = 8085 +masterdata-service = 8086 + +# --- External Services --- +postgres = 5432 +redis = 6379 +keycloak = 8180 +consul = 8500 +zookeeper = 2181 +kafka = 9092 + +# --- Monitoring Stack --- +prometheus = 9090 +grafana = 3000 + +# --- Client Applications --- +web-app = 4000 +desktop-app-vnc = 5901 +desktop-app-novnc = 6080 + +[port-ranges] +# --- Port-Range-Definitionen für automatische Port-Zuweisung --- +infrastructure = "8081-8088" +services = "8082-8099" +monitoring = "9090-9099" +clients = "4000-4099" +vnc = "5901-5999" +debug = "5005-5009" + +# --- Reserved Port Ranges --- +system-reserved = "0-1023" +ephemeral = "32768-65535" + [build-args] # --- Global Build Arguments (used across all categories) --- global = [ @@ -89,6 +140,53 @@ gradle-version = "DOCKER_GRADLE_VERSION" java-version = "DOCKER_JAVA_VERSION" node-version = "DOCKER_NODE_VERSION" nginx-version = "DOCKER_NGINX_VERSION" +prometheus-version = "DOCKER_PROMETHEUS_VERSION" +grafana-version = "DOCKER_GRAFANA_VERSION" +keycloak-version = "DOCKER_KEYCLOAK_VERSION" spring-profiles-default = "DOCKER_SPRING_PROFILES_DEFAULT" spring-profiles-docker = "DOCKER_SPRING_PROFILES_DOCKER" app-version = "DOCKER_APP_VERSION" + +[environments] +# --- Environment-spezifische Konfigurationen --- +# Zentrale Verwaltung für dev/test/prod Umgebungen + +[environments.development] +spring-profiles = "dev" +debug-enabled = true +log-level = "DEBUG" +health-check-interval = "30s" +health-check-timeout = "5s" +health-check-retries = 3 +health-check-start-period = "40s" +resource-limits = false +jvm-debug-port = 5005 +hot-reload = true + +[environments.production] +spring-profiles = "prod" +debug-enabled = false +log-level = "INFO" +health-check-interval = "15s" +health-check-timeout = "3s" +health-check-retries = 3 +health-check-start-period = "30s" +resource-limits = true +jvm-debug-port = false +hot-reload = false +security-headers = true +tls-enabled = true + +[environments.testing] +spring-profiles = "test" +debug-enabled = true +log-level = "DEBUG" +health-check-interval = "10s" +health-check-timeout = "5s" +health-check-retries = 2 +health-check-start-period = "20s" +resource-limits = false +jvm-debug-port = 5005 +hot-reload = false +ephemeral-storage = true +test-containers = true diff --git a/scripts/docker-versions-update.sh b/scripts/docker-versions-update.sh index c70da758..8b0ff870 100755 --- a/scripts/docker-versions-update.sh +++ b/scripts/docker-versions-update.sh @@ -71,6 +71,9 @@ sync_to_env_files() { local spring_default=$(get_version "spring-profiles-default") local spring_docker=$(get_version "spring-profiles-docker") local alpine_version=$(get_version "alpine") + local prometheus_version=$(get_version "prometheus") + local grafana_version=$(get_version "grafana") + local keycloak_version=$(get_version "keycloak") # Update global.env cat > "$BUILD_ARGS_DIR/global.env" << EOF @@ -92,6 +95,11 @@ VERSION=$app_version ALPINE_VERSION=$alpine_version ECLIPSE_TEMURIN_JDK_VERSION=$java_version-jdk-alpine ECLIPSE_TEMURIN_JRE_VERSION=$java_version-jre-alpine + +# --- Monitoring & Infrastructure Services --- +DOCKER_PROMETHEUS_VERSION=$prometheus_version +DOCKER_GRAFANA_VERSION=$grafana_version +DOCKER_KEYCLOAK_VERSION=$keycloak_version EOF print_success "Updated global.env" @@ -220,6 +228,9 @@ show_current_versions() { echo " Node.js: $(get_version "node")" echo " Nginx: $(get_version "nginx")" echo " Alpine: $(get_version "alpine")" + echo " Prometheus: $(get_version "prometheus")" + echo " Grafana: $(get_version "grafana")" + echo " Keycloak: $(get_version "keycloak")" echo " App Version: $(get_version "app-version")" echo " Spring Profile (Default): $(get_version "spring-profiles-default")" echo " Spring Profile (Docker): $(get_version "spring-profiles-docker")" @@ -242,6 +253,9 @@ show_help() { echo " node Node.js version" echo " nginx Nginx version" echo " alpine Alpine Linux version" + echo " prometheus Prometheus version" + echo " grafana Grafana version" + echo " keycloak Keycloak version" echo " app-version Application version" echo " spring-profiles-default Default Spring profile" echo " spring-profiles-docker Docker Spring profile" diff --git a/scripts/generate-compose-files.sh b/scripts/generate-compose-files.sh new file mode 100755 index 00000000..911d99a3 --- /dev/null +++ b/scripts/generate-compose-files.sh @@ -0,0 +1,504 @@ +#!/bin/bash +# =================================================================== +# Docker Compose Template Generator +# Generates docker-compose files from docker/versions.toml templates +# =================================================================== + +set -e + +# Script directory and project root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +DOCKER_DIR="$PROJECT_ROOT/docker" +VERSIONS_TOML="$DOCKER_DIR/versions.toml" +TEMPLATES_DIR="$DOCKER_DIR/compose-templates" +OUTPUT_DIR="$PROJECT_ROOT" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to extract version from TOML file +get_version() { + local key=$1 + grep "^$key = " "$VERSIONS_TOML" | sed 's/.*= "\(.*\)"/\1/' || echo "" +} + +# Function to extract port from TOML file +get_port() { + local service=$1 + grep "^$service = " "$VERSIONS_TOML" | grep -A 50 "\[service-ports\]" | grep "^$service = " | sed 's/.*= \(.*\)/\1/' || echo "" +} + +# Function to extract environment config from TOML file +get_env_config() { + local env=$1 + local key=$2 + awk "/\[environments\.$env\]/,/^\[/ {if (/^$key = /) {gsub(/.*= \"?|\"?$/, \"\"); print}}" "$VERSIONS_TOML" || echo "" +} + +# Function to generate build args section for a service category +generate_build_args_section() { + local category=$1 + + cat << EOF + args: + # Global build arguments (from docker/build-args/global.env) + GRADLE_VERSION: \${DOCKER_GRADLE_VERSION:-$(get_version "gradle")} + JAVA_VERSION: \${DOCKER_JAVA_VERSION:-$(get_version "java")} + BUILD_DATE: \${BUILD_DATE} + VERSION: \${DOCKER_APP_VERSION:-$(get_version "app-version")} +EOF + + case $category in + "services") + cat << EOF + # Service-specific arguments (from docker/build-args/services.env) + SPRING_PROFILES_ACTIVE: \${DOCKER_SPRING_PROFILES_DOCKER:-$(get_version "spring-profiles-docker")} +EOF + ;; + "infrastructure") + cat << EOF + # Infrastructure-specific arguments (from docker/build-args/infrastructure.env) + SPRING_PROFILES_ACTIVE: \${DOCKER_SPRING_PROFILES_DEFAULT:-$(get_version "spring-profiles-default")} +EOF + ;; + "clients") + cat << EOF + # Client-specific arguments (from docker/build-args/clients.env) + NODE_VERSION: \${DOCKER_NODE_VERSION:-$(get_version "node")} + NGINX_VERSION: \${DOCKER_NGINX_VERSION:-$(get_version "nginx")} +EOF + ;; + esac +} + +# Function to generate environment variables section +generate_environment_vars_for_service() { + local service=$1 + local environment=${2:-development} + + local spring_profiles=$(get_env_config $environment "spring-profiles") + local debug_enabled=$(get_env_config $environment "debug-enabled") + local log_level=$(get_env_config $environment "log-level") + local debug_port=$(get_env_config $environment "jvm-debug-port") + local service_port=$(get_port $service) + + cat << EOF + environment: + SPRING_PROFILES_ACTIVE: \${SPRING_PROFILES_ACTIVE:-$spring_profiles} + SERVER_PORT: \${${service^^}_PORT:-$service_port} + DEBUG: \${DEBUG:-$debug_enabled} + LOGGING_LEVEL_ROOT: \${LOGGING_LEVEL_ROOT:-$log_level} +EOF + + # Add debug port if enabled + if [[ "$debug_port" != "false" && "$debug_port" != "" ]]; then + echo " JVM_DEBUG_PORT: ${debug_port}" + fi +} + +# Function to generate health check section +generate_health_check() { + local service=$1 + local environment=${2:-development} + + local interval=$(get_env_config $environment "health-check-interval") + local timeout=$(get_env_config $environment "health-check-timeout") + local retries=$(get_env_config $environment "health-check-retries") + local start_period=$(get_env_config $environment "health-check-start-period") + local service_port=$(get_port $service) + + cat << EOF + healthcheck: + test: ["CMD", "curl", "--fail", "http://localhost:${service_port}/actuator/health/readiness"] + interval: ${interval:-30s} + timeout: ${timeout:-5s} + retries: ${retries:-3} + start_period: ${start_period:-40s} +EOF +} + +# Function to generate service definition +generate_service_definition() { + local service=$1 + local category=$2 + local environment=${3:-development} + + local service_port=$(get_port $service) + local debug_port=$(get_env_config $environment "jvm-debug-port") + + cat << EOF + $service: + build: + context: . + dockerfile: dockerfiles/$category/$service/Dockerfile +$(generate_build_args_section $category) + container_name: meldestelle-$service +$(generate_environment_vars_for_service $service $environment) + ports: + - "\${${service^^}_PORT:-$service_port}:$service_port" +EOF + + # Add debug port if enabled + if [[ "$debug_port" != "false" && "$debug_port" != "" ]]; then + echo " - \"${debug_port}:${debug_port}\" # Debug-Port" + fi + + cat << EOF + networks: + - meldestelle-network +$(generate_health_check $service $environment) + restart: unless-stopped +EOF +} + +# Function to generate main infrastructure compose file +generate_infrastructure_compose() { + local environment=${1:-development} + + print_info "Generating docker-compose.yml (Infrastructure)..." + + cat > "$OUTPUT_DIR/docker-compose.yml" << EOF +# =================================================================== +# Docker Compose - Infrastructure Services +# Generated from docker/versions.toml +# Environment: $environment +# Generated: $(date -u +'%Y-%m-%d %H:%M:%S UTC') +# =================================================================== + +services: + # =================================================================== + # Database + # =================================================================== + postgres: + image: postgres:16-alpine + container_name: meldestelle-postgres + environment: + POSTGRES_USER: \${POSTGRES_USER:-meldestelle} + POSTGRES_PASSWORD: \${POSTGRES_PASSWORD:-meldestelle} + POSTGRES_DB: \${POSTGRES_DB:-meldestelle} + ports: + - "$(get_port postgres):$(get_port postgres)" + volumes: + - postgres-data:/var/lib/postgresql/data + - ./docker/services/postgres:/docker-entrypoint-initdb.d + networks: + - meldestelle-network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U meldestelle -d meldestelle"] + interval: $(get_env_config $environment "health-check-interval") + timeout: $(get_env_config $environment "health-check-timeout") + retries: $(get_env_config $environment "health-check-retries") + start_period: $(get_env_config $environment "health-check-start-period") + restart: unless-stopped + + # =================================================================== + # Cache + # =================================================================== + redis: + image: redis:7-alpine + container_name: meldestelle-redis + ports: + - "\${REDIS_PORT:-$(get_port redis)}:$(get_port redis)" + volumes: + - redis-data:/data + command: redis-server --appendonly yes + networks: + - meldestelle-network + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: $(get_env_config $environment "health-check-interval") + timeout: $(get_env_config $environment "health-check-timeout") + retries: $(get_env_config $environment "health-check-retries") + start_period: $(get_env_config $environment "health-check-start-period") + restart: unless-stopped + + # =================================================================== + # Authentication + # =================================================================== + keycloak: + image: quay.io/keycloak/keycloak:\${DOCKER_KEYCLOAK_VERSION:-$(get_version "keycloak")} + container_name: meldestelle-keycloak + environment: + KEYCLOAK_ADMIN: \${KEYCLOAK_ADMIN:-admin} + KEYCLOAK_ADMIN_PASSWORD: \${KEYCLOAK_ADMIN_PASSWORD:-admin} + KC_DB: postgres + KC_DB_URL: jdbc:postgresql://postgres:$(get_port postgres)/\${POSTGRES_DB:-meldestelle} + KC_DB_USERNAME: \${POSTGRES_USER:-meldestelle} + KC_DB_PASSWORD: \${POSTGRES_PASSWORD:-meldestelle} + ports: + - "$(get_port keycloak):8080" + depends_on: + postgres: + condition: service_healthy + volumes: + - ./docker/services/keycloak:/opt/keycloak/data/import + command: start-dev --import-realm + networks: + - meldestelle-network + healthcheck: + test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/"] + interval: $(get_env_config $environment "health-check-interval") + timeout: $(get_env_config $environment "health-check-timeout") + retries: $(get_env_config $environment "health-check-retries") + start_period: $(get_env_config $environment "health-check-start-period") + restart: unless-stopped + + # =================================================================== + # Monitoring + # =================================================================== + prometheus: + image: prom/prometheus:\${DOCKER_PROMETHEUS_VERSION:-$(get_version "prometheus")} + container_name: meldestelle-prometheus + ports: + - "\${PROMETHEUS_PORT:-$(get_port prometheus)}:$(get_port prometheus)" + volumes: + - prometheus-data:/prometheus + - ./docker/monitoring/prometheus:/etc/prometheus:ro + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + - '--web.console.libraries=/etc/prometheus/console_libraries' + - '--web.console.templates=/etc/prometheus/consoles' + - '--storage.tsdb.retention.time=200h' + - '--web.enable-lifecycle' + networks: + - meldestelle-network + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:$(get_port prometheus)/-/healthy"] + interval: $(get_env_config $environment "health-check-interval") + timeout: $(get_env_config $environment "health-check-timeout") + retries: $(get_env_config $environment "health-check-retries") + start_period: $(get_env_config $environment "health-check-start-period") + restart: unless-stopped + + grafana: + image: grafana/grafana:\${DOCKER_GRAFANA_VERSION:-$(get_version "grafana")} + container_name: meldestelle-grafana + environment: + GF_SECURITY_ADMIN_USER: \${GF_SECURITY_ADMIN_USER:-admin} + GF_SECURITY_ADMIN_PASSWORD: \${GF_SECURITY_ADMIN_PASSWORD:-admin} + GF_USERS_ALLOW_SIGN_UP: \${GF_USERS_ALLOW_SIGN_UP:-false} + GF_INSTALL_PLUGINS: grafana-piechart-panel + ports: + - "\${GRAFANA_PORT:-$(get_port grafana)}:$(get_port grafana)" + volumes: + - grafana-data:/var/lib/grafana + - ./docker/monitoring/grafana:/etc/grafana/provisioning:ro + depends_on: + - prometheus + networks: + - meldestelle-network + healthcheck: + test: ["CMD", "curl", "--fail", "http://localhost:$(get_port grafana)/api/health"] + interval: $(get_env_config $environment "health-check-interval") + timeout: $(get_env_config $environment "health-check-timeout") + retries: $(get_env_config $environment "health-check-retries") + start_period: $(get_env_config $environment "health-check-start-period") + restart: unless-stopped + +# =================================================================== +# Volumes +# =================================================================== +volumes: + postgres-data: + driver: local + redis-data: + driver: local + prometheus-data: + driver: local + grafana-data: + driver: local + +# =================================================================== +# Networks +# =================================================================== +networks: + meldestelle-network: + driver: bridge +EOF + + print_success "Generated docker-compose.yml" +} + +# Function to generate services compose file +generate_services_compose() { + local environment=${1:-development} + + print_info "Generating docker-compose.services.yml..." + + cat > "$OUTPUT_DIR/docker-compose.services.yml" << EOF +# =================================================================== +# Docker Compose - Application Services +# Generated from docker/versions.toml +# Environment: $environment +# Generated: $(date -u +'%Y-%m-%d %H:%M:%S UTC') +# =================================================================== + +services: +$(generate_service_definition "ping-service" "services" $environment) + +$(generate_service_definition "api-gateway" "infrastructure" $environment) + +# =================================================================== +# Networks (shared network from main compose file) +# =================================================================== +networks: + meldestelle-network: + driver: bridge +EOF + + print_success "Generated docker-compose.services.yml" +} + +# Function to generate clients compose file +generate_clients_compose() { + local environment=${1:-development} + + print_info "Generating docker-compose.clients.yml..." + + cat > "$OUTPUT_DIR/docker-compose.clients.yml" << EOF +# =================================================================== +# Docker Compose - Client Applications +# Generated from docker/versions.toml +# Environment: $environment +# Generated: $(date -u +'%Y-%m-%d %H:%M:%S UTC') +# =================================================================== + +services: + # =================================================================== + # Web Application (Compose for Web) + # =================================================================== + web-app: + build: + context: . + dockerfile: dockerfiles/clients/web-app/Dockerfile +$(generate_build_args_section "clients") + # Application-specific arguments + CLIENT_PATH: client + CLIENT_MODULE: client + CLIENT_NAME: meldestelle-web-app + container_name: meldestelle-web-app + environment: + NODE_ENV: \${NODE_ENV:-$(get_env_config $environment "spring-profiles")} + API_BASE_URL: http://api-gateway:\${GATEWAY_PORT:-$(get_port "api-gateway")} + WS_URL: ws://api-gateway:\${GATEWAY_PORT:-$(get_port "api-gateway")}/ws + APP_TITLE: \${APP_NAME:-Meldestelle} + APP_VERSION: \${APP_VERSION:-$(get_version "app-version")} + ports: + - "$(get_port "web-app"):$(get_port "web-app")" + networks: + - meldestelle-network + healthcheck: + test: ["CMD", "curl", "--fail", "http://localhost:$(get_port "web-app")/health"] + interval: $(get_env_config $environment "health-check-interval") + timeout: $(get_env_config $environment "health-check-timeout") + retries: $(get_env_config $environment "health-check-retries") + start_period: $(get_env_config $environment "health-check-start-period") + restart: unless-stopped + +# =================================================================== +# Networks (shared network from main compose file) +# =================================================================== +networks: + meldestelle-network: + driver: bridge +EOF + + print_success "Generated docker-compose.clients.yml" +} + +# Function to show help +show_help() { + echo "Docker Compose Template Generator" + echo "" + echo "Usage: $0 [COMMAND] [ENVIRONMENT]" + echo "" + echo "Commands:" + echo " all Generate all compose files" + echo " infrastructure Generate docker-compose.yml (infrastructure)" + echo " services Generate docker-compose.services.yml" + echo " clients Generate docker-compose.clients.yml" + echo "" + echo "Environments:" + echo " development Development environment (default)" + echo " production Production environment" + echo " testing Testing environment" + echo "" + echo "Examples:" + echo " $0 all # Generate all files for development" + echo " $0 all production # Generate all files for production" + echo " $0 infrastructure development # Generate infrastructure compose for dev" + echo " $0 services production # Generate services compose for prod" +} + +# Main execution +main() { + # Check if versions.toml exists + if [[ ! -f "$VERSIONS_TOML" ]]; then + print_error "Versions file not found: $VERSIONS_TOML" + exit 1 + fi + + local command=${1:-all} + local environment=${2:-development} + + # Validate environment + if [[ ! "$environment" =~ ^(development|production|testing)$ ]]; then + print_error "Invalid environment: $environment" + print_error "Valid environments: development, production, testing" + exit 1 + fi + + print_info "Generating Docker Compose files for environment: $environment" + + case $command in + "all") + generate_infrastructure_compose $environment + generate_services_compose $environment + generate_clients_compose $environment + print_success "All compose files generated successfully!" + ;; + "infrastructure") + generate_infrastructure_compose $environment + ;; + "services") + generate_services_compose $environment + ;; + "clients") + generate_clients_compose $environment + ;; + "-h"|"--help"|"help") + show_help + ;; + *) + print_error "Unknown command: $command" + show_help + exit 1 + ;; + esac +} + +# Run main function with all arguments +main "$@" diff --git a/scripts/validate-docker-consistency.sh b/scripts/validate-docker-consistency.sh new file mode 100755 index 00000000..9d3d87b2 --- /dev/null +++ b/scripts/validate-docker-consistency.sh @@ -0,0 +1,433 @@ +#!/bin/bash +# =================================================================== +# Docker Consistency Validator +# Validates Dockerfiles and docker-compose files against docker/versions.toml +# =================================================================== + +set -e + +# Script directory and project root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +DOCKER_DIR="$PROJECT_ROOT/docker" +VERSIONS_TOML="$DOCKER_DIR/versions.toml" +DOCKERFILES_DIR="$PROJECT_ROOT/dockerfiles" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Counters +ERRORS=0 +WARNINGS=0 +CHECKS_PASSED=0 + +# Function to print colored output +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" + ((CHECKS_PASSED++)) +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" + ((WARNINGS++)) +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" + ((ERRORS++)) +} + +# Function to extract version from TOML file +get_version() { + local key=$1 + grep "^$key = " "$VERSIONS_TOML" | sed 's/.*= "\(.*\)"/\1/' || echo "" +} + +# Function to get valid ARG names from TOML +get_valid_args() { + # Extract all version keys from [versions] section + awk '/^\[versions\]/,/^\[/ {if (/^[a-zA-Z].*= /) print $1}' "$VERSIONS_TOML" | grep -v "^\[" || true + + # Extract all build-args from [build-args] section + awk '/^\[build-args\]/,/^\[/ { + if (/^[a-zA-Z].*= \[/) { + in_array = 1 + line = $0 + gsub(/.*= \[/, "", line) + } + if (in_array) { + gsub(/[\[\]",]/, " ", line) + split(line, args, " ") + for (i in args) { + if (args[i] != "" && args[i] != "]") { + print args[i] + } + } + if (/\]/) in_array = 0 + } + }' "$VERSIONS_TOML" || true + + # Extract service ports + awk '/^\[service-ports\]/,/^\[/ {if (/^[a-zA-Z].*= /) print $1}' "$VERSIONS_TOML" | grep -v "^\[" || true +} + +# Function to get environment variable mappings from TOML +get_env_mappings() { + awk '/^\[environment-mapping\]/,/^\[/ { + if (/^[a-zA-Z].*= /) { + key = $1 + value = $3 + gsub(/"/, "", value) + print key ":" value + } + }' "$VERSIONS_TOML" || true +} + +# Function to validate Dockerfile ARGs +validate_dockerfile_args() { + local dockerfile=$1 + local relative_path=${dockerfile#$PROJECT_ROOT/} + + print_info "Validating Dockerfile: $relative_path" + + if [[ ! -f "$dockerfile" ]]; then + print_error "Dockerfile not found: $relative_path" + return + fi + + # Get all ARG declarations from Dockerfile + local dockerfile_args=$(grep "^ARG " "$dockerfile" | sed 's/^ARG //' | sed 's/=.*//' | sort -u) + + # Get valid ARG names from TOML + local valid_args=$(get_valid_args | sort -u) + + local has_errors=false + local has_centralized_args=false + + # Check each ARG in Dockerfile + while IFS= read -r arg; do + [[ -z "$arg" ]] && continue + + # Skip empty lines + if [[ -z "$arg" ]]; then + continue + fi + + # Check if ARG is defined in versions.toml or is a standard Docker ARG + case "$arg" in + # Standard Docker build args + BUILDPLATFORM|TARGETPLATFORM|BUILDOS|TARGETOS|BUILDARCH|TARGETARCH) + print_success " ✓ Standard Docker ARG: $arg" + has_centralized_args=true + ;; + # Application-specific args that should be centralized + GRADLE_VERSION|JAVA_VERSION|NODE_VERSION|NGINX_VERSION|BUILD_DATE|VERSION|SPRING_PROFILES_ACTIVE|SERVICE_PATH|SERVICE_NAME|SERVICE_PORT|CLIENT_PATH|CLIENT_MODULE|CLIENT_NAME) + if echo "$valid_args" | grep -q "^$arg$"; then + print_success " ✓ Centralized ARG: $arg" + has_centralized_args=true + else + print_warning " ⚠ ARG $arg should be defined in versions.toml" + fi + ;; + # Runtime configuration args (acceptable) + APP_USER|APP_GROUP|APP_UID|APP_GID) + print_success " ✓ Runtime configuration ARG: $arg" + ;; + *) + # Check if it's a version-related ARG that should be centralized + if [[ "$arg" =~ _(VERSION|PORT)$ ]] || [[ "$arg" =~ ^(DOCKER_|SERVICE_|CLIENT_) ]]; then + print_warning " ⚠ ARG $arg might need to be centralized in versions.toml" + else + print_success " ✓ Custom ARG: $arg" + fi + ;; + esac + done <<< "$dockerfile_args" + + # Check if Dockerfile uses centralized version management + if [[ "$has_centralized_args" == true ]]; then + print_success " ✓ Dockerfile uses centralized version management" + else + print_warning " ⚠ Dockerfile should use centralized ARGs from versions.toml" + fi + + # Check for hardcoded versions + local hardcoded_versions=$(grep -E "ARG.*=.*(alpine|[0-9]+\.[0-9]+)" "$dockerfile" | grep -v "APP_" || true) + if [[ -n "$hardcoded_versions" ]]; then + print_error " ❌ Hardcoded versions found (should use versions.toml):" + echo "$hardcoded_versions" | while read -r line; do + print_error " $line" + done + else + print_success " ✓ No hardcoded versions found" + fi +} + +# Function to validate docker-compose version references +validate_compose_versions() { + local compose_file=$1 + local relative_path=${compose_file#$PROJECT_ROOT/} + + print_info "Validating Docker Compose file: $relative_path" + + if [[ ! -f "$compose_file" ]]; then + print_error "Compose file not found: $relative_path" + return + fi + + # Get environment variable mappings + local env_mappings=$(get_env_mappings) + + # Check for version references in compose file + local version_refs=$(grep -o '\${DOCKER_[^}]*}' "$compose_file" | sort -u || true) + + if [[ -z "$version_refs" ]]; then + print_warning " ⚠ No centralized version references found" + return + fi + + # Validate each version reference + while IFS= read -r ref; do + [[ -z "$ref" ]] && continue + + local var_name=${ref#\$\{} + var_name=${var_name%\}} + + # Check if mapping exists in TOML + local mapping_found=false + while IFS=':' read -r toml_key env_var; do + if [[ "$env_var" == "$var_name" ]]; then + mapping_found=true + local toml_version=$(get_version "$toml_key") + if [[ -n "$toml_version" ]]; then + print_success " ✓ Version reference $ref maps to $toml_key = $toml_version" + else + print_error " ❌ TOML key $toml_key has no value" + fi + break + fi + done <<< "$env_mappings" + + if [[ "$mapping_found" == false ]]; then + print_warning " ⚠ Version reference $ref has no mapping in environment-mapping section" + fi + done <<< "$version_refs" + + # Check for hardcoded image versions + local hardcoded_images=$(grep -E "image:.*:[0-9]" "$compose_file" | grep -v "\${" || true) + if [[ -n "$hardcoded_images" ]]; then + print_error " ❌ Hardcoded image versions found:" + echo "$hardcoded_images" | while read -r line; do + print_error " $line" + done + else + print_success " ✓ No hardcoded image versions found" + fi +} + +# Function to validate port consistency +validate_port_consistency() { + print_info "Validating port consistency..." + + # Get ports from TOML + local toml_ports=$(awk '/^\[service-ports\]/,/^\[/ { + if (/^[a-zA-Z].*= [0-9]/) { + service = $1 + port = $3 + print service ":" port + } + }' "$VERSIONS_TOML") + + # Check docker-compose files for port consistency + local compose_files=("docker-compose.yml" "docker-compose.services.yml" "docker-compose.clients.yml") + + for compose_file in "${compose_files[@]}"; do + local full_path="$PROJECT_ROOT/$compose_file" + if [[ -f "$full_path" ]]; then + # Extract port mappings from compose file + local compose_ports=$(grep -E "- \".*:[0-9]+\"" "$full_path" | sed 's/.*- "\([^"]*\)".*/\1/' || true) + + # Compare with TOML ports + while IFS=':' read -r service expected_port; do + [[ -z "$service" ]] && continue + + # Convert service name for grep (handle different naming conventions) + local service_pattern="$service" + case "$service" in + "api-gateway") service_pattern="api-gateway" ;; + "ping-service") service_pattern="ping-service" ;; + *) ;; + esac + + # Check if service exists in compose file and port matches + if grep -q "$service_pattern" "$full_path"; then + local found_port=$(echo "$compose_ports" | grep ":$expected_port" | head -1 || true) + if [[ -n "$found_port" ]]; then + print_success " ✓ Port consistency for $service: $expected_port" + else + print_warning " ⚠ Port mismatch for $service (expected: $expected_port)" + fi + fi + done <<< "$toml_ports" + fi + done +} + +# Function to validate build args environment files +validate_build_args_files() { + print_info "Validating build-args environment files..." + + local build_args_files=("global.env" "services.env" "infrastructure.env" "clients.env") + + for env_file in "${build_args_files[@]}"; do + local full_path="$DOCKER_DIR/build-args/$env_file" + + if [[ -f "$full_path" ]]; then + print_success " ✓ Build args file exists: $env_file" + + # Check if file is not empty + if [[ -s "$full_path" ]]; then + print_success " ✓ Build args file is not empty: $env_file" + else + print_warning " ⚠ Build args file is empty: $env_file" + fi + + # Check for DOCKER_ environment variables + local docker_vars=$(grep "^DOCKER_" "$full_path" | wc -l || echo "0") + if [[ "$docker_vars" -gt 0 ]]; then + print_success " ✓ Found $docker_vars centralized version variables in $env_file" + else + print_warning " ⚠ No DOCKER_ version variables found in $env_file" + fi + else + print_error " ❌ Build args file missing: $env_file" + fi + done +} + +# Function to show validation summary +show_summary() { + echo "" + echo "===============================================" + echo "Docker Consistency Validation Summary" + echo "===============================================" + echo -e "${GREEN}Checks Passed: $CHECKS_PASSED${NC}" + echo -e "${YELLOW}Warnings: $WARNINGS${NC}" + echo -e "${RED}Errors: $ERRORS${NC}" + echo "===============================================" + + if [[ $ERRORS -eq 0 ]]; then + if [[ $WARNINGS -eq 0 ]]; then + print_success "All consistency checks passed! ✨" + return 0 + else + print_warning "Validation completed with warnings. Consider addressing them for optimal consistency." + return 0 + fi + else + print_error "Validation failed with $ERRORS errors. Please fix them before proceeding." + return 1 + fi +} + +# Function to show help +show_help() { + echo "Docker Consistency Validator" + echo "" + echo "Usage: $0 [COMMAND]" + echo "" + echo "Commands:" + echo " all Run all validation checks (default)" + echo " dockerfiles Validate Dockerfile ARG declarations" + echo " compose Validate docker-compose version references" + echo " ports Validate port consistency" + echo " build-args Validate build-args environment files" + echo "" + echo "Examples:" + echo " $0 # Run all validations" + echo " $0 dockerfiles # Validate only Dockerfiles" + echo " $0 compose # Validate only compose files" + echo " $0 ports # Validate only port consistency" +} + +# Main execution +main() { + # Check if versions.toml exists + if [[ ! -f "$VERSIONS_TOML" ]]; then + print_error "Versions file not found: $VERSIONS_TOML" + exit 1 + fi + + local command=${1:-all} + + print_info "Docker Consistency Validation - Starting..." + print_info "Versions file: $VERSIONS_TOML" + echo "" + + case $command in + "all") + # Validate Dockerfiles + find "$DOCKERFILES_DIR" -name "Dockerfile" -type f | while read -r dockerfile; do + validate_dockerfile_args "$dockerfile" + echo "" + done + + # Validate docker-compose files + for compose_file in docker-compose*.yml; do + if [[ -f "$PROJECT_ROOT/$compose_file" ]]; then + validate_compose_versions "$PROJECT_ROOT/$compose_file" + echo "" + fi + done + + # Validate port consistency + validate_port_consistency + echo "" + + # Validate build args files + validate_build_args_files + ;; + "dockerfiles") + find "$DOCKERFILES_DIR" -name "Dockerfile" -type f | while read -r dockerfile; do + validate_dockerfile_args "$dockerfile" + echo "" + done + ;; + "compose") + for compose_file in docker-compose*.yml; do + if [[ -f "$PROJECT_ROOT/$compose_file" ]]; then + validate_compose_versions "$PROJECT_ROOT/$compose_file" + echo "" + fi + done + ;; + "ports") + validate_port_consistency + ;; + "build-args") + validate_build_args_files + ;; + "-h"|"--help"|"help") + show_help + exit 0 + ;; + *) + print_error "Unknown command: $command" + show_help + exit 1 + ;; + esac + + show_summary +} + +# Run main function with all arguments +main "$@"