refactoring Single Source of Truth
This commit is contained in:
@@ -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.
|
||||
@@ -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
|
||||
<!-- .idea/docker.xml -->
|
||||
<project version="4">
|
||||
<component name="DockerConfiguration">
|
||||
<option name="composeFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/docker-compose.yml" />
|
||||
<option value="$PROJECT_DIR$/docker-compose.services.yml" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="buildKitEnabled" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
```
|
||||
|
||||
### ⚡ 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 |
|
||||
|
||||
@@ -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<MemberId, ValidationError> =
|
||||
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<Member?, RepositoryError>
|
||||
suspend fun save(member: Member): Result<Unit, RepositoryError>
|
||||
}
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
+28
-2
@@ -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
|
||||
@@ -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<MemberResponse> {
|
||||
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<Member, BusinessError> {
|
||||
// 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<Member, ValidationError> {
|
||||
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<Unit, RepositoryError> {
|
||||
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<Member?, RepositoryError> {
|
||||
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<Member?, RepositoryError>
|
||||
suspend fun save(member: Member): Result<Unit, RepositoryError>
|
||||
suspend fun findByEmail(email: Email): Result<Member?, RepositoryError>
|
||||
suspend fun findByLicenseNumber(licenseNumber: LicenseNumber): Result<Member?, RepositoryError>
|
||||
suspend fun findAll(pageable: Pageable): Result<Page<Member>, 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<MemberListUiState> = _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<Member> = 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<TournamentRegistration> = mutableListOf()
|
||||
) {
|
||||
companion object {
|
||||
fun create(
|
||||
name: String,
|
||||
startDate: LocalDate,
|
||||
endDate: LocalDate,
|
||||
maxParticipants: Int
|
||||
): Result<Tournament, ValidationError> {
|
||||
// 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<TournamentRegistrationCreatedEvent, BusinessError> {
|
||||
// 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<MemberResponse>
|
||||
```
|
||||
|
||||
## 🚀 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
|
||||
@@ -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<MemberId, ValidationError> =
|
||||
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<EntityId, ValidationError> =
|
||||
runCatching { UUID.fromString(value) }
|
||||
.map { EntityId(it) }
|
||||
.mapError { ValidationError.INVALID_UUID }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Error-Handling mit Result
|
||||
```kotlin
|
||||
interface EntityRepository {
|
||||
suspend fun findById(id: EntityId): Result<Entity?, RepositoryError>
|
||||
suspend fun save(entity: Entity): Result<Unit, RepositoryError>
|
||||
}
|
||||
|
||||
// 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<Unit, ProcessingError> {
|
||||
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
|
||||
@@ -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<Boolean, ValidationError> {
|
||||
// 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<T>(
|
||||
private val redisClient: RedisClient,
|
||||
private val ttl: Duration = Duration.ofHours(1)
|
||||
) : Cache<T> {
|
||||
|
||||
override suspend fun get(key: String): T? {
|
||||
// Use Redis GET command with automatic deserialization
|
||||
return redisClient.get(key)?.let {
|
||||
jsonMapper.readValue(it, typeRef<T>())
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 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
|
||||
@@ -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<MemberRepository>()
|
||||
private val eventPublisher = mockk<EventPublisher>()
|
||||
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<Result.Success<Unit>>()
|
||||
verify { memberRepository.save(any()) }
|
||||
verify { eventPublisher.publish(ofType<MemberCreatedEvent>()) }
|
||||
}
|
||||
|
||||
@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<Result.Failure<RepositoryError>>()
|
||||
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<Result.Success<Unit>>()
|
||||
assertThat(findResult).isInstanceOf<Result.Success<Member?>>()
|
||||
|
||||
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<Nothing>("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<Result.Success<Unit>>()
|
||||
assertThat(retrieveResult).isInstanceOf<Result.Success<List<DomainEvent>>>()
|
||||
|
||||
val events = (retrieveResult as Result.Success).value
|
||||
assertThat(events).hasSize(1)
|
||||
assertThat(events.first()).isInstanceOf<MemberCreatedEvent>()
|
||||
|
||||
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<Nothing>("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<Result.Success<ExpectedType>>()
|
||||
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<Result.Failure<ExpectedError>>()
|
||||
assertThat((result as Result.Failure).error).isEqualTo(ExpectedError.SOME_ERROR)
|
||||
}
|
||||
```
|
||||
|
||||
### Mock-Setup für Services
|
||||
|
||||
```kotlin
|
||||
class ServiceTest {
|
||||
private val repository = mockk<Repository>()
|
||||
private val eventPublisher = mockk<EventPublisher>()
|
||||
private val externalService = mockk<ExternalService>()
|
||||
|
||||
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
|
||||
@@ -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 <service-name>
|
||||
|
||||
# Versionen aktualisieren
|
||||
./scripts/docker-versions-update.sh show
|
||||
./scripts/docker-versions-update.sh update <component> <version>
|
||||
|
||||
# Services neu starten
|
||||
docker-compose restart <service-name>
|
||||
```
|
||||
|
||||
### 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
|
||||
@@ -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 <service> 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 <service> sh` | Shell im Container |
|
||||
| Logs verfolgen | `docker-compose logs -f <service>` | Live-Logs anzeigen |
|
||||
| Service neu bauen | `make service-build SERVICE=<name>` | Einzelnen Service rebuilden |
|
||||
| Health-Check | `curl localhost:<port>/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 <service-name>
|
||||
|
||||
# Container neu starten
|
||||
docker-compose restart <service-name>
|
||||
|
||||
# Image neu bauen
|
||||
docker-compose build --no-cache <service-name>
|
||||
```
|
||||
|
||||
#### Port-Konflikte
|
||||
```bash
|
||||
# Ports prüfen
|
||||
netstat -tulpn | grep :<port>
|
||||
|
||||
# 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 <service> 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
|
||||
@@ -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:<port>/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 <service-name>
|
||||
|
||||
# Error-Logs filtern
|
||||
docker-compose logs <service-name> | 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 <token>" \
|
||||
http://localhost:3000/api/dashboards/uid/<dashboard-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
|
||||
@@ -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.
|
||||
@@ -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 <image>` | 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
|
||||
@@ -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>` | Port-Nutzung prüfen |
|
||||
| Service startet nicht | `docker-compose logs <service>` | Service-Logs anzeigen |
|
||||
| Container hängt | `docker stats` | Ressourcenverbrauch |
|
||||
| DNS-Probleme | `docker-compose exec <service> nslookup <target>` | 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 <service>` - Logs analysieren
|
||||
3. `docker-compose exec <service> 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 <service> ping <target>` - 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 <component> <version>`
|
||||
> - **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
|
||||
+23
-2
@@ -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
|
||||
|
||||
Vendored
+126
@@ -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"
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -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}
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
Executable
+504
@@ -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 "$@"
|
||||
Executable
+433
@@ -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 "$@"
|
||||
Reference in New Issue
Block a user