chore(ci): Align GH Workflows with Docker SSoT, new paths; minimal SSoT guard; staticAnalysis (#23)

* chore(MP-21): snapshot pre-refactor state (Epic 1)

* chore(MP-22): scaffold new repo structure, relocate Docker Compose, move frontend/backend modules, update Makefile; add docs mapping and env template

* MP-22 Epic 2: Erfolgreich umgesetzt und verifiziert

* MP-23 Epic 3: Gradle/Build Governance zentralisieren

* MP-23 Epic 3: Gradle/Build Governance zentralisieren

* chore(devops)!: Docker-SSoT (.env) konsolidiert, Compose-Mounts ergänzt, Makefile entfernt

- ENV Single Source of Truth
  - docker/.env.example neu (inkl. REDIS_PASSWORD, Ports, Build-Overrides)
  - config/.env(.example) als DEPRECATED markiert (Verweis auf docker/.env[.example])

- Docker Compose vereinheitlicht (docker/docker-compose.yaml)
  - Postgres: zentralen postgresql.conf mounten (../config/postgres/postgresql.conf)
    und Start mit -c config_file=/etc/postgresql/postgresql.conf
  - Redis: zentralen redis.conf mounten (../config/redis/redis.conf)
    und Start via "redis-server … ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}"
  - Web-Nginx: ../config/nginx/nginx.prod.conf → /etc/nginx/nginx.conf (ro)
  - Monitoring: Prometheus/Grafana nutzen ../config/monitoring/* als SSoT

- Frontend/DI/Network (MP-23 Grundlage)
  - :frontend:core:network Modul mit Koin `apiClient` (Ktor + JSON/Retry/Timeout/Logging)
  - Plattform-Basis-URL-Auflösung (JVM: ENV API_BASE_URL; JS: globalThis.API_BASE_URL / Same-Origin)
  - Web index.html setzt API_BASE_URL (Query `?apiBaseUrl=…` > Same-Origin > Fallback)

- Build/Gradle & Module-Refs
  - settings.gradle.kts: neue Frontend-/Backend-Pfade bereits inkludiert
  - Features/Shell: Abhängigkeiten auf :frontend:shared / :frontend:core:* angepasst
  - Ping-API-Refs auf :backend:services:ping:ping-api vereinheitlicht

- Dockerfiles angepasst
  - backend/infrastructure/gateway/Dockerfile → Tasks/Pfade auf :backend:gateway
  - backend/services/ping/Dockerfile → Tasks/Pfade auf :backend:services:ping:ping-service

- Static Analysis / Guards
  - config/detekt/detekt.yml hinzugefügt
  - Leichter Arch-Guard (Frontend) gegen manuelle Authorization-Header vorbereitet

- Doku
  - docs/ARCHITECTURE.md (Struktur, Mapping, Next Steps) ergänzt
  - docs/adr/README.md angelegt

BREAKING CHANGES:
- Makefile komplett entfernt (bitte direkt `docker compose` verwenden)
- ENV-Quelle ist jetzt docker/.env (statt config/.env oder Root)
- Compose-Datei unter docker/docker-compose.yaml (nicht mehr compose.yaml im Repo-Root)

Verifikation (lokal):
- ENV anlegen: `cp docker/.env.example docker/.env` (Werte anpassen)
- Compose prüfen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml config`
- Infrastruktur: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle up -d postgres redis keycloak web-app`
- Services bauen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle build api-gateway ping-service --no-cache --progress=plain`

Refs: MP-22 (Epic 2), MP-23 (Epic 3)

* chore(devops)!: Docker-SSoT (.env) konsolidiert, Compose-Mounts ergänzt, Makefile entfernt

- ENV Single Source of Truth
  - docker/.env.example neu (inkl. REDIS_PASSWORD, Ports, Build-Overrides)
  - config/.env(.example) als DEPRECATED markiert (Verweis auf docker/.env[.example])

- Docker Compose vereinheitlicht (docker/docker-compose.yaml)
  - Postgres: zentralen postgresql.conf mounten (../config/postgres/postgresql.conf)
    und Start mit -c config_file=/etc/postgresql/postgresql.conf
  - Redis: zentralen redis.conf mounten (../config/redis/redis.conf)
    und Start via "redis-server … ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}"
  - Web-Nginx: ../config/nginx/nginx.prod.conf → /etc/nginx/nginx.conf (ro)
  - Monitoring: Prometheus/Grafana nutzen ../config/monitoring/* als SSoT

- Frontend/DI/Network (MP-23 Grundlage)
  - :frontend:core:network Modul mit Koin `apiClient` (Ktor + JSON/Retry/Timeout/Logging)
  - Plattform-Basis-URL-Auflösung (JVM: ENV API_BASE_URL; JS: globalThis.API_BASE_URL / Same-Origin)
  - Web index.html setzt API_BASE_URL (Query `?apiBaseUrl=…` > Same-Origin > Fallback)

- Build/Gradle & Module-Refs
  - settings.gradle.kts: neue Frontend-/Backend-Pfade bereits inkludiert
  - Features/Shell: Abhängigkeiten auf :frontend:shared / :frontend:core:* angepasst
  - Ping-API-Refs auf :backend:services:ping:ping-api vereinheitlicht

- Dockerfiles angepasst
  - backend/infrastructure/gateway/Dockerfile → Tasks/Pfade auf :backend:gateway
  - backend/services/ping/Dockerfile → Tasks/Pfade auf :backend:services:ping:ping-service

- Static Analysis / Guards
  - config/detekt/detekt.yml hinzugefügt
  - Leichter Arch-Guard (Frontend) gegen manuelle Authorization-Header vorbereitet

- Doku
  - docs/ARCHITECTURE.md (Struktur, Mapping, Next Steps) ergänzt
  - docs/adr/README.md angelegt

BREAKING CHANGES:
- Makefile komplett entfernt (bitte direkt `docker compose` verwenden)
- ENV-Quelle ist jetzt docker/.env (statt config/.env oder Root)
- Compose-Datei unter docker/docker-compose.yaml (nicht mehr compose.yaml im Repo-Root)

Verifikation (lokal):
- ENV anlegen: `cp docker/.env.example docker/.env` (Werte anpassen)
- Compose prüfen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml config`
- Infrastruktur: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle up -d postgres redis keycloak web-app`
- Services bauen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle build api-gateway ping-service --no-cache --progress=plain`

Refs: MP-22 (Epic 2), MP-23 (Epic 3)

* chore(devops)!: Docker-SSoT (.env) konsolidiert, Compose-Mounts ergänzt, Makefile entfernt

- ENV Single Source of Truth
  - docker/.env.example neu (inkl. REDIS_PASSWORD, Ports, Build-Overrides)
  - config/.env(.example) als DEPRECATED markiert (Verweis auf docker/.env[.example])

- Docker Compose vereinheitlicht (docker/docker-compose.yaml)
  - Postgres: zentralen postgresql.conf mounten (../config/postgres/postgresql.conf)
    und Start mit -c config_file=/etc/postgresql/postgresql.conf
  - Redis: zentralen redis.conf mounten (../config/redis/redis.conf)
    und Start via "redis-server … ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}"
  - Web-Nginx: ../config/nginx/nginx.prod.conf → /etc/nginx/nginx.conf (ro)
  - Monitoring: Prometheus/Grafana nutzen ../config/monitoring/* als SSoT

- Frontend/DI/Network (MP-23 Grundlage)
  - :frontend:core:network Modul mit Koin `apiClient` (Ktor + JSON/Retry/Timeout/Logging)
  - Plattform-Basis-URL-Auflösung (JVM: ENV API_BASE_URL; JS: globalThis.API_BASE_URL / Same-Origin)
  - Web index.html setzt API_BASE_URL (Query `?apiBaseUrl=…` > Same-Origin > Fallback)

- Build/Gradle & Module-Refs
  - settings.gradle.kts: neue Frontend-/Backend-Pfade bereits inkludiert
  - Features/Shell: Abhängigkeiten auf :frontend:shared / :frontend:core:* angepasst
  - Ping-API-Refs auf :backend:services:ping:ping-api vereinheitlicht

- Dockerfiles angepasst
  - backend/infrastructure/gateway/Dockerfile → Tasks/Pfade auf :backend:gateway
  - backend/services/ping/Dockerfile → Tasks/Pfade auf :backend:services:ping:ping-service

- Static Analysis / Guards
  - config/detekt/detekt.yml hinzugefügt
  - Leichter Arch-Guard (Frontend) gegen manuelle Authorization-Header vorbereitet

- Doku
  - docs/ARCHITECTURE.md (Struktur, Mapping, Next Steps) ergänzt
  - docs/adr/README.md angelegt

BREAKING CHANGES:
- Makefile komplett entfernt (bitte direkt `docker compose` verwenden)
- ENV-Quelle ist jetzt docker/.env (statt config/.env oder Root)
- Compose-Datei unter docker/docker-compose.yaml (nicht mehr compose.yaml im Repo-Root)

Verifikation (lokal):
- ENV anlegen: `cp docker/.env.example docker/.env` (Werte anpassen)
- Compose prüfen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml config`
- Infrastruktur: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle up -d postgres redis keycloak web-app`
- Services bauen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle build api-gateway ping-service --no-cache --progress=plain`

Refs: MP-22 (Epic 2), MP-23 (Epic 3)

* chore(ci): Workflows an Docker-SSoT & neue Struktur angepasst, minimaler SSoT-Guard

- ssot-guard.yml: Option B (minimal) → `docker compose -f docker/docker-compose.yaml config` als Lint
- integration-tests.yml: `./gradlew staticAnalysis` vor Integrationstests
- docs-kdoc-sync.yml: Dokka-Task Fallback (dokkaGfmAll || dokkaGfm), YouTrack-Sync nur wenn Script vorhanden
- deploy-proxmox.yml: Compose-Pfade auf docker/docker-compose.yaml + `--env-file docker/.env`; Build/Test Schritte vereinheitlicht
- ci-main.yml: SSoT-Skripte per `if: hashFiles(...)` guarded, Compose-Lint Fallback; OpenAPI‑Pfad → backend/gateway; ADR‑Pfade → docs/adr/**; `staticAnalysis` in Build integriert
- youtrack-sync.yml: unverändert (funktional)

Refs: MP-22, MP-23

* chore(ci): Workflows an Docker-SSoT & neue Struktur angepasst, minimaler SSoT-Guard

- ssot-guard.yml: Option B (minimal) → `docker compose -f docker/docker-compose.yaml config` als Lint
- integration-tests.yml: `./gradlew staticAnalysis` vor Integrationstests
- docs-kdoc-sync.yml: Dokka-Task Fallback (dokkaGfmAll || dokkaGfm), YouTrack-Sync nur wenn Script vorhanden
- deploy-proxmox.yml: Compose-Pfade auf docker/docker-compose.yaml + `--env-file docker/.env`; Build/Test Schritte vereinheitlicht
- ci-main.yml: SSoT-Skripte per `if: hashFiles(...)` guarded, Compose-Lint Fallback; OpenAPI‑Pfad → backend/gateway; ADR‑Pfade → docs/adr/**; `staticAnalysis` in Build integriert
- youtrack-sync.yml: unverändert (funktional)

Refs: MP-22, MP-23

* fix(ci): create .env from example before validating compose config

* fix(ci): update ssot-guard filename (.yaml) and sync workflow state

* fixing

* fix(webpack): correct sql.js fallback configuration for webpack 5
This commit is contained in:
StefanMo
2025-12-03 12:03:40 +01:00
committed by GitHub
parent 034892e890
commit 95fe3e0573
365 changed files with 2283 additions and 15142 deletions
+1 -1
View File
@@ -70,7 +70,7 @@ Thumbs.db
# ===================================================================
# Environment and Configuration files
# ===================================================================
.env
config/.env
.env.local
.env.*.local
**/.env
-60
View File
@@ -1,60 +0,0 @@
# ====================================================
# Meldestelle - Environment - Template Configuration
# ====================================================
# Profil: DEVELOPMENT (Development)
# --- PROJEKT EINSTELLUNGEN ---
# .env.template - Vorlage für Server/Kollegen
COMPOSE_PROJECT_NAME=meldestelle
# Restart Policy: 'no' für Dev (Fehler sehen), 'always' für Prod
RESTART_POLICY=always
# --- POSTGRESQL (Datenbank) ---
POSTGRES_USER=pg-user
POSTGRES_PASSWORD=
POSTGRES_DB=meldestelle
# Port Mapping: Host:Container.
# Prod: 127.0.0.1:5432 (nur localhost) oder leer lassen
POSTGRES_PORT=5432:5432
# --- REDIS (Cache) ---
# Prod: 127.0.0.1:6379 oder leer lassen
REDIS_PORT=6379:6379
# --- KEYCLOAK (Identity Provider) ---
# Admin Login für die Konsole
KC_ADMIN_USER=kc-admin
KC_ADMIN_PASSWORD=
# Hostname (Wichtig für Redirects)
KC_HOSTNAME=localhost
# Port Mapping
KC_PORT=8180:8080
# --- PGADMIN (DB GUI) ---
PGADMIN_EMAIL=user@domain.com
PGADMIN_PASSWORD=
PGADMIN_PORT=8888:80
# --- GRAFANA (Monitoring GUI) ---
GF_ADMIN_USER=gf-admin
GF_ADMIN_PASSWORD=
GF_PORT=3000:3000
# --- PROMETHEUS (Metriken) ---
PROMETHEUS_PORT=9090:9090
# --- SERVICE DISCOVERY (Consul) ---
CONSUL_PORT=8500:8500
# --- API GATEWAY ---
# Der Port, der nach außen für Clients (Web App) offen ist
GATEWAY_PORT=8081
# Debug Port für IntelliJ (Remote JVM Debug)
GATEWAY_DEBUG_PORT=5005
# --- CLIENT APPLICATIONS ---
# Web-App (Kotlin/JS, kein WASM)
WEB_APP_PORT=4000:4000
# Desktop-App (VNC/noVNC)
DESKTOP_APP_VNC_PORT=5901:5901
DESKTOP_APP_NOVNC_PORT=6080:6080
+16 -10
View File
@@ -21,19 +21,25 @@ jobs:
name: Docker SSoT Validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Validate Docker SSoT (compat mode)
if: ${{ hashFiles('scripts/docker-versions-update.sh') != '' && hashFiles('scripts/generate-compose-files.sh') != '' && hashFiles('scripts/validate-docker-consistency.sh') != '' }}
run: |
bash scripts/docker-versions-update.sh sync
bash scripts/generate-compose-files.sh all development
bash scripts/validate-docker-consistency.sh all
- name: Validate Docker SSoT (envless mode)
if: ${{ hashFiles('scripts/generate-compose-files.sh') != '' && hashFiles('scripts/validate-docker-consistency.sh') != '' }}
run: |
DOCKER_SSOT_MODE=envless bash scripts/generate-compose-files.sh all development
DOCKER_SSOT_MODE=envless bash scripts/validate-docker-consistency.sh all
- name: Lint docker-compose (fallback)
if: ${{ hashFiles('scripts/validate-docker-consistency.sh') == '' }}
run: docker compose -f docker/docker-compose.yaml config
# ========================================
# 2. OpenAPI Validation (nur Lint)
# ========================================
@@ -41,10 +47,10 @@ jobs:
name: Validate OpenAPI Specs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
@@ -53,7 +59,7 @@ jobs:
- name: Validate OpenAPI
run: |
spectral lint infrastructure/gateway/src/main/resources/openapi/documentation.yaml \
spectral lint backend/gateway/src/main/resources/openapi/documentation.yaml \
--ruleset .spectral.yaml \
--fail-severity error
@@ -64,22 +70,22 @@ jobs:
name: Validate Essential Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Lint Critical Markdown
uses: DavidAnson/markdownlint-cli2-action@v20
uses: DavidAnson/markdownlint-cli2-action@v21
with:
globs: |
README.md
docs/README.md
docs/architecture/adr/**/*.md
docs/adr/**/*.md
docs/how-to/start-local.md
- name: Check Links in ADRs
uses: gaurav-nelson/github-action-markdown-link-check@v1
with:
config-file: '.github/markdown-link-check.json'
folder-path: 'docs/architecture/adr/'
folder-path: 'docs/adr/'
use-quiet-mode: 'yes'
# ========================================
@@ -91,7 +97,7 @@ jobs:
needs: [ docker-ssot, validate-openapi, validate-docs ]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Setup JDK 21
uses: actions/setup-java@v5
@@ -101,7 +107,7 @@ jobs:
cache: gradle
- name: Build
run: ./gradlew build -x test
run: ./gradlew staticAnalysis build -x test
- name: Test
run: ./gradlew test
+18 -15
View File
@@ -27,7 +27,7 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Set up JDK 21
uses: actions/setup-java@v5
@@ -48,11 +48,14 @@ jobs:
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build Client (Test Compilation)
run: ./gradlew :client:compileCommonMainKotlinMetadata --no-daemon
- name: Static Analysis
run: ./gradlew staticAnalysis --no-daemon || true
- name: Run Client Tests
run: ./gradlew :client:test --no-daemon || true # Allow failure for now
- name: Build (all)
run: ./gradlew build -x test --no-daemon
- name: Test (all)
run: ./gradlew test --no-daemon || true # Allow failure for now
# ===================================================================
# Deploy to Proxmox (nur bei main branch)
@@ -64,7 +67,7 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Setup SSH Key
uses: webfactory/ssh-agent@v0.8.0
@@ -98,7 +101,7 @@ jobs:
# Stop existing services
echo "🛑 Stopping existing services..."
docker compose -f docker-compose.yml -f docker-compose.services.yml -f docker-compose.clients.yml down || true
docker compose --env-file docker/.env -f docker/docker-compose.yaml down || true
# Clean up old images (optional)
echo "🧹 Cleaning up old images..."
@@ -106,13 +109,11 @@ jobs:
# Build new images
echo "🏗️ Building new images..."
docker compose -f docker-compose.yml build
docker compose -f docker-compose.services.yml build
docker compose -f docker-compose.clients.yml build
docker compose --env-file docker/.env -f docker/docker-compose.yaml build
# Start infrastructure first
echo "🚀 Starting infrastructure..."
docker compose -f docker-compose.yml up -d
docker compose --env-file docker/.env -f docker/docker-compose.yaml up -d
# Wait for infrastructure to be ready
echo "⏳ Waiting for infrastructure..."
@@ -120,7 +121,8 @@ jobs:
# Start services
echo "🚀 Starting services..."
docker compose -f docker-compose.yml -f docker-compose.services.yml up -d
# Start services (already included in main compose file)
docker compose --env-file docker/.env -f docker/docker-compose.yaml up -d
# Wait for services to be ready
echo "⏳ Waiting for services..."
@@ -128,7 +130,8 @@ jobs:
# Start clients
echo "🚀 Starting clients..."
docker compose -f docker-compose.yml -f docker-compose.services.yml -f docker-compose.clients.yml up -d
# Start clients (already included in main compose file)
docker compose --env-file docker/.env -f docker/docker-compose.yaml up -d
# Health check
echo "🏥 Running health checks..."
@@ -136,11 +139,11 @@ jobs:
# Check service status
echo "📊 Service Status:"
docker compose -f docker-compose.yml -f docker-compose.services.yml -f docker-compose.clients.yml ps
docker compose --env-file docker/.env -f docker/docker-compose.yaml ps
# Check logs for errors
echo "📋 Recent logs:"
docker compose -f docker-compose.yml -f docker-compose.services.yml -f docker-compose.clients.yml logs --tail=50
docker compose --env-file docker/.env -f docker/docker-compose.yaml logs --tail=50
echo "✅ Deployment completed successfully!"
ENDSSH
+4 -2
View File
@@ -26,7 +26,7 @@ jobs:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Setup JDK 21
uses: actions/setup-java@v5
@@ -38,7 +38,8 @@ jobs:
uses: gradle/actions/setup-gradle@v5
- name: Build Dokka (GFM)
run: ./gradlew --no-daemon dokkaGfmAll
run: |
./gradlew --no-daemon dokkaGfmAll || ./gradlew --no-daemon dokkaGfm
- name: Python deps for YouTrack sync
run: |
@@ -46,6 +47,7 @@ jobs:
pip install requests pyyaml
- name: Sync KDoc Markdown to YouTrack KB
if: ${{ hashFiles('.junie/scripts/youtrack-sync-kb.py') != '' }}
env:
YT_URL: ${{ secrets.YT_URL }}
YT_TOKEN: ${{ secrets.YT_TOKEN }}
+4 -1
View File
@@ -93,7 +93,7 @@ jobs:
--health-start-period 10s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Set up JDK 21
uses: actions/setup-java@v5
@@ -197,6 +197,9 @@ jobs:
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Static Analysis
run: ./gradlew staticAnalysis --no-daemon
- name: Run integration tests
run: ./gradlew integrationTest --no-daemon --parallel
env:
+9 -209
View File
@@ -1,225 +1,25 @@
name: Docker SSoT Guard
permissions:
contents: read
concurrency:
group: ssot-guard-${{ github.ref }}
cancel-in-progress: true
name: Docker SSoT Guard (Minimal)
on:
push:
branches: [ main ]
paths:
- 'docker/**'
- 'dockerfiles/**'
- 'docker-compose*.yml*'
- 'scripts/**'
- '.github/workflows/ssot-guard.yml'
pull_request:
paths:
- 'docker/**'
- 'dockerfiles/**'
- 'docker-compose*.yml*'
- 'scripts/**'
- '.github/workflows/ssot-guard.yml'
jobs:
ssot-guard:
check-compose-config:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: actions/checkout@v4
- name: Show environment
run: |
bash --version
docker --version || true
compose_ver=$(docker compose version 2>/dev/null || true); echo "docker compose: $compose_ver"
# FIX: .env aus Example erstellen, damit Variablen da sind
- name: Create .env context
run: cp docker/.env.example docker/.env
- name: Sync versions to env files
run: bash scripts/docker-versions-update.sh sync
- name: Generate docker-compose files (all)
run: bash scripts/generate-compose-files.sh all development
- name: Validate Docker SSoT consistency
run: bash scripts/validate-docker-consistency.sh all
- name: Build vs Runtime variable guards
run: |
set -euo pipefail
echo "[Guard] Prüfe, dass keine Laufzeit-Variablen in Build-Args-Dateien vorkommen..."
RUNTIME_KEYS_REGEX='^(GATEWAY_HOST|GATEWAY_PORT|WEB_APP_PORT|NODE_ENV|CONSUL_(HOST|PORT|ENABLED)|DB_(HOST|PORT|NAME|USER|USERNAME|PASSWORD)|POSTGRES_DB|REDIS_PORT|KEYCLOAK_PORT|PING_SERVICE_PORT|MEMBERS_SERVICE_PORT|HORSES_SERVICE_PORT|EVENTS_SERVICE_PORT|MASTERDATA_SERVICE_PORT|AUTH_SERVICE_PORT|MONITORING_SERVER_PORT|PROMETHEUS_PORT|GRAFANA_PORT|JWT_ISSUER|JWT_AUDIENCE)$'
FAIL=0
shopt -s nullglob
for f in docker/build-args/*.env config/build/*.env; do
[ -f "$f" ] || continue
BAD=$(grep -E '^[A-Z0-9_]+=' "$f" | cut -d= -f1 | grep -E "$RUNTIME_KEYS_REGEX" || true)
if [ -n "$BAD" ]; then
echo "Fehler: Laufzeit-Variablen in Build-Args Datei $f gefunden:"; echo "$BAD"; FAIL=1
fi
done
shopt -u nullglob
if [ $FAIL -ne 0 ]; then
echo "Build vs Runtime Trennung verletzt."; exit 1; fi
echo "[Guard] Prüfe, dass keine Build-/Versions-Variablen in Runtime-Env vorkommen..."
BUILD_KEYS_REGEX='^(GRADLE_VERSION|JAVA_VERSION|VERSION|APP_VERSION|[A-Z]+_IMAGE_TAG)$'
shopt -s nullglob
for f in config/env/.env .env.template; do
[ -f "$f" ] || continue
BAD=$(grep -E '^[A-Z0-9_]+=' "$f" | cut -d= -f1 | grep -E "$BUILD_KEYS_REGEX" || true)
if [ -n "$BAD" ]; then
echo "Fehler: Build-/Versions-Variablen in Runtime-Env $f gefunden:"; echo "$BAD"; FAIL=1
fi
done
shopt -u nullglob
if [ $FAIL -ne 0 ]; then
echo "Build-/Runtime-Mischung in Runtime-Env."; exit 1; fi
- name: Check versions.toml vs global.env consistency
run: |
set -euo pipefail
TOML=docker/versions.toml
GLOBAL=docker/build-args/global.env
[ -f "$TOML" ] || { echo "Missing $TOML"; exit 1; }
[ -f "$GLOBAL" ] || { echo "Missing $GLOBAL"; exit 1; }
get_toml_ver(){ awk -F'=' -v key="$1" '/^\[versions\]/{in_vers=1; next} /^\[/{in_vers=0} in_vers && gsub(/^[ \t]+|[ \t]+$/,"",$1) && $1==key {gsub(/[ "\t]/,"",$2); print $2; exit}' "$TOML"; }
mapfile -t checks < <(printf "%s\n" \
"GRADLE_VERSION:versions.gradle" \
"JAVA_VERSION:versions.java" \
"VERSION:versions.app-version" \
"PROMETHEUS_IMAGE_TAG:versions.prometheus" \
"GRAFANA_IMAGE_TAG:versions.grafana" \
"KEYCLOAK_IMAGE_TAG:versions.keycloak" \
"POSTGRES_IMAGE_TAG:versions.postgres" \
"REDIS_IMAGE_TAG:versions.redis" \
"CONSUL_IMAGE_TAG:versions.consul" \
"ZOOKEEPER_IMAGE_TAG:versions.zookeeper" \
"KAFKA_IMAGE_TAG:versions.kafka")
FAIL=0
for entry in "${checks[@]}"; do
var=${entry%%:*}; path=${entry##*:}
key=${path#*.}
case "$var" in
GRADLE_VERSION) expected=$(get_toml_ver gradle) ;;
JAVA_VERSION) expected=$(get_toml_ver java) ;;
VERSION) expected=$(get_toml_ver app-version) ;;
PROMETHEUS_IMAGE_TAG) expected=$(get_toml_ver prometheus) ;;
GRAFANA_IMAGE_TAG) expected=$(get_toml_ver grafana) ;;
KEYCLOAK_IMAGE_TAG) expected=$(get_toml_ver keycloak) ;;
POSTGRES_IMAGE_TAG) expected=$(get_toml_ver postgres) ;;
REDIS_IMAGE_TAG) expected=$(get_toml_ver redis) ;;
CONSUL_IMAGE_TAG) expected=$(get_toml_ver consul) ;;
ZOOKEEPER_IMAGE_TAG) expected=$(get_toml_ver zookeeper) ;;
KAFKA_IMAGE_TAG) expected=$(get_toml_ver kafka) ;;
esac
actual=$(grep -E "^${var}=" "$GLOBAL" | head -n1 | cut -d= -f2-)
if [ -z "$actual" ] || [ "$actual" != "$expected" ]; then
echo "Versions-Drift: $var global.env='$actual' != versions.toml('$expected')"; FAIL=1
fi
done
if [ $FAIL -ne 0 ]; then
echo "Versions SSoT-Drift erkannt."; exit 1; fi
- name: Check drift of generated artifacts (ignore timestamps)
run: |
set -euo pipefail
# Gather modified files after sync+generate
CHANGED=$(git diff --name-only)
if [ -z "$CHANGED" ]; then
echo "No drift detected."
exit 0
fi
echo "Changed files:" $CHANGED
fail=0
for f in $CHANGED; do
# Inspect actual content changes but ignore volatile timestamp/comment lines
# Ignore lines starting with + or - that are exactly the timestamp markers we generate
DIFF_FILTERED=$(git diff --unified=0 -- "$f" \
| awk 'BEGIN{show=0} { \
if ($0 ~ /^\+\+\+|^---|^@@/) { next } \
if ($0 ~ /^[+-]# (Generated:|Last updated:)/) { next } \
if ($0 ~ /^[+-]#\s*Generated from docker\/versions.toml/) { next } \
if ($0 ~ /^[+-]#\s*Environment:/) { next } \
if ($0 ~ /^[+-]#\s*Source:/) { next } \
if ($0 ~ /^[+-]$/) { next } \
if ($0 ~ /^[+-]/) { print $0 } \
}')
if [ -n "$DIFF_FILTERED" ]; then
echo "SSoT drift detected in $f:";
echo "$DIFF_FILTERED";
fail=1;
fi
done
if [ $fail -ne 0 ]; then
echo "\nERROR: Generated artifacts differ from repository (beyond timestamps)."
echo "Run:"
echo " bash scripts/docker-versions-update.sh sync"
echo " bash scripts/generate-compose-files.sh all"
echo "and commit the changes."
exit 1
fi
echo "No SSoT drift (ignoring timestamps)."
ssot-guard-envless:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Show environment
run: |
bash --version
docker --version || true
compose_ver=$(docker compose version 2>/dev/null || true); echo "docker compose: $compose_ver"
- name: Generate docker-compose files (all)
run: bash scripts/generate-compose-files.sh all development
- name: Validate Docker SSoT consistency (envless)
run: DOCKER_SSOT_MODE=envless bash scripts/validate-docker-consistency.sh all
- name: Check drift of generated artifacts (ignore timestamps)
run: |
set -euo pipefail
CHANGED=$(git diff --name-only)
if [ -z "$CHANGED" ]; then
echo "No drift detected."
exit 0
fi
echo "Changed files:" $CHANGED
fail=0
for f in $CHANGED; do
DIFF_FILTERED=$(git diff --unified=0 -- "$f" \
| awk 'BEGIN{show=0} { \
if ($0 ~ /^\+\+\+|^---|^@@/) { next } \
if ($0 ~ /^[+-]# (Generated:|Last updated:)/) { next } \
if ($0 ~ /^[+-]#\s*Generated from docker\/versions.toml/) { next } \
if ($0 ~ /^[+-]#\s*Environment:/) { next } \
if ($0 ~ /^[+-]#\s*Source:/) { next } \
if ($0 ~ /^[+-]$/) { next } \
if ($0 ~ /^[+-]/) { print $0 } \
}')
if [ -n "$DIFF_FILTERED" ]; then
echo "SSoT drift detected in $f:";
echo "$DIFF_FILTERED";
fail=1;
fi
done
if [ $fail -ne 0 ]; then
echo "\nERROR: Generated artifacts differ from repository (beyond timestamps)."
echo "Run:"
echo " DOCKER_SSOT_MODE=envless bash scripts/generate-compose-files.sh all"
echo "and commit the changes."
exit 1
fi
echo "No SSoT drift (ignoring timestamps)."
# FIX: .yaml Extension nutzen (SSoT)
- name: Validate Docker Compose Config
run: docker compose --env-file docker/.env -f docker/docker-compose.yaml config
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
steps:
# WICHTIG: Checkout ist notwendig, damit "git log" funktioniert
- name: Checkout Code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0 # Notwendig, um die Commit-Historie für "git log" zu laden
+1 -1
View File
@@ -23,7 +23,7 @@ logs/
# Kotlin/Java
*.class
.env
config/.env
# Generated diagrams
build/diagrams/
@@ -108,7 +108,7 @@ graph TB
```bash
# Massive Redundanz über 100+ Dateien verteilt:
gradle.properties: services.port.ping=8082
docker-compose.services.yml: SERVER_PORT: ${PING_SERVICE_PORT:-8082}
docker-compose.services.yaml: SERVER_PORT: ${PING_SERVICE_PORT:-8082}
dockerfiles/services/ping: EXPOSE 8082
scripts/test/integration: ping-service:8082
config/monitoring/prometheus: - targets: ['ping-service:8082']
@@ -258,7 +258,7 @@ ping-service = 8092 # Geändert von 8082
# Ergebnis: 38+ Dateien automatisch aktualisiert:
# ✓ gradle.properties: services.port.ping=8092
# ✓ docker-compose.services.yml: SERVER_PORT: ${PING_SERVICE_PORT:-8092}
# ✓ docker-compose.services.yaml: SERVER_PORT: ${PING_SERVICE_PORT:-8092}
# ✓ dockerfiles/services/ping-service/Dockerfile: EXPOSE 8092
# ✓ scripts/test/integration-test.sh: ping-service:8092
# ✓ config/monitoring/prometheus.dev.yml: - targets: ['ping-service:8092']
@@ -355,7 +355,7 @@ future-service = 8099
# Nach Synchronisation automatisch in:
# - gradle.properties
# - docker-compose.yml
# - docker-compose.yaml
# - Monitoring-Konfiguration
# - Test-Scripts
# - Environment-Files
@@ -387,7 +387,7 @@ future-service = 8099
```bash
# ❌ FALSCH - Nie mehr manuelle Port-Änderungen
vim docker-compose.yml # Änderungen gehen verloren!
vim docker-compose.yaml # Änderungen gehen verloren!
# ✅ RICHTIG - Zentrale Änderung + Synchronisation
vim config/central.toml
@@ -914,7 +914,7 @@ test-containers = true
```bash
# Development mit Hot-Reload und Debug
export DOCKER_ENVIRONMENT=development
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d
docker-compose -f docker-compose.yaml -f docker-compose.dev.yml up -d
```
#### Production Environment
@@ -1162,9 +1162,9 @@ jobs:
},
"docker.composeCommand": "docker-compose",
"docker.composeFiles": [
"docker-compose.yml",
"docker-compose.services.yml",
"docker-compose.clients.yml"
"docker-compose.yaml",
"docker-compose.services.yaml",
"docker-compose.clients.yaml"
]
}
```
@@ -1713,20 +1713,20 @@ Unsere Compose-Dateien sind modular organisiert für verschiedene Einsatzszenari
```bash
# Alle Services einschließlich Clients
docker-compose \
-f docker-compose.yml \
-f docker-compose.services.yml \
-f docker-compose.clients.yml \
-f docker-compose.yaml \
-f docker-compose.services.yaml \
-f docker-compose.clients.yaml \
up -d
# Nur Infrastructure für Backend-Entwicklung
docker-compose -f docker-compose.yml up -d postgres redis kafka consul zipkin
docker-compose -f docker-compose.yaml up -d postgres redis kafka consul zipkin
# Mit Debug-Unterstützung für Service-Entwicklung
DEBUG=true SPRING_PROFILES_ACTIVE=docker \
docker-compose -f docker-compose.yml -f docker-compose.services.yml up -d
docker-compose -f docker-compose.yaml -f docker-compose.services.yaml up -d
# Mit Live-Reload für Frontend-Entwicklung
docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d
docker-compose -f docker-compose.yaml -f docker-compose.override.yml up -d
```
#### 🔧 Erweiterte Umgebungskonfiguration
@@ -1734,7 +1734,7 @@ docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d
**Beispiel für Auth-Server Konfiguration:**
```yaml
# Erweiterte Environment-Variablen aus docker-compose.services.yml
# Erweiterte Environment-Variablen aus docker-compose.services.yaml
auth-server:
environment:
# Spring Boot Configuration
@@ -1788,7 +1788,7 @@ auth-server:
# Production - Optimiert und sicher
docker-compose \
-f docker-compose.prod.yml \
-f docker-compose.services.yml \
-f docker-compose.services.yaml \
up -d
# Mit spezifischen Environment-Variablen
@@ -1801,11 +1801,11 @@ docker-compose -f docker-compose.prod.yml up -d
```bash
# Nur notwendige Services für Tests
docker-compose -f docker-compose.yml up -d postgres redis
docker-compose -f docker-compose.yaml up -d postgres redis
./gradlew test
# End-to-End Tests
docker-compose -f docker-compose.yml -f docker-compose.services.yml up -d
docker-compose -f docker-compose.yaml -f docker-compose.services.yaml up -d
./gradlew :client:web-app:jsTest
```
@@ -1909,7 +1909,7 @@ services:
```bash
# Service im Debug-Modus starten
docker-compose -f docker-compose.yml up -d ping-service
docker-compose -f docker-compose.yaml up -d ping-service
docker-compose exec ping-service sh
# Logs in Echtzeit verfolgen
@@ -2080,7 +2080,7 @@ labels:
```bash
# Centralized logging mit ELK Stack (optional)
docker-compose -f docker-compose.yml -f docker-compose.logging.yml up -d
docker-compose -f docker-compose.yaml -f docker-compose.logging.yml up -d
# Log-Parsing für strukturierte Logs
docker-compose logs --follow --tail=100 api-gateway | jq -r '.message'
@@ -53,7 +53,7 @@ make full-logs # Alle Logs in Echtzeit
Befehle für die lokale Entwicklungsumgebung:
```bash
make dev-up # Startet Entwicklungsumgebung (docker-compose.yml)
make dev-up # Startet Entwicklungsumgebung (docker-compose.yaml)
make dev-down # Stoppt Entwicklungsumgebung
make dev-restart # Neustart Entwicklungsumgebung
make dev-logs # Zeigt alle Development-Logs
@@ -634,16 +634,16 @@ Das Projekt verwendet mehrere Compose-Files:
```bash
# Nur Infrastruktur
docker compose -f docker-compose.yml up -d
docker compose -f docker-compose.yaml up -d
# Infrastruktur + Services
docker compose -f docker-compose.yml -f docker-compose.services.yml up -d
docker compose -f docker-compose.yaml -f docker-compose.services.yaml up -d
# Infrastruktur + Clients
docker compose -f docker-compose.yml -f docker-compose.clients.yml up -d
docker compose -f docker-compose.yaml -f docker-compose.clients.yaml up -d
# Alles
docker compose -f docker-compose.yml -f docker-compose.services.yml -f docker-compose.clients.yml up -d
docker compose -f docker-compose.yaml -f docker-compose.services.yaml -f docker-compose.clients.yaml up -d
# ⚠️ Tipp: Verwende stattdessen die Makefile-Befehle!
```
@@ -58,7 +58,7 @@ labels:
```bash
# Centralized logging mit ELK Stack (optional)
docker-compose -f docker-compose.yml -f docker-compose.logging.yml up -d
docker-compose -f docker-compose.yaml -f docker-compose.logging.yml up -d
# Log-Parsing für strukturierte Logs
docker-compose logs --follow --tail=100 api-gateway | jq -r '.message'
@@ -186,7 +186,7 @@ source .env.production
certbot certificates
# 3. Services mit Production-Konfiguration starten
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
docker-compose -f docker-compose.yaml -f docker-compose.prod.yml up -d
# 4. Health-Checks durchführen
curl -f https://api.meldestelle.at/actuator/health
@@ -146,8 +146,8 @@ Das Docker-Setup ist spezifisch für die Web-Entwicklung konfiguriert (wie in `R
```shell script
# Startet die Web-App mit Hot-Reload
docker-compose -f docker-compose.yml \
-f docker-compose.clients.yml up -d web-app
docker-compose -f docker-compose.yaml \
-f docker-compose.clients.yaml up -d web-app
```
Der Dienst ist dann unter dem in der `docker-compose.clients.yml` konfigurierten Port (z.B. Port `3000`) erreichbar.
+6 -5
View File
@@ -1,5 +1,6 @@
# Meldestelle
> Modulares System für Pferdesportveranstaltungen mit Domain-Driven Design
[![CI Pipeline](https://github.com/StefanMoCoAt/meldestelle/workflows/CI%20-%20Main%20Pipeline/badge.svg)](https://github.com/StefanMoCoAt/meldestelle/actions)
@@ -26,7 +27,7 @@ cp -n .env.template config/env/.env 2>/dev/null || true
# DOCKER_SSOT_MODE=envless bash scripts/generate-compose-files.sh all development
# 4) Infrastruktur starten
docker compose -f docker-compose.yml up -d
docker compose -f docker-compose.yaml up -d
# 5) Services starten (Beispiel)
./gradlew :members:members-service:bootRun
@@ -259,10 +260,10 @@ bash scripts/generate-compose-files.sh all development && \
```bash
# Nur Infrastruktur
# Wenn eine handgeschriebene docker-compose.yml existiert:
docker compose -f docker-compose.yml up -d
# Wenn eine handgeschriebene docker-compose.yaml existiert:
docker compose -f docker-compose.yaml up -d
# Falls Compose-Files generiert werden:
docker compose -f docker-compose.services.yml up -d
docker compose -f docker-compose.services.yaml up -d
# Services via Gradle
a) Einzeldienst
@@ -304,7 +305,7 @@ b) Falls unterstützt: alle (oder Aggregator)
#### Nur Infrastruktur (Postgres, Redis, Kafka, Keycloak)
```bash
docker compose -f docker-compose.yml up -d
docker compose -f docker-compose.yaml up -d
```
#### Services über Gradle
-195
View File
@@ -1,195 +0,0 @@
# ===================================================================
# Environment Configuration Template - Meldestelle Project
# ===================================================================
# Copy this file to config/env/.env and customize the values for your environment
# Security Note: Never commit .env files containing production secrets!
# ===================================================================
# ===================================================================
# Runtime Configuration (Single Source for runtime values)
# Hinweis: Build-/Image-Versionen werden ausschließlich in docker/versions.toml
# und docker/build-args/global.env gepflegt. Keine Build-/Versionseinträge hier.
# ===================================================================
# Anwendung
APP_NAME=Meldestelle
# Profile
SPRING_PROFILES_ACTIVE=docker,keycloak
# ===================================================================
# Infrastructure Services - Port Configuration
# ===================================================================
# Database
POSTGRES_DB=meldestelle
# Note: Username and password are now managed via Docker secrets
# Redis Cache
REDIS_PORT=6379
# Keycloak Authentication
KEYCLOAK_PORT=8180
KEYCLOAK_LOG_LEVEL=INFO
# Service Discovery
CONSUL_HOST=consul
CONSUL_PORT=8500
CONSUL_ENABLED=true
# Messaging
ZOOKEEPER_CLIENT_PORT=2181
KAFKA_PORT=9092
KAFKA_BROKER_ID=1
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1
# Monitoring
PROMETHEUS_PORT=9090
GRAFANA_PORT=3000
# ===================================================================
# Application Services - Port Configuration
# ===================================================================
# API Gateway
GATEWAY_HOST=api-gateway
GATEWAY_PORT=8081
# Microservices
PING_SERVICE_PORT=8082
MEMBERS_SERVICE_PORT=8083
HORSES_SERVICE_PORT=8084
EVENTS_SERVICE_PORT=8085
MASTERDATA_SERVICE_PORT=8086
AUTH_SERVICE_PORT=8087
MONITORING_SERVER_PORT=8088
# ===================================================================
# Client Applications - Port Configuration
# ===================================================================
# Web Application
WEB_APP_PORT=4000
WEB_APP_DOMAIN=localhost
NODE_ENV=production
# Nginx Configuration
NGINX_WORKER_PROCESSES=auto
NGINX_WORKER_CONNECTIONS=1024
# Desktop Application
DESKTOP_VNC_WEB_PORT=6080
DESKTOP_VNC_PORT=5901
DESKTOP_APP_DOMAIN=localhost
# ===================================================================
# Security Configuration
# ===================================================================
# JWT Configuration
JWT_ISSUER=meldestelle-auth-server
JWT_AUDIENCE=meldestelle-services
# Note: JWT_SECRET is now managed via Docker secrets
# Generate with: openssl rand -hex 32
# Keycloak Configuration
KEYCLOAK_REALM=meldestelle
KEYCLOAK_CLIENT_ID=api-gateway
# Note: All passwords and secrets are now managed via Docker secrets
# Run: ./docker/secrets/setup-secrets.sh to generate secure secrets
# ===================================================================
# Data Storage Configuration
# ===================================================================
# Data directory for persistent volumes
# Default: ./data (relative to project root)
# Production: /var/lib/meldestelle or dedicated mount point
DATA_PATH=./data
# Volume configuration
# These directories will be created under DATA_PATH:
# - postgres/ (PostgreSQL data)
# - redis/ (Redis data)
# - prometheus/ (Prometheus metrics)
# - grafana/ (Grafana dashboards)
# - keycloak/ (Keycloak data)
# - consul/ (Consul data)
# - monitoring/ (Custom monitoring data)
# - desktop-app/ (Desktop application data)
# ===================================================================
# Development and Testing
# ===================================================================
# Enable debug mode for Java applications
DEBUG=false
# Enable Wasm compilation for client applications
ENABLE_WASM=false
# ===================================================================
# Production Deployment Settings
# ===================================================================
# Container resource limits (configured in docker-compose files)
# These are documented here for reference:
# Infrastructure Services Resource Limits:
# - postgres: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - redis: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - keycloak: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 1GB RAM)
# - consul: 1 CPU, 512MB RAM (reserved: 0.25 CPU, 128MB RAM)
# - kafka: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - zookeeper: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - prometheus: 1 CPU, 2GB RAM (reserved: 0.25 CPU, 512MB RAM)
# - grafana: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - api-gateway: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 1GB RAM)
# Microservices Resource Limits:
# - ping-service: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - members-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - horses-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - events-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - masterdata-service: 1.5 CPU, 1.5GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - auth-server: 1.5 CPU, 1.5GB RAM (reserved: 0.5 CPU, 512MB RAM)
# Client Applications Resource Limits:
# - web-app: 1 CPU, 512MB RAM (reserved: 0.25 CPU, 128MB RAM)
# - desktop-app: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - monitoring-server: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# ===================================================================
# Security Notes
# ===================================================================
# 1. All passwords and secrets are managed via Docker secrets
# 2. Run ./docker/secrets/setup-secrets.sh to generate secure credentials
# 3. Containers run as non-root users where possible
# 4. Security options: no-new-privileges enabled for all services
# 5. Networks are isolated with custom subnet (172.20.0.0/16)
# 6. Volumes have proper permissions and are mounted read-only where appropriate
# 7. Health checks are configured for all services
# 8. Resource limits prevent resource exhaustion attacks
# ===================================================================
# Usage Instructions
# ===================================================================
# 1. Copy this file: mkdir -p config/env && cp .env.template config/env/.env
# 2. Customize values in config/env/.env for your environment
# 3. Generate secrets: ./docker/secrets/setup-secrets.sh --all
# 4. Create data directories: mkdir -p ./data/{postgres,redis,prometheus,grafana,keycloak,consul}
# 5. Deploy infrastructure: docker compose -f docker-compose.yml up -d
# 6. Deploy services: docker compose -f docker-compose.services.yml up -d
# 7. Deploy clients: docker compose -f docker-compose.clients.yml up -d
# ===================================================================
# Monitoring and Logging
# ===================================================================
# Access URLs (when running with default ports):
# - Grafana Dashboard: http://localhost:3000 (admin credentials in secrets)
# - Prometheus Metrics: http://localhost:9090
# - Consul UI: http://localhost:8500
# - Keycloak Admin: http://localhost:8180/admin (admin credentials in secrets)
# - API Gateway: http://localhost:8081
# - Web Application: http://localhost:4000
# - Desktop VNC: http://localhost:6080
# Log locations (inside containers):
# - Application logs: /app/logs/
# - Nginx logs: /var/log/nginx/
# - System logs: journalctl -u docker
-207
View File
@@ -1,207 +0,0 @@
# ===================================================================
# Environment Configuration Template - Meldestelle Project
# ===================================================================
# Copy this file to .env and customize the values for your environment
# Security Note: Never commit .env files containing production secrets!
# ===================================================================
# ===================================================================
# Build Configuration
# ===================================================================
# Docker image versions
DOCKER_GRADLE_VERSION=9.1.0
DOCKER_JAVA_VERSION=21
DOCKER_KEYCLOAK_VERSION=26.4.0
DOCKER_PROMETHEUS_VERSION=v2.54.1
DOCKER_GRAFANA_VERSION=11.3.0
# Application version
DOCKER_APP_VERSION=1.0.0
APP_VERSION=1.0.0
APP_NAME=Meldestelle
# Build metadata
BUILD_DATE=2025-11-11
# BUILD_DATE will be auto-generated if not set
# Spring profiles for services
SPRING_PROFILES_ACTIVE=docker,keycloak
DOCKER_SPRING_PROFILES_DEFAULT=default
DOCKER_SPRING_PROFILES_DOCKER=docker
# ===================================================================
# Infrastructure Services - Port Configuration
# ===================================================================
# Database
POSTGRES_DB=meldestelle
# Note: Username and password are now managed via Docker secrets
# Redis Cache
REDIS_PORT=6379
# Keycloak Authentication
KEYCLOAK_PORT=8180
KEYCLOAK_LOG_LEVEL=INFO
# Service Discovery
CONSUL_HOST=consul
CONSUL_PORT=8500
CONSUL_ENABLED=true
# Messaging
ZOOKEEPER_CLIENT_PORT=2181
KAFKA_PORT=9092
KAFKA_BROKER_ID=1
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1
# Monitoring
PROMETHEUS_PORT=9090
GRAFANA_PORT=3000
# ===================================================================
# Application Services - Port Configuration
# ===================================================================
# API Gateway
GATEWAY_HOST=api-gateway
GATEWAY_PORT=8081
# Microservices
PING_SERVICE_PORT=8082
MEMBERS_SERVICE_PORT=8083
HORSES_SERVICE_PORT=8084
EVENTS_SERVICE_PORT=8085
MASTERDATA_SERVICE_PORT=8086
AUTH_SERVICE_PORT=8087
MONITORING_SERVER_PORT=8088
# ===================================================================
# Client Applications - Port Configuration
# ===================================================================
# Web Application
WEB_APP_PORT=4000
WEB_APP_DOMAIN=localhost
NODE_ENV=production
# Nginx Configuration
NGINX_WORKER_PROCESSES=auto
NGINX_WORKER_CONNECTIONS=1024
# Desktop Application
DESKTOP_VNC_WEB_PORT=6080
DESKTOP_VNC_PORT=5901
DESKTOP_APP_DOMAIN=localhost
# ===================================================================
# Security Configuration
# ===================================================================
# JWT Configuration
JWT_ISSUER=meldestelle-auth-server
JWT_AUDIENCE=meldestelle-services
# Note: JWT_SECRET is now managed via Docker secrets
# Generate with: openssl rand -hex 32
# Keycloak Configuration
KEYCLOAK_REALM=meldestelle
KEYCLOAK_CLIENT_ID=api-gateway
# Note: All passwords and secrets are now managed via Docker secrets
# Run: ./docker/secrets/setup-secrets.sh to generate secure secrets
# ===================================================================
# Data Storage Configuration
# ===================================================================
# Data directory for persistent volumes
# Default: ./data (relative to project root)
# Production: /var/lib/meldestelle or dedicated mount point
DATA_PATH=./data
# Volume configuration
# These directories will be created under DATA_PATH:
# - postgres/ (PostgreSQL data)
# - redis/ (Redis data)
# - prometheus/ (Prometheus metrics)
# - grafana/ (Grafana dashboards)
# - keycloak/ (Keycloak data)
# - consul/ (Consul data)
# - monitoring/ (Custom monitoring data)
# - desktop-app/ (Desktop application data)
# ===================================================================
# Development and Testing
# ===================================================================
# Enable debug mode for Java applications
DEBUG=false
# Enable Wasm compilation for client applications
ENABLE_WASM=false
# ===================================================================
# Production Deployment Settings
# ===================================================================
# Container resource limits (configured in docker-compose files)
# These are documented here for reference:
# Infrastructure Services Resource Limits:
# - postgres: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - redis: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - keycloak: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 1GB RAM)
# - consul: 1 CPU, 512MB RAM (reserved: 0.25 CPU, 128MB RAM)
# - kafka: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - zookeeper: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - prometheus: 1 CPU, 2GB RAM (reserved: 0.25 CPU, 512MB RAM)
# - grafana: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - api-gateway: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 1GB RAM)
# Microservices Resource Limits:
# - ping-service: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - members-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - horses-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - events-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - masterdata-service: 1.5 CPU, 1.5GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - auth-server: 1.5 CPU, 1.5GB RAM (reserved: 0.5 CPU, 512MB RAM)
# Client Applications Resource Limits:
# - web-app: 1 CPU, 512MB RAM (reserved: 0.25 CPU, 128MB RAM)
# - desktop-app: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - monitoring-server: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# ===================================================================
# Security Notes
# ===================================================================
# 1. All passwords and secrets are managed via Docker secrets
# 2. Run ./docker/secrets/setup-secrets.sh to generate secure credentials
# 3. Containers run as non-root users where possible
# 4. Security options: no-new-privileges enabled for all services
# 5. Networks are isolated with custom subnet (172.20.0.0/16)
# 6. Volumes have proper permissions and are mounted read-only where appropriate
# 7. Health checks are configured for all services
# 8. Resource limits prevent resource exhaustion attacks
# ===================================================================
# Usage Instructions
# ===================================================================
# 1. Copy this file: cp .env.template .env
# 2. Customize values in .env for your environment
# 3. Generate secrets: ./docker/secrets/setup-secrets.sh --all
# 4. Create data directories: mkdir -p ./data/{postgres,redis,prometheus,grafana,keycloak,consul}
# 5. Deploy infrastructure: docker-compose -f docker-compose.yml.optimized up -d
# 6. Deploy services: docker-compose -f docker-compose.yml.optimized -f docker-compose.services.yml.optimized up -d
# 7. Deploy clients: docker-compose -f docker-compose.yml.optimized -f docker-compose.services.yml.optimized -f docker-compose.clients.yml.optimized up -d
# ===================================================================
# Monitoring and Logging
# ===================================================================
# Access URLs (when running with default ports):
# - Grafana Dashboard: http://localhost:3000 (admin credentials in secrets)
# - Prometheus Metrics: http://localhost:9090
# - Consul UI: http://localhost:8500
# - Keycloak Admin: http://localhost:8180/admin (admin credentials in secrets)
# - API Gateway: http://localhost:8081
# - Web Application: http://localhost:4000
# - Desktop VNC: http://localhost:6080
# Log locations (inside containers):
# - Application logs: /app/logs/
# - Nginx logs: /var/log/nginx/
# - System logs: journalctl -u docker
-1
View File
@@ -1 +0,0 @@
# Horses Module\n\nThis is a minimal placeholder README to satisfy documentation validation. See docs/index.md for project docs
-443
View File
@@ -1,443 +0,0 @@
### Schlachtplan für das 'infrastructure'-Modul
Basierend auf der Analyse des aktuellen Zustands (Stand: 11. Oktober 2025) habe ich einen strukturierten Aktionsplan
erstellt. Die letzte größere Aktualisierung war im Juli 2025, seitdem gab es signifikante Änderungen am Gateway-Modul.
---
### 🔴 Phase 1: SOFORT (Diese Woche)
#### 1.1 Gateway-Tests reparieren (Höchste Priorität)
**Problem:** Tests sind komplett defekt - nur ~47% funktionieren noch (25/53 Tests).
**Aktionen:**
- ❌ **Löschen:** `JwtAuthenticationTests.kt` - testet nicht-existierende Custom-Filter
- ✅ **Behalten:** `FallbackControllerTests.kt`, `GatewayApplicationTests.kt`
- ✏️ **Überarbeiten:** `GatewayRoutingTests.kt`, `GatewaySecurityTests.kt`, `GatewayFiltersTests.kt`
- Option A: Tests mit MockJWT-Tokens ausstatten (siehe `TestSecurityConfig.kt`)
- Option B: Tests auf Public Paths verlegen (`/actuator/**`, `/fallback/**`)
- Option C: Security in Tests deaktivieren
**Warum jetzt:** Tests geben keine Sicherheit mehr blockiert Entwicklung.
**Zeitaufwand:** 46 Stunden
---
#### 1.2 Gateway-Build-Datei bereinigen
**Problem:** Duplizierte Dependency in `gateway/build.gradle.kts` (Zeile 33-34).
**Aktion:**
```kotlin
// ENTFERNEN: Zeile 34
implementation(project(":infrastructure:event-store:redis-event-store")) // ← Duplikat!
```
**Zeitaufwand:** 5 Minuten
---
### 🟡 Phase 2: KURZFRISTIG (Nächste 2 Wochen)
#### 2.1 Dependency-Versionen aktualisieren
**Problem:** Versionen von Juli 2025 teilweise veraltet.
**Zu prüfen und aktualisieren:**
| Dependency | Aktuell | Latest (Okt 2025) | Priorität |
|-------------------|----------|-------------------|-----------|
| Spring Boot | 3.5.5 | 3.5.x | Mittel |
| Spring Cloud | 2025.0.0 | 2025.0.x | Mittel |
| Kotlin | 2.2.20 | 2.2.x | Niedrig |
| Keycloak | 26.0.7 | 26.x.x | Hoch |
| Testcontainers | 1.21.3 | 1.21.x | Niedrig |
| PostgresQL Driver | 42.7.7 | 42.7.x | Niedrig |
**Aktion:**
1. `gradle/libs.versions.toml` aktualisieren
2. Tests nach jedem Update ausführen
3. Breaking Changes dokumentieren
**Zeitaufwand:** 12 Tage (mit Testing)
---
#### 2.2 Docker-Images aktualisieren
**Problem:** Einige Docker-Images sind möglicherweise veraltet.
**Zu prüfen:**
```yaml
# docker-compose.yml
postgres: 16-alpine # ✅ Aktuell (neueste: 16.x)
redis: 7-alpine # ✅ Aktuell
keycloak: 26.4.0 # ⚠️ Prüfen auf 26.x updates
consul: 1.15 # ⚠️ Prüfen (neueste: 1.20+)
kafka: 7.4.0 # ⚠️ Prüfen (neueste: 7.8+)
prometheus: v2.54.1 # ⚠️ Prüfen
grafana: 11.3.0 # ✅ Wahrscheinlich aktuell
```
**Aktion:**
1. Versions-Check durchführen
2. Schrittweise aktualisieren (einzeln testen!)
3. `.env`-Datei mit Versions-Variablen anlegen
**Zeitaufwand:** 34 Stunden
---
#### 2.3 Monitoring-Modul vervollständigen
**Problem:** Nur 3 Kotlin-Files deutlich unter implementiert im Vergleich zur Dokumentation.
**Dokumentiert, aber fehlt:**
- Distributed Tracing (Zipkin) - Docker-Container fehlt!
- Custom Metrics Implementation
- Health Check Aggregation
- Alerting Rules Implementation
**Aktion:**
1. Zipkin zu `docker-compose.yml` hinzufügen
2. Tracing-Integration in Gateway testen
3. Custom Metrics-Library erstellen
4. Prometheus Alerting Rules konfigurieren
**Zeitaufwand:** 23 Tage
---
### 🟢 Phase 3: MITTELFRISTIG (Nächste 46 Wochen)
#### 3.1 Dokumentation aktualisieren
**Problem:** README von Juli 2025 nicht mehr aktuell.
**Zu aktualisieren:**
**`README-INFRASTRUCTURE.md`:**
- Zeile 552: "Letzte Aktualisierung: 25. Juli 2025" → Oktober 2025
- Security-Sektion: OAuth2 Resource Server statt Custom JWT Filter
- Keycloak Version: 23.0 → 26.4.0
- Kafka Version: 7.5.0 → 7.4.0 (Downgrade dokumentieren!)
- Monitoring: Zipkin-Konfiguration ergänzen
**Neue Sections hinzufügen:**
- #### Bekannte Limitierungen
- #### Migration Notes (Juli → Oktober 2025)
- #### Troubleshooting erweitern
**Zeitaufwand:** 1 Tag
---
#### 3.2 Auth-Module überarbeiten
**Problem:** Vermutlich veraltet - Custom JWT vs. OAuth2 Resource Server Diskrepanz.
**Zu klären:**
- Werden `auth-client` und `auth-server` noch verwendet?
- Redundanz mit Gateway's OAuth2 Resource Server?
- Keycloak-Integration vereinheitlichen
**Aktion:**
1. Abhängigkeiten zu auth-Modulen analysieren
2. Entscheiden: Refactoring oder Deprecation
3. Wenn deprecated: Migration Path dokumentieren
**Zeitaufwand:** 35 Tage
---
#### 3.3 Cache-Module modernisieren
**Problem:** Redis 7 ist aktuell, aber Implementation-Patterns könnten veraltet sein.
**Zu prüfen:**
- Multi-Level Caching tatsächlich implementiert?
- Cache Statistics vorhanden?
- TTL Management korrekt?
- Integration mit Spring Cache Abstraction?
**Aktion:**
1. Cache-Tests erweitern
2. Performance-Metriken hinzufügen
3. Cache-Warming Strategy implementieren
**Zeitaufwand:** 23 Tage
---
#### 3.4 Event-Store Performance-Optimierung
**Problem:** Redis-basiert - für Production ggf. nicht optimal.
**Zu evaluieren:**
- Ist Redis der richtige Event Store für Production?
- Alternative: PostgresQL mit Event Store Pattern?
- Snapshot-Strategie tatsächlich implementiert?
**Aktion:**
1. Performance-Tests durchführen
2. Event Store Benchmark (Redis vs. PostgresQL)
3. Dokumentation aktualisieren mit Pros/Cons
**Zeitaufwand:** 1 Woche
---
### 🔵 Phase 4: LANGFRISTIG (Nächste 23 Monate)
#### 4.1 Service Mesh evaluieren
**Dokumentiert in "Zukünftige Erweiterungen"** noch nicht implementiert.
**Optionen:**
- Istio (komplex, feature-reich)
- Linkerd (leichtgewichtig)
- Consul Connect (bereits Consul vorhanden!)
**Empfehlung:** Start mit Consul Connect - minimaler Overhead.
**Zeitaufwand:** 23 Wochen
---
#### 4.2 OpenTelemetry statt Zipkin
**Problem:** Zipkin ist veraltet OpenTelemetry ist der moderne Standard.
**Migration Path:**
1. OpenTelemetry Collector aufsetzen
2. Spring Boot Auto-Instrumentation aktivieren
3. Zipkin als Backend behalten (kompatibel!)
4. Schrittweise migrieren
**Zeitaufwand:** 12 Wochen
---
#### 4.3 Security Hardening
**Aktuelle Gaps:**
- JWT Token Rotation nicht implementiert
- Rate Limiting nur dokumentiert, nicht konfiguriert
- Audit Logging fehlt
- HTTPS/TLS noch nicht erzwungen
**Aktion:**
1. Rate Limiting im Gateway aktivieren
2. Audit Log Framework implementieren
3. TLS für Service-zu-Service-Kommunikation
4. Security Scan mit OWASP Dependency Check
**Zeitaufwand:** 23 Wochen
---
#### 4.4 Infrastructure as Code (IaC)
**Problem:** Nur Docker Compose für Production nicht ausreichend.
**Zu erstellen:**
- Kubernetes Manifests (aktualisieren - Zeile 393+)
- Helm Charts (aktualisieren Zeile 420+)
- Terraform für Cloud-Ressourcen
- CI/CD Pipelines
**Zeitaufwand:** 46 Wochen
---
### 📊 Priorisierung-Matrix
| Phase | Aufgabe | Dringlichkeit | Aufwand | Impact |
|-------|---------------|---------------|---------|---------|
| 1 | Gateway-Tests | 🔴 Sehr hoch | 4-6h | Hoch |
| 1 | Build-Datei | 🔴 Sehr hoch | 5min | Niedrig |
| 2 | Dependencies | 🟡 Hoch | 1-2d | Mittel |
| 2 | Docker-Images | 🟡 Hoch | 3-4h | Mittel |
| 2 | Monitoring | 🟡 Mittel | 2-3d | Hoch |
| 3 | Dokumentation | 🟢 Mittel | 1d | Mittel |
| 3 | Auth-Module | 🟢 Mittel | 3-5d | Hoch |
| 3 | Cache | 🟢 Niedrig | 2-3d | Mittel |
| 3 | Event-Store | 🟢 Niedrig | 1w | Mittel |
| 4 | Service Mesh | 🔵 Niedrig | 2-3w | Hoch |
| 4 | OpenTelemetry | 🔵 Niedrig | 1-2w | Mittel |
| 4 | Security | 🔵 Mittel | 2-3w | Hoch |
| 4 | IaC | 🔵 Niedrig | 4-6w | Hoch |
---
### 🎯 Empfohlene Reihenfolge
#### Woche 1-2
1. Gateway-Tests reparieren
2. Build-Datei bereinigen
3. Dependencies aktualisieren
#### Woche 3-4
4. Docker-Images aktualisieren
5. Monitoring vervollständigen
6. Dokumentation aktualisieren
#### Woche 5-8
7. Auth-Module evaluieren/refactored
8. Cache-Module modernisieren
9. Event-Store Performance-Tests
#### Monat 3-4
10. Security Hardening
11. OpenTelemetry Migration
12. Service Mesh Evaluation
#### Monat 5-6
13. Infrastructure as Code
14. Production Readiness Assessment
---
### 🛠️ Tooling-Empfehlungen
**Für Dependency-Management:**
- Renovate Bot oder Dependabot für automatische Updates
- `./gradlew dependencyUpdates` Plugin verwenden
**Für Security:**
- OWASP Dependency Check
- Trivy für Container-Scanning
- SonarQube für Code-Qualität
**Für Monitoring:**
- Grafana Dashboards aus Community importieren
- Prometheus Alertmanager konfigurieren
---
### 📝 Nächste Schritte
1. **Jetzt sofort:** Gateway-Tests fixen (blockiert alles andere)
2. **Diese Woche:** Dependencies updaten und testen
3. **Nächste Woche:** Sprint Planning für Phase 2
4. **Monatlich:** Review des Fortschritts und Repriorisierung
---
### ⚠️ Risiken & Abhängigkeiten
**Kritische Pfade:**
- Gateway-Tests müssen ZUERST behoben werden
- Dependency-Updates können Breaking Changes haben
- Auth-Refactoring könnte alle Services betreffen
**Externe Abhängigkeiten:**
- Keycloak Breaking Changes bei Major Updates
- Spring Boot/Cloud Release Schedule beachten
- Kubernetes Cluster für IaC-Phase benötigt
---
**Geschätzter Gesamtaufwand:** 68 Wochen (bei 1 Vollzeit-Entwickler)
**Empfohlener Start:** Sofort mit Phase 1, dann iterativ durch die Phasen
---
### Documentations-Sprachbereinigung (2025-10-22)
Im Zuge der Vereinheitlichung auf ausschließlich deutschsprachige Dokumentation wurden folgende Dateien entfernt:
Gelöschte ADRs (englische Varianten):
- docs/architecture/adr/0000-adr-template.md
- docs/architecture/adr/0001-modular-architecture.md
- docs/architecture/adr/0002-domain-driven-design.md
- docs/architecture/adr/0003-microservices-architecture.md
- docs/architecture/adr/0004-event-driven-communication.md
- docs/architecture/adr/0005-polyglot-persistence.md
- docs/architecture/adr/0006-authentication-authorization-keycloak.md
- docs/architecture/adr/0007-api-gateway-pattern.md
- docs/architecture/adr/0008-multiplatform-client-applications.md
Gelöschte C4-Diagramme (englische Varianten):
- docs/architecture/c4/01-context.puml
- docs/architecture/c4/02-container.puml
- docs/architecture/c4/03-component-events-service.puml
Hinweis:
- Alle verbleibenden ADRs und C4-Diagramme sind in deutscher Sprache vorhanden (Suffix-de) und verlinkt.
- Weitere Doku-Dateien in docs/ sind deutsch (Front-Matter/Sprachindizien geprüft).
---
## CIStabilisierung Keycloak (20251025)
Hintergrund: In GitHub Actions startete Keycloak zeitweise nicht zuverlässig. Ziel: Integrationstests stabilisieren,
ohne produktive Architektur zu ändern.
Änderungen:
- IntegrationWorkflow (`.github/workflows/integration-tests.yml`) auf Matrixbetrieb umgestellt:
- `keycloak_db=postgres` (produktnäher, mit externer PostgresDB)
- `keycloak_db=dev-file` (Dateibackend, ohne Postgres; stabiler im CI)
- Robuste Startlogik:
- Aktives Warten auf Postgres (nur in `postgres`Variante)
- KeycloakStart per `docker run … start-dev` (26.4.2) mit `KC_HEALTH_ENABLED=true`
- HealthChecks gegen `/`, `/health`, `/q/health`, `/health/ready`, AdminKonsole
- Ausführliche LogAusgabe bei Fehlern (Keycloak & Postgres)
- Failfast deaktiviert; beide MatrixJobs laufen unabhängig.
Nutzung/Operative Hinweise:
- In PRs beide MatrixRuns beachten; bei Flakes in `postgres` sichert `dev-file` die Tests ab.
- Logs bei Fehlschlag: Step „Dump service logs (Keycloak, Postgres)“ am Jobende öffnen.
- Produktiv bleibt Postgres maßgeblich (siehe `docker-compose.yml`).
ADRKonsistenz:
- ADR0006 (Keycloak) bleibt gültig und unverändert; die `dev-file`Variante betrifft ausschließlich CITests.
Next Steps (optional):
- Falls `postgres` im CI dauerhaft flakey: Required Checks vorübergehend auf `dev-file` begrenzen.
- Langfristig: Ursachenanalyse für PostgresVariante (RunnerLeistung/Timeouts/SchemaSetup) und ReEnable als Required
Check nach Stabilisierung.
---
-20
View File
@@ -1,20 +0,0 @@
# ===================================================================
# Clients Docker Build Arguments - dockerfiles/clients/*
# Source: docker/versions.toml [categories.clients]
# Last updated: 2025-11-18 14:30:11 UTC
# ===================================================================
# --- Include Global Arguments ---
# Source global.env for GRADLE_VERSION, JAVA_VERSION, VERSION
# --- Client-Specific Build Tools ---
NODE_VERSION=22.21.0
NGINX_VERSION=1.28.0-alpine
# --- Client Build Configuration ---
CLIENT_PATH=client
CLIENT_MODULE=client
CLIENT_NAME=meldestelle-client
# Note: Runtime/Dev values moved to config/env/.env
# Keep this file strictly for build-time values only.
-26
View File
@@ -1,26 +0,0 @@
# ===================================================================
# Global Docker Build Arguments - Used by all categories
# Source: docker/versions.toml
# Last updated: 2025-11-18 15:44:00 UTC
# ===================================================================
# --- Build Tools ---
GRADLE_VERSION=9.1.0
JAVA_VERSION=21
# --- Build Metadata ---
VERSION=1.0.0
# --- Monitoring & Infrastructure Services (image tags) ---
PROMETHEUS_IMAGE_TAG=v2.54.1
GRAFANA_IMAGE_TAG=11.3.0
KEYCLOAK_IMAGE_TAG=26.4.2
# --- Datastore Images (image tags) ---
POSTGRES_IMAGE_TAG=16-alpine
REDIS_IMAGE_TAG=7-alpine
# --- Additional Infrastructure Images (image tags) ---
CONSUL_IMAGE_TAG=1.15
ZOOKEEPER_IMAGE_TAG=7.4.0
KAFKA_IMAGE_TAG=7.4.0
@@ -1,22 +0,0 @@
# ===================================================================
# Infrastructure Docker Build Arguments - dockerfiles/infrastructure/*
# Source: docker/versions.toml [categories.infrastructure]
# Last updated: 2025-11-18 14:30:11 UTC
# ===================================================================
# --- Include Global Arguments ---
# Source global.env for GRADLE_VERSION, JAVA_VERSION, VERSION
# --- API Gateway Specific ---
GATEWAY_SERVICE_PATH=infrastructure/gateway
GATEWAY_SERVICE_NAME=api-gateway
# --- Auth Server Specific ---
AUTH_SERVER_PATH=infrastructure/auth/auth-server
AUTH_SERVER_SERVICE_NAME=auth-server
# --- Monitoring Server Specific ---
MONITORING_SERVER_PATH=infrastructure/monitoring/monitoring-server
MONITORING_SERVER_SERVICE_NAME=monitoring-server
# Note: Runtime profiles/ports/dependencies moved to config/env/.env
-14
View File
@@ -1,14 +0,0 @@
# ===================================================================
# Services Docker Build Arguments - dockerfiles/services/*
# Source: docker/versions.toml [categories.services]
# Last updated: 2025-11-18 14:30:11 UTC
# ===================================================================
# --- Include Global Arguments ---
# Source global.env for GRADLE_VERSION, JAVA_VERSION, VERSION
# --- Service-Specific Arguments ---
SERVICE_PATH=.
SERVICE_NAME=spring-boot-service
# Note: Runtime profiles/ports moved to config/env/.env
-12
View File
@@ -1,12 +0,0 @@
# Zentrale Einstiegsdatei für Docker Compose
name: meldestelle-system
include:
- path: docker-compose.yml # Infra (Postgres, Redis, Keycloak...)
- path: docker-compose.services.yml # Gateway & Microservices
- path: docker-compose.clients.yml # Web App
# Hier definieren wir das Netzwerk zentral, damit alle includes es nutzen können
networks:
meldestelle-network:
driver: bridge
-54
View File
@@ -1,54 +0,0 @@
# ===================================================================
# Docker Compose - Client Applications
# Generated from docker/versions.toml
# Environment: development
# Generated: 2025-11-18 19:43:46 UTC
# ===================================================================
services:
# ===================================================================
# Web Application (Compose for Web)
# ===================================================================
web-app:
profiles: ["ui", "frontend"]
build:
context: ..
dockerfile: ../dockerfiles/clients/web-app/Dockerfile
args:
# Global build arguments (centralized DOCKER_* variables)
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION}
BUILD_DATE: ${BUILD_DATE}
VERSION: ${DOCKER_APP_VERSION}
# Client-specific arguments (centralized DOCKER_* variables)
NODE_VERSION: ${DOCKER_NODE_VERSION}
NGINX_VERSION: ${DOCKER_NGINX_VERSION}
# Application-specific arguments
CLIENT_PATH: client
CLIENT_MODULE: client
CLIENT_NAME: meldestelle-web-app
container_name: meldestelle-web-app
environment:
NODE_ENV: ${NODE_ENV:-dev}
API_BASE_URL: http://api-gateway:${GATEWAY_PORT:-8081}
WS_URL: ws://api-gateway:${GATEWAY_PORT:-8081}/ws
APP_TITLE: ${APP_NAME:-Meldestelle}
APP_VERSION: ${APP_VERSION:-1.0.0}
ports:
- "4000:4000"
networks:
- meldestelle-network
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:4000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 40s
restart: unless-stopped
# ===================================================================
# Networks (shared network from main compose file)
# ===================================================================
networks:
meldestelle-network:
driver: bridge
-80
View File
@@ -1,80 +0,0 @@
# ===================================================================
# Docker Compose - Application Services
# Generated from docker/versions.toml
# Environment: development
# Generated: 2025-11-18 19:43:46 UTC
# ===================================================================
services:
profiles: ["app", "backend"]
ping-service:
build:
context: ..
dockerfile: ../dockerfiles/services/ping-service/Dockerfile
args:
# Global build arguments (centralized DOCKER_* variables)
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION}
BUILD_DATE: ${BUILD_DATE}
VERSION: ${DOCKER_APP_VERSION}
# Service-specific arguments (centralized DOCKER_* variables)
SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DOCKER}
container_name: meldestelle-ping-service
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-dev}
SERVER_PORT: ${PING_SERVICE_PORT:-8082}
DEBUG: ${DEBUG:-true}
LOGGING_LEVEL_ROOT: ${LOGGING_LEVEL_ROOT:-DEBUG}
JVM_DEBUG_PORT: 5005
ports:
- "${PING_SERVICE_PORT:-8082}:8082"
- "5005:5005" # Debug-Port
networks:
- meldestelle-network
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8082/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 3
start_period: 40s
restart: unless-stopped
api-gateway:
profiles: ["infra", "gateway"]
build:
context: ..
dockerfile: ../dockerfiles/infrastructure/gateway/Dockerfile
args:
# Global build arguments (centralized DOCKER_* variables)
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION}
BUILD_DATE: ${BUILD_DATE}
VERSION: ${DOCKER_APP_VERSION}
# Infrastructure-specific arguments (centralized DOCKER_* variables)
SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DEFAULT}
container_name: meldestelle-api-gateway
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-dev}
SERVER_PORT: ${API_GATEWAY_PORT:-8081}
DEBUG: ${DEBUG:-true}
LOGGING_LEVEL_ROOT: ${LOGGING_LEVEL_ROOT:-DEBUG}
JVM_DEBUG_PORT: 5005
ports:
- "${API_GATEWAY_PORT:-8081}:8081"
- "5005:5005" # Debug-Port
networks:
- meldestelle-network
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8081/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 3
start_period: 40s
restart: unless-stopped
# ===================================================================
# Networks (shared network from main compose file)
# ===================================================================
networks:
meldestelle-network:
driver: bridge
-162
View File
@@ -1,162 +0,0 @@
# ===================================================================
# Docker Compose - Infrastructure Services
# Generated from docker/versions.toml
# Environment: development
# Generated: 2025-11-18 19:43:46 UTC
# ===================================================================
services:
# ===================================================================
# Database
# ===================================================================
postgres:
profiles: ["core", "backend"]
image: postgres:${DOCKER_POSTGRES_VERSION:-16-alpine}
container_name: meldestelle-postgres
environment:
POSTGRES_USER: ${POSTGRES_USER:-meldestelle}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-meldestelle}
POSTGRES_DB: ${POSTGRES_DB:-meldestelle}
ports:
- "5432:5432"
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: 30s
timeout: 5s
retries: 3
start_period: 40s
restart: unless-stopped
# ===================================================================
# Cache
# ===================================================================
redis:
profiles: ["core", "backend"]
image: redis:${DOCKER_REDIS_VERSION:-7-alpine}
container_name: meldestelle-redis
ports:
- "${REDIS_PORT:-6379}:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yes
networks:
- meldestelle-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 5s
retries: 3
start_period: 40s
restart: unless-stopped
# ===================================================================
# Authentication
# ===================================================================
keycloak:
profiles: ["auth", "security"]
image: quay.io/keycloak/keycloak:${DOCKER_KEYCLOAK_VERSION:-26.4.2}
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:5432/${POSTGRES_DB:-meldestelle}
KC_DB_USERNAME: ${POSTGRES_USER:-meldestelle}
KC_DB_PASSWORD: ${POSTGRES_PASSWORD:-meldestelle}
ports:
- "8180: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: 30s
timeout: 5s
retries: 3
start_period: 40s
restart: unless-stopped
# ===================================================================
# Monitoring
# ===================================================================
prometheus:
profiles: ["monitoring"]
image: prom/prometheus:${DOCKER_PROMETHEUS_VERSION:-v2.54.1}
container_name: meldestelle-prometheus
ports:
- "${PROMETHEUS_PORT:-9090}:9090"
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:9090/-/healthy"]
interval: 30s
timeout: 5s
retries: 3
start_period: 40s
restart: unless-stopped
grafana:
profiles: ["monitoring"]
image: grafana/grafana:${DOCKER_GRAFANA_VERSION:-11.3.0}
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:-3000}:3000"
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:3000/api/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 40s
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
-1
View File
@@ -1 +0,0 @@
# Events Module\n\nThis is a minimal placeholder README to satisfy documentation validation. See docs/index.md for project docs
-1
View File
@@ -1 +0,0 @@
# Masterdata Module\n\nThis is a minimal placeholder README to satisfy documentation validation. See docs/index.md for project docs
-1
View File
@@ -1 +0,0 @@
# Members Module\n\nThis is a minimal placeholder README to satisfy documentation validation. See docs/index.md for project docs
-15
View File
@@ -1,15 +0,0 @@
# Docker Secrets (Development vs. Production)
In der lokalen Entwicklung werden keine Docker-Secrets erzwungen.
- Verwende für sensible Werte stattdessen die Datei `config/env/.env.local` (ist gitignored).
- Die Dateien in diesem Ordner sind lediglich Platzhalter und enthalten KEINE echten Geheimnisse.
- Für ein Deployment in Produktion kannst du diese Dateien mit echten Werten befüllen oder einen sicheren Secret-Store (Docker/K8s) verwenden.
Hinweise:
- Postgres-User/Passwort haben in der lokalen Entwicklung Standard/Fallback-Werte via `docker-compose.yml` (Environment mit Defaults).
- Die optimierten Compose-Dateien (`*.optimized`) können weiterhin Docker-Secrets verwenden diese sind für Prod gedacht.
Schnellstart lokal (ohne Secrets):
- Passe `config/env/.env` und optional `config/env/.env.local` an
- Starte mit: `docker compose -f docker-compose.yml -f docker-compose.services.yml up`
@@ -1 +0,0 @@
TiB6FRRYW4gjM7xie17mKtTYFOp
@@ -1 +0,0 @@
admin
-1
View File
@@ -1 +0,0 @@
ba960b899f72d5ed192b5597d7f4b5b8853d9d641a2dc23c6b1a4b692b20211c
@@ -1 +0,0 @@
XASb7AzVy7G5fEKulE1mNPTy2Sw6pHi
@@ -1 +0,0 @@
s8N3r59JwS0lFsJobKWFJXh9qvdbHgcC6S3fYXYdXFM6eMKkRMtQbxHo0NJKFJC
@@ -1 +0,0 @@
lRo7W15UNy60EFRlvk1XP99MmgrgK2Z97QK9btl9ZPVIVzWcY81Bebp9hpB
@@ -1 +0,0 @@
pON4NxxsKPWseVg1gw5PyLNN4YYrj8h
@@ -1 +0,0 @@
metrics
@@ -1 +0,0 @@
CHANGE_ME_LOCAL_DEV
-1
View File
@@ -1 +0,0 @@
meldestelle
-1
View File
@@ -1 +0,0 @@
p701HhKOnZJ4zbY9dGRvyH9kQTKcsUm
-345
View File
@@ -1,345 +0,0 @@
#!/bin/bash
# ===================================================================
# Docker Secrets Setup Script - Meldestelle Project
# ===================================================================
# This script generates secure secrets for all Docker services
# Security Features:
# - Generates cryptographically secure random passwords
# - Creates JWT secrets with proper length for HMAC512
# - Sets appropriate file permissions (600) for security
# - Provides backup functionality
# - Validates secret file creation
# ===================================================================
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SECRETS_DIR="${SCRIPT_DIR}"
# Logging function
log() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}
warn() {
echo -e "${YELLOW}[WARNING] $1${NC}"
}
error() {
echo -e "${RED}[ERROR] $1${NC}"
exit 1
}
# Function to generate secure random password
generate_password() {
local length=${1:-32}
openssl rand -base64 $((length * 3 / 4)) | tr -d "=+/" | cut -c1-${length}
}
# Function to generate JWT secret (64 characters for HMAC512)
generate_jwt_secret() {
openssl rand -hex 32
}
# Function to create secret file with proper permissions
create_secret_file() {
local filename="$1"
local content="$2"
local filepath="${SECRETS_DIR}/${filename}"
# Check if file already exists
if [[ -f "$filepath" ]]; then
warn "Secret file $filename already exists. Use --force to overwrite."
return 1
fi
# Create the secret file
echo -n "$content" > "$filepath"
chmod 600 "$filepath"
log "Created secret file: $filename"
return 0
}
# Function to backup existing secrets
backup_secrets() {
local backup_dir="${SECRETS_DIR}/backup_$(date +%Y%m%d_%H%M%S)"
if find "$SECRETS_DIR" -name "*.txt" -type f | grep -q .; then
log "Creating backup of existing secrets..."
mkdir -p "$backup_dir"
find "$SECRETS_DIR" -name "*.txt" -type f -exec cp {} "$backup_dir/" \;
log "Backup created in: $backup_dir"
fi
}
# Function to validate secret file
validate_secret_file() {
local filepath="$1"
local min_length="$2"
if [[ ! -f "$filepath" ]]; then
error "Secret file does not exist: $filepath"
fi
local content_length=$(wc -c < "$filepath")
if [[ $content_length -lt $min_length ]]; then
error "Secret file $filepath is too short (${content_length} < ${min_length})"
fi
local permissions=$(stat -c %a "$filepath")
if [[ "$permissions" != "600" ]]; then
warn "Secret file $filepath has incorrect permissions: $permissions (should be 600)"
chmod 600 "$filepath"
fi
}
# Function to generate all secrets
generate_all_secrets() {
local force_overwrite=${1:-false}
log "Starting secret generation for Meldestelle Docker infrastructure..."
# Create backup if not forcing overwrite
if [[ "$force_overwrite" != "true" ]]; then
backup_secrets
fi
# Database secrets
log "Generating database secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/postgres_user.txt" ]]; then
create_secret_file "postgres_user.txt" "meldestelle"
fi
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/postgres_password.txt" ]]; then
create_secret_file "postgres_password.txt" "$(generate_password 32)"
fi
# Redis secrets
log "Generating Redis secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/redis_password.txt" ]]; then
create_secret_file "redis_password.txt" "$(generate_password 32)"
fi
# Keycloak secrets
log "Generating Keycloak secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/keycloak_admin_password.txt" ]]; then
create_secret_file "keycloak_admin_password.txt" "$(generate_password 32)"
fi
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/keycloak_client_secret.txt" ]]; then
create_secret_file "keycloak_client_secret.txt" "$(generate_password 64)"
fi
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/keycloak_auth_client_secret.txt" ]]; then
create_secret_file "keycloak_auth_client_secret.txt" "$(generate_password 64)"
fi
# Grafana secrets
log "Generating Grafana secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/grafana_admin_user.txt" ]]; then
create_secret_file "grafana_admin_user.txt" "admin"
fi
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/grafana_admin_password.txt" ]]; then
create_secret_file "grafana_admin_password.txt" "$(generate_password 32)"
fi
# JWT secrets
log "Generating JWT secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/jwt_secret.txt" ]]; then
create_secret_file "jwt_secret.txt" "$(generate_jwt_secret)"
fi
# VNC secrets (for desktop app)
log "Generating VNC secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/vnc_password.txt" ]]; then
create_secret_file "vnc_password.txt" "$(generate_password 16)"
fi
# Monitoring secrets
log "Generating monitoring secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/metrics_auth_username.txt" ]]; then
create_secret_file "metrics_auth_username.txt" "metrics"
fi
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/metrics_auth_password.txt" ]]; then
create_secret_file "metrics_auth_password.txt" "$(generate_password 32)"
fi
log "Secret generation completed successfully!"
}
# Function to validate all secrets
validate_all_secrets() {
log "Validating all secret files..."
# Define expected secrets with minimum lengths
declare -A secrets=(
["postgres_user.txt"]=8
["postgres_password.txt"]=16
["redis_password.txt"]=16
["keycloak_admin_password.txt"]=16
["keycloak_client_secret.txt"]=32
["keycloak_auth_client_secret.txt"]=32
["grafana_admin_user.txt"]=4
["grafana_admin_password.txt"]=16
["jwt_secret.txt"]=64
["vnc_password.txt"]=8
["metrics_auth_username.txt"]=4
["metrics_auth_password.txt"]=16
)
local all_valid=true
for secret_file in "${!secrets[@]}"; do
local filepath="${SECRETS_DIR}/${secret_file}"
local min_length=${secrets[$secret_file]}
if validate_secret_file "$filepath" "$min_length" 2>/dev/null; then
log "$secret_file is valid"
else
error "$secret_file is invalid or missing"
all_valid=false
fi
done
if [[ "$all_valid" == "true" ]]; then
log "All secret files are valid and properly secured!"
else
error "Some secret files are invalid. Please regenerate secrets."
fi
}
# Function to create Docker secrets
create_docker_secrets() {
log "Creating Docker secrets..."
# Get the project name (directory name)
local project_name=$(basename "$(dirname "$(dirname "$SCRIPT_DIR")")")
# Define secrets to create
declare -A docker_secrets=(
["postgres_user"]="postgres_user.txt"
["postgres_password"]="postgres_password.txt"
["redis_password"]="redis_password.txt"
["keycloak_admin_password"]="keycloak_admin_password.txt"
["keycloak_client_secret"]="keycloak_client_secret.txt"
["grafana_admin_user"]="grafana_admin_user.txt"
["grafana_admin_password"]="grafana_admin_password.txt"
["jwt_secret"]="jwt_secret.txt"
)
for secret_name in "${!docker_secrets[@]}"; do
local secret_file="${docker_secrets[$secret_name]}"
local filepath="${SECRETS_DIR}/${secret_file}"
local docker_secret_name="${project_name}_${secret_name}"
# Check if Docker secret already exists
if docker secret ls --format "{{.Name}}" | grep -q "^${docker_secret_name}$"; then
warn "Docker secret $docker_secret_name already exists"
else
# Create Docker secret
if docker secret create "$docker_secret_name" "$filepath"; then
log "Created Docker secret: $docker_secret_name"
else
error "Failed to create Docker secret: $docker_secret_name"
fi
fi
done
}
# Function to show usage
show_usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --help Show this help message"
echo " --generate Generate all secret files (default)"
echo " --force Force overwrite existing secret files"
echo " --validate Validate existing secret files"
echo " --docker-secrets Create Docker secrets from files"
echo " --all Generate files, validate, and create Docker secrets"
echo ""
echo "Examples:"
echo " $0 # Generate secrets (skip existing files)"
echo " $0 --force # Generate secrets (overwrite existing files)"
echo " $0 --validate # Validate existing secret files"
echo " $0 --all # Complete setup (generate, validate, docker secrets)"
}
# Main execution
main() {
local action="generate"
local force_overwrite=false
# Check dependencies
if ! command -v openssl &> /dev/null; then
error "openssl is required but not installed"
fi
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--help)
show_usage
exit 0
;;
--generate)
action="generate"
shift
;;
--force)
force_overwrite=true
shift
;;
--validate)
action="validate"
shift
;;
--docker-secrets)
action="docker-secrets"
shift
;;
--all)
action="all"
shift
;;
*)
error "Unknown option: $1"
;;
esac
done
# Ensure secrets directory exists
mkdir -p "$SECRETS_DIR"
# Execute requested action
case $action in
"generate")
generate_all_secrets "$force_overwrite"
;;
"validate")
validate_all_secrets
;;
"docker-secrets")
create_docker_secrets
;;
"all")
generate_all_secrets "$force_overwrite"
validate_all_secrets
create_docker_secrets
;;
*)
error "Invalid action: $action"
;;
esac
log "Operation completed successfully!"
}
# Run main function with all arguments
main "$@"
-1
View File
@@ -1 +0,0 @@
nrscAXfIoOKTAEt
-192
View File
@@ -1,192 +0,0 @@
# ===================================================================
# Docker Versions Catalog - Single Source of Truth
# Analogous to gradle/libs.versions.toml for centralized version management
# ===================================================================
# Last updated: 2025-09-13
# Eliminates version redundancy across 12+ Dockerfiles
[versions]
# --- Build Tools ---
gradle = "9.1.0"
java = "21"
node = "22.21.0"
# --- Base Images ---
nginx = "1.25-alpine"
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"
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 = [
"GRADLE_VERSION",
"JAVA_VERSION",
"BUILD_DATE",
"VERSION"
]
# --- Spring Boot Services (dockerfiles/services/* and infrastructure/*) ---
spring-services = [
"SPRING_PROFILES_ACTIVE",
"SERVICE_PATH",
"SERVICE_NAME",
"SERVICE_PORT"
]
# --- Kotlin/JS Web Clients (dockerfiles/clients/*) ---
web-clients = [
"NODE_VERSION",
"NGINX_VERSION",
"CLIENT_PATH",
"CLIENT_MODULE",
"CLIENT_NAME"
]
[categories]
# --- Services Configuration ---
[categories.services]
default-spring-profile = "docker"
default-port-start = 8082
services = [
"ping-service",
"members-service",
"horses-service",
"events-service",
"masterdata-service"
]
# --- Infrastructure Configuration ---
[categories.infrastructure]
default-spring-profile = "default"
services = [
"gateway",
"auth-server",
"monitoring-server"
]
# --- Client Applications Configuration ---
[categories.clients]
default-node-version = "20.11.0"
default-nginx-version = "1.25-alpine"
clients = [
"web-app",
"desktop-app"
]
[environment-mapping]
# --- Environment Variable Names for Docker Compose ---
# Maps internal version names to environment variable names
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
-7
View File
@@ -1,7 +0,0 @@
# Backend
Domänenspezifische Services und Gateway.
- gateway: API Gateway/Auth/Routing
- discovery: Service Registry/Discovery (optional)
- services: Microservices, pro Domäne ein Service
-733
View File
@@ -1,733 +0,0 @@
# Gateway Configuration Documentation
## Überblick
Dieses Dokument beschreibt alle zentralen Konfigurationseigenschaften für das API Gateway. Die Konfiguration erfolgt über die `application.yml` Datei und kann durch Umgebungsvariablen überschrieben werden.
## Table of Contents
- [Server Configuration](#server-configuration)
- [Spring Application](#spring-application)
- [Consul Service Discovery](#consul-service-discovery)
- [Spring Cloud Gateway](#spring-cloud-gateway)
- [Circuit Breaker (Resilience4j)](#circuit-breaker-resilience4j)
- [Management & Monitoring](#management--monitoring)
- [Security](#security)
- [Logging](#logging)
---
## Server Configuration
### server.port
- **Typ**: Integer
- **Default**: 8081
- **Environment Variable**: `GATEWAY_PORT`
- **Beschreibung**: Port, auf dem das Gateway läuft
### server.netty.connection-timeout
- **Typ**: Duration
- **Default**: 5s
- **Beschreibung**: Timeout für initiale TCP-Verbindungen
### server.netty.idle-timeout
- **Typ**: Duration
- **Default**: 15s
- **Beschreibung**: Timeout für inaktive Verbindungen
**Beispiel:**
```yaml
server:
port: 8081
netty:
connection-timeout: 5s
idle-timeout: 15s
```
---
## Spring Application
### spring.application.name
- **Typ**: String
- **Default**: api-gateway
- **Beschreibung**: Name der Anwendung, wird in Consul und Logs verwendet
### spring.profiles.active
- **Typ**: String
- **Default**: dev
- **Environment Variable**: `SPRING_PROFILES_ACTIVE`
- **Beschreibung**: Aktives Spring-Profil (dev, test, prod)
- **Mögliche Werte**: dev, test, staging, prod
### spring.security.user.name / password
- **Typ**: String
- **Default**: admin / admin
- **Environment Variables**: `GATEWAY_ADMIN_USER`, `GATEWAY_ADMIN_PASSWORD`
- **Beschreibung**: Basic Auth für administrative Endpunkte
- **⚠️ Wichtig**: In Produktion durch sichere Werte ersetzen!
**Beispiel:**
```yaml
spring:
application:
name: api-gateway
profiles:
active: ${SPRING_PROFILES_ACTIVE:dev}
security:
user:
name: ${GATEWAY_ADMIN_USER:admin}
password: ${GATEWAY_ADMIN_PASSWORD:admin}
```
---
## Consul Service Discovery
### spring.cloud.consul.host
- **Typ**: String
- **Default**: localhost
- **Environment Variable**: `CONSUL_HOST`
- **Beschreibung**: Hostname des Consul-Servers
### spring.cloud.consul.port
- **Typ**: Integer
- **Default**: 8500
- **Environment Variable**: `CONSUL_PORT`
- **Beschreibung**: Port des Consul-Servers
### spring.cloud.consul.enabled
- **Typ**: Boolean
- **Default**: true
- **Environment Variable**: `CONSUL_ENABLED`
- **Beschreibung**: Aktiviert/Deaktiviert Consul Integration
### spring.cloud.consul.discovery.enabled
- **Typ**: Boolean
- **Default**: true
- **Environment Variable**: `CONSUL_ENABLED`
- **Beschreibung**: Aktiviert Service Discovery
### spring.cloud.consul.discovery.register
- **Typ**: Boolean
- **Default**: true
- **Environment Variable**: `CONSUL_ENABLED`
- **Beschreibung**: Registriert das Gateway in Consul
### spring.cloud.consul.discovery.health-check-path
- **Typ**: String
- **Default**: /actuator/health
- **Beschreibung**: Pfad für Consul Health Checks
### spring.cloud.consul.discovery.health-check-interval
- **Typ**: Duration
- **Default**: 10s
- **Beschreibung**: Intervall für Health Checks
### spring.cloud.consul.discovery.instance-id
- **Typ**: String
- **Default**: ${spring.application.name}-${server.port}-${random.uuid}
- **Beschreibung**: Eindeutige Instanz-ID für Service Discovery
**Beispiel:**
```yaml
spring:
cloud:
consul:
host: ${CONSUL_HOST:localhost}
port: ${CONSUL_PORT:8500}
enabled: ${CONSUL_ENABLED:true}
discovery:
enabled: ${CONSUL_ENABLED:true}
register: ${CONSUL_ENABLED:true}
health-check-path: /actuator/health
health-check-interval: 10s
instance-id: ${spring.application.name}-${server.port}-${random.uuid}
```
---
## Spring Cloud Gateway
### Verbindungskonfiguration
#### spring.cloud.gateway.server.webflux.httpclient.connect-timeout
- **Typ**: Integer (Millisekunden)
- **Default**: 5000
- **Beschreibung**: Timeout für Backend-Verbindungen
#### spring.cloud.gateway.server.webflux.httpclient.response-timeout
- **Typ**: Duration
- **Default**: 30s
- **Beschreibung**: Timeout für Backend-Responses
#### spring.cloud.gateway.server.webflux.httpclient.pool.max-idle-time
- **Typ**: Duration
- **Default**: 15s
- **Beschreibung**: Max. Idle-Zeit für Verbindungen im Pool
#### spring.cloud.gateway.server.webflux.httpclient.pool.max-life-time
- **Typ**: Duration
- **Default**: 60s
- **Beschreibung**: Max. Lebensdauer einer Verbindung
**Beispiel:**
```yaml
spring:
cloud:
gateway:
server:
webflux:
httpclient:
connect-timeout: 5000
response-timeout: 30s
pool:
max-idle-time: 15s
max-life-time: 60s
```
### Default Filters
Diese Filter werden auf **alle** Routen angewendet:
1. **DedupeResponseHeader**: Entfernt doppelte CORS-Header
2. **CircuitBreaker**: Default Circuit Breaker mit Fallback
3. **Retry**: Automatische Wiederholung bei Fehlern
4. **Security Headers**: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, etc.
5. **Cache-Control**: No-cache Header für alle Responses
**Beispiel:**
```yaml
spring:
cloud:
gateway:
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
- name: CircuitBreaker
args:
name: defaultCircuitBreaker
fallbackUri: forward:/fallback
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY,GATEWAY_TIMEOUT
methods: GET,POST,PUT,DELETE
backoff:
firstBackoff: 50ms
maxBackoff: 500ms
factor: 2
```
### Routes
Das Gateway definiert folgende Service-Routen:
#### 1. Members Service Route
- **Path**: `/api/members/**`
- **Service**: members-service (via Consul)
- **Circuit Breaker**: membersCircuitBreaker
- **Fallback**: /fallback/members
#### 2. Horses Service Route
- **Path**: `/api/horses/**`
- **Service**: horses-service (via Consul)
- **Circuit Breaker**: horsesCircuitBreaker
- **Fallback**: /fallback/horses
#### 3. Events Service Route
- **Path**: `/api/events/**`
- **Service**: events-service (via Consul)
- **Circuit Breaker**: eventsCircuitBreaker
- **Fallback**: /fallback/events
#### 4. Masterdata Service Route
- **Path**: `/api/masterdata/**`
- **Service**: masterdata-service (via Consul)
- **Circuit Breaker**: masterdataCircuitBreaker
- **Fallback**: /fallback/masterdata
#### 5. Auth Service Route
- **Path**: `/api/auth/**`
- **Service**: auth-service (via Consul)
- **Circuit Breaker**: authCircuitBreaker
- **Fallback**: /fallback/auth
#### 6. Ping Service Route
- **Path**: `/api/ping/**`
- **Service**: ping-service (via Consul)
- **No Circuit Breaker**: Optional service
**Beispiel einer Route:**
```yaml
spring:
cloud:
gateway:
routes:
- id: members-service-route
uri: lb://members-service # lb = Load Balanced via Consul
predicates:
- Path=/api/members/**
filters:
- StripPrefix=1 # Entfernt /api vom Pfad
- name: CircuitBreaker
args:
name: membersCircuitBreaker
fallbackUri: forward:/fallback/members
```
---
## Circuit Breaker (Resilience4j)
### Default Konfiguration
#### resilience4j.circuitbreaker.configs.default.registerHealthIndicator
- **Typ**: Boolean
- **Default**: true
- **Beschreibung**: Registriert Circuit Breaker im Health Endpoint
#### resilience4j.circuitbreaker.configs.default.slidingWindowSize
- **Typ**: Integer
- **Default**: 100
- **Beschreibung**: Größe des Sliding Window für Fehlerrate-Berechnung
#### resilience4j.circuitbreaker.configs.default.minimumNumberOfCalls
- **Typ**: Integer
- **Default**: 20
- **Beschreibung**: Mindestanzahl an Calls bevor Circuit Breaker aktiviert wird
#### resilience4j.circuitbreaker.configs.default.permittedNumberOfCallsInHalfOpenState
- **Typ**: Integer
- **Default**: 3
- **Beschreibung**: Anzahl Test-Calls im Half-Open State
#### resilience4j.circuitbreaker.configs.default.waitDurationInOpenState
- **Typ**: Duration
- **Default**: 5s
- **Beschreibung**: Wartezeit bevor von Open zu Half-Open gewechselt wird
#### resilience4j.circuitbreaker.configs.default.failureRateThreshold
- **Typ**: Integer (Prozent)
- **Default**: 50
- **Beschreibung**: Fehlerrate-Schwelle für Circuit Breaker Aktivierung
### Service-spezifische Circuit Breaker
Jeder Service hat einen eigenen Circuit Breaker mit angepasster Konfiguration:
| Service | Sliding Window | Failure Threshold | Besonderheit |
|---------|---------------|-------------------|--------------|
| members-service | 50 | 50% | Standard |
| horses-service | 50 | 50% | Standard |
| events-service | 75 | 50% | Größeres Window |
| masterdata-service | 30 | 50% | Kleineres Window |
| auth-service | 20 | 30% | Sensitiverer Threshold |
**Beispiel:**
```yaml
resilience4j:
circuitbreaker:
instances:
authCircuitBreaker:
baseConfig: default
slidingWindowSize: 20
failureRateThreshold: 30 # Auth ist kritisch -> niedrigerer Threshold
```
---
## Management & Monitoring
### Exposed Endpoints
#### management.endpoints.web.exposure.include
- **Typ**: Comma-separated String
- **Default**: health,info,metrics,prometheus,gateway,circuitbreakers
- **Beschreibung**: Öffentlich verfügbare Actuator Endpoints
**Verfügbare Endpoints:**
- `/actuator/health` - Service Health Status
- `/actuator/info` - Service Informationen
- `/actuator/metrics` - Micrometer Metriken
- `/actuator/prometheus` - Prometheus Scrape Endpoint
- `/actuator/gateway` - Gateway Routes & Filters
- `/actuator/circuitbreakers` - Circuit Breaker Status
### Health Endpoint
#### management.endpoint.health.show-details
- **Typ**: String
- **Default**: always
- **Mögliche Werte**: never, when-authorized, always
- **Beschreibung**: Zeigt detaillierte Health-Informationen
#### management.endpoint.health.show-components
- **Typ**: Boolean
- **Default**: always
- **Beschreibung**: Zeigt Health-Komponenten
#### management.endpoint.health.probes.enabled
- **Typ**: Boolean
- **Default**: true
- **Beschreibung**: Aktiviert Kubernetes Liveness/Readiness Probes
### Metrics
#### management.metrics.tags
- **Beschreibung**: Globale Tags für alle Metriken
- **Standard Tags**:
- application: ${spring.application.name}
- environment: ${spring.profiles.active}
- instance: ${spring.cloud.consul.discovery.instance-id}
- service: gateway
- component: infrastructure
- gateway: api-gateway
#### management.metrics.distribution.percentiles-histogram.http.server.requests
- **Typ**: Boolean
- **Default**: true
- **Beschreibung**: Aktiviert Histogram für Request-Zeiten
#### management.metrics.distribution.percentiles.http.server.requests
- **Typ**: Array[Double]
- **Default**: [0.5, 0.90, 0.95, 0.99]
- **Beschreibung**: Percentile-Werte für Request-Zeiten
### Tracing
#### management.tracing.enabled
- **Typ**: Boolean
- **Default**: false
- **Environment Variable**: `TRACING_ENABLED`
- **Beschreibung**: Aktiviert Distributed Tracing
#### management.tracing.sampling.probability
- **Typ**: Double (0.0 - 1.0)
- **Default**: 1.0
- **Environment Variable**: `TRACING_SAMPLING_PROBABILITY`
- **Beschreibung**: Sampling-Rate für Traces (1.0 = 100%)
#### management.zipkin.tracing.endpoint
- **Typ**: URL
- **Default**: <http://localhost:9411/api/v2/spans>
- **Environment Variable**: `ZIPKIN_TRACING_ENDPOINT`
- **Beschreibung**: Zipkin Server URL
**Beispiel:**
```yaml
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus,gateway,circuitbreakers
endpoint:
health:
show-details: always
probes:
enabled: true
tracing:
enabled: ${TRACING_ENABLED:false}
sampling:
probability: ${TRACING_SAMPLING_PROBABILITY:1.0}
zipkin:
tracing:
endpoint: ${ZIPKIN_TRACING_ENDPOINT:http://localhost:9411/api/v2/spans}
```
---
## Security
Die Security-Konfiguration erfolgt über Custom Properties unter `gateway.security`:
### gateway.security.publicPaths
- **Typ**: Array[String]
- **Default**: ["/", "/fallback/**", "/actuator/**", "/webjars/**", "/v3/api-docs/**", "/api/auth/**"]
- **Beschreibung**: Pfade, die ohne Authentifizierung zugänglich sind
### gateway.security.cors.allowedOriginPatterns
- **Typ**: Array[String]
- **Default**: ["http://localhost:[*]", "https://*.meldestelle.at"]
- **Beschreibung**: Erlaubte Origin-Patterns für CORS
### gateway.security.cors.allowedMethods
- **Typ**: Array[String]
- **Default**: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"]
- **Beschreibung**: Erlaubte HTTP-Methoden
### gateway.security.cors.allowedHeaders
- **Typ**: Array[String]
- **Default**: ["*"]
- **Beschreibung**: Erlaubte Request-Headers
### gateway.security.cors.exposedHeaders
- **Typ**: Array[String]
- **Default**: ["X-Correlation-ID", "X-RateLimit-Limit", "X-RateLimit-Remaining"]
- **Beschreibung**: Headers die an Client exponiert werden
### gateway.security.cors.allowCredentials
- **Typ**: Boolean
- **Default**: true
- **Beschreibung**: Erlaubt Credentials (Cookies, Auth-Header)
### gateway.security.cors.maxAge
- **Typ**: Duration
- **Default**: 1h
- **Beschreibung**: Cache-Zeit für CORS Preflight-Requests
**Beispiel:**
```yaml
gateway:
security:
publicPaths:
- "/"
- "/actuator/**"
- "/api/auth/**"
cors:
allowedOriginPatterns:
- "http://localhost:[*]"
- "https://*.meldestelle.at"
allowedMethods:
- GET
- POST
- PUT
- DELETE
allowCredentials: true
maxAge: 1h
```
### JWT Configuration
#### spring.security.oauth2.resourceserver.jwt.jwk-set-uri
- **Typ**: URL
- **Environment Variable**: `KEYCLOAK_JWK_SET_URI`
- **Beschreibung**: Keycloak JWK Set URI für JWT-Validierung
- **Beispiel**: <http://localhost:8180/realms/meldestelle/protocol/openid-connect/certs>
---
## Logging
### logging.level
- **Beschreibung**: Log-Level für verschiedene Pakete
**Standard Log-Levels:**
- `org.springframework.cloud.gateway`: INFO
- `org.springframework.cloud.loadbalancer`: DEBUG
- `org.springframework.cloud.consul`: INFO
- `at.mocode.infrastructure.gateway`: DEBUG
- `io.github.resilience4j`: INFO
- `reactor.netty.http.client`: INFO
- `org.springframework.security`: WARN
- `org.springframework.web`: INFO
### logging.pattern.console
- **Beschreibung**: Console-Log-Pattern mit Farben und Correlation-ID
### logging.pattern.file
- **Beschreibung**: File-Log-Pattern ohne Farben
### logging.file.name
- **Typ**: String
- **Default**: infrastructure/gateway/logs/gateway.log
- **Beschreibung**: Log-Datei Pfad
### logging.logback.rollingpolicy
- **clean-history-on-start**: true
- **max-file-size**: 100MB
- **total-size-cap**: 1GB
- **max-history**: 30 (Tage)
**Beispiel:**
```yaml
logging:
level:
at.mocode.infrastructure.gateway: DEBUG
org.springframework.cloud.gateway: INFO
file:
name: infrastructure/gateway/logs/gateway.log
logback:
rollingpolicy:
max-file-size: 100MB
max-history: 30
```
---
## Umgebungsvariablen Übersicht
### Kritische Variablen für Produktion
| Variable | Beschreibung | Default |
|----------|--------------|---------|
| `GATEWAY_PORT` | Gateway Port | 8081 |
| `CONSUL_HOST` | Consul Server | localhost |
| `CONSUL_PORT` | Consul Port | 8500 |
| `CONSUL_ENABLED` | Consul Aktivieren | true |
| `GATEWAY_ADMIN_USER` | Admin Username | admin |
| `GATEWAY_ADMIN_PASSWORD` | Admin Password | admin |
| `KEYCLOAK_JWK_SET_URI` | Keycloak JWK URI | <http://localhost:8180/>... |
| `TRACING_ENABLED` | Tracing aktivieren | false |
| `ZIPKIN_TRACING_ENDPOINT` | Zipkin Server | <http://localhost:9411/>... |
| `SPRING_PROFILES_ACTIVE` | Spring Profil | dev |
---
## Profile-spezifische Konfiguration
Das Gateway unterstützt verschiedene Spring Profile:
### dev (Development)
- Detailliertes Logging
- Alle Monitoring-Endpunkte verfügbar
- Tracing optional
### test
- Reduziertes Logging
- Test-spezifische Timeouts
- In-Memory Services optional
### prod (Production)
- Production-ready Logging
- Sichere Credentials erforderlich
- Tracing empfohlen
- Rate Limiting aktiviert
**Beispiel für profile-spezifische Datei:**
```yaml
# application-prod.yml
spring:
security:
user:
name: ${GATEWAY_ADMIN_USER} # Muss gesetzt sein!
password: ${GATEWAY_ADMIN_PASSWORD} # Muss gesetzt sein!
management:
tracing:
enabled: true
sampling:
probability: 0.1 # 10% Sampling in Production
logging:
level:
at.mocode.infrastructure.gateway: INFO # Weniger Logs
```
---
## Best Practices
1. **Umgebungsvariablen verwenden**: Nie Credentials in application.yml hardcoden
2. **Profile nutzen**: Separate Konfigurationen für dev/test/prod
3. **Health Checks aktivieren**: Für Consul und Kubernetes
4. **Tracing in Production**: Mindestens 10% Sampling
5. **Monitoring exportieren**: Prometheus-Endpunkt für Grafana
6. **Circuit Breaker tunen**: An Service-Charakteristiken anpassen
7. **CORS restriktiv**: Nur benötigte Origins erlauben
8. **Log Rotation**: Verhindert volle Festplatten
---
## Troubleshooting
### Gateway startet nicht
- ✅ Prüfen: Consul erreichbar?
- ✅ Prüfen: Port 8081 frei?
- ✅ Prüfen: Keycloak erreichbar? (Optional)
### Service nicht erreichbar
- ✅ Prüfen: Service in Consul registriert?
- ✅ Prüfen: Circuit Breaker offen?
- ✅ Prüfen: Health Check erfolgreich?
### CORS-Fehler
- ✅ Prüfen: Origin in allowedOriginPatterns?
- ✅ Prüfen: Methode in allowedMethods?
- ✅ Prüfen: allowCredentials korrekt?
### Hohe Latenz
- ✅ Prüfen: response-timeout zu hoch?
- ✅ Prüfen: Backend-Services langsam?
- ✅ Prüfen: Connection Pool ausgeschöpft?
---
## Weitere Ressourcen
- [Gateway README](README-INFRA-GATEWAY.md)
- [Spring Cloud Gateway Dokumentation](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/)
- [Resilience4j Dokumentation](https://resilience4j.readme.io/)
- [Consul Dokumentation](https://www.consul.io/docs)
@@ -1,442 +0,0 @@
# Infrastructure/Gateway Module - Comprehensive Documentation
## Überblick
Das API-Gateway ist der zentrale und einzige öffentliche Einstiegspunkt für alle Anfragen von externen Clients (z.B. Web-Anwendung, Desktop-Anwendung, mobile Apps) an das Meldestelle-System. Es fungiert als "Pförtner" für die gesamte Microservice-Landschaft und wurde zu einem vollwertigen, produktionstauglichen API Gateway mit modernen Best Practices erweitert.
**Wichtiger Grundsatz**: Kein externer Client sollte jemals direkt mit einem internen Microservice kommunizieren. Alle Anfragen laufen über das Gateway.
## Architektur und Technologie
Das Gateway ist als eigenständiger Spring Boot Service implementiert und nutzt Spring Cloud Gateway als technologische Grundlage. Spring Cloud Gateway ist ein reaktives, nicht-blockierendes Framework, das sich nahtlos in das Spring-Ökosystem integriert.
### Technologie-Stack
- **Spring Boot 3.x** - Moderne Spring Boot Anwendung
- **Spring Cloud Gateway** - Reaktives Gateway Framework
- **Spring WebFlux** - Reaktive Web-Programmierung mit Netty
- **Resilience4j** - Circuit Breaker Pattern Implementation
- **Consul** - Service Discovery und Health Checks
- **Micrometer + Prometheus** - Umfassende Metriken und Monitoring
- **JWT** - Token-basierte Authentifizierung
- **Reactive Streams** - Non-blocking I/O für optimale Performance
## Hauptverantwortlichkeiten
Das Gateway handhabt alle Cross-Cutting Concerns (übergreifende Belange), die für mehrere oder alle Microservices gelten und entlastet damit die Fach-Services von technischen Aufgaben.
### 1. Dynamisches Routing
- **Service Discovery Integration**: Vollständige Consul Integration für automatische Service-Erkennung
- **Load Balancing**: Intelligente Lastverteilung zwischen Service-Instanzen
- **Health-basiertes Routing**: Weiterleitung nur an gesunde Service-Instanzen
**Verfügbare Routen**:
- `/api/members/**` → members-service
- `/api/horses/**` → horses-service
- `/api/events/**` → events-service
- `/api/masterdata/**` → masterdata-service
- `/api/auth/**` → auth-service
- `/api/ping/**` → ping-service
### 2. Sicherheit und Authentifizierung
- **JWT Security Enforcement**: Validierung von Bearer Tokens für alle geschützten Endpunkte
- **Public Path Exemptions**: Konfigurierbare öffentliche Pfade (`/`, `/health`, `/actuator/**`, `/api/auth/login`)
- **User Context Injection**: Automatische Weiterleitung von User-ID und Rolle an Backend Services
- **Standardisierte Fehlerbehandlung**: Strukturierte 401 Unauthorized Responses
### 3. Rate Limiting
- **Intelligentes Rate Limiting** basierend auf User-Typ:
- **Anonymous Users**: 50 Anfragen pro Minute
- **Authenticated Users**: 200 Anfragen pro Minute
- **Admin Users**: 500 Anfragen pro Minute
- **IP-basierte Limits**: Schutz vor DDoS-Attacken
- **Custom Headers**: X-RateLimit-* Header für Client-Information
### 4. Circuit Breaker und Resilienz
- **Service-spezifische Circuit Breaker**: Resilience4j Integration für jeden Backend Service
- **Fallback Mechanismen**: Benutzerfreundliche Fehlermeldungen bei Service-Ausfällen
- **Retry Logic**: Automatische Wiederholungen bei transienten Fehlern
- **Graceful Degradation**: Systembetrieb auch bei partiellen Service-Ausfällen
### 5. Monitoring und Observability
Das Gateway implementiert umfassende Observability durch eine vollständig integrierte Micrometer-basierte Metriken-Architektur.
#### Automatische Metriken-Erfassung (GatewayMetricsConfig)
- **Request Duration Tracking**: Automatische Messung aller Request-Response Zyklen
- Metric: `gateway_request_duration` (Timer)
- Tags: method, path, status, status_series
- Percentile-basierte Auswertung (P50, P90, P95, P99)
- **Error Rate Monitoring**: Detailliertes Error-Tracking für 4xx/5xx Responses
- Metric: `gateway_errors_total` (Counter)
- Tags: method, path, status, status_series, error_type
- Unterscheidung zwischen client_error und server_error
- **Request Volume Tracking**: Vollständige Request-Volumen Überwachung
- Metric: `gateway_requests_total` (Counter)
- Tags: method, path für detaillierte Analyse
- **Circuit Breaker Events**: Monitoring von Resilience-Pattern Events
- Metric: `gateway_circuit_breaker_events_total` (Counter)
- Integration mit Resilience4j Circuit Breaker Status
#### Intelligente Pfad-Normalisierung
- **Kardinalitäts-Kontrolle**: Automatische Normalisierung von dynamischen Pfaden
- `/api/horses/123``/api/horses/{id}`
- UUID-Pattern → `/{uuid}`
- Sehr lange Pfade werden gekürzt (100+ Zeichen)
#### Health Monitoring Integration
- **Downstream Service Health**: Umfassende Überwachung aller Backend Services
- Kritische Services: Members, Horses, Events, Masterdata, Auth
- Optionale Services: Ping Service
- Circuit Breaker Status Integration
- **Distributed Tracing**: Korrelations-ID basiertes Request-Tracking
- **Strukturierte Logs**: JSON-Format für maschinelle Auswertung
#### Prometheus Export
- **Automatischer Export**: Alle Metriken werden automatisch an Prometheus exportiert
- **Common Tags**: Alle Metriken erhalten automatisch Service- und Component-Tags
- **Filter-Optimierung**: Rauschen-reduzierende Metrik-Filter für interne Spring/Netty Metriken
### 6. CORS-Management
- **Produktionstaugliche CORS-Konfiguration**:
- Erlaubte Origins: `https://*.meldestelle.at`, `http://localhost:*`
- Alle HTTP-Methoden (GET, POST, PUT, DELETE, PATCH, OPTIONS)
- Credential-Support für authentifizierte Anfragen
## Implementierte Optimierungen
### Gateway-Konfiguration (application.yml)
**Vollständige Service-Routen**: Routing für alle Business Services
**Circuit Breaker Integration**: Service-spezifische Resilience4j Konfigurationen
**Connection Pooling**: Optimierte HTTP-Client-Konfiguration
**Security Headers**: Umfassende Sicherheits-Header (X-Content-Type-Options, X-Frame-Options, X-XSS-Protection)
**Enhanced Logging**: Strukturierte Logs mit Korrelations-IDs und Performance-Daten
### Health Monitoring (GatewayHealthIndicator.kt)
**Downstream Service Monitoring**: Überwachung aller kritischen Services
**Service Discovery Integration**: Consul-basierte Service-Erkennung
**Test-Environment Handling**: Graceful Degradation in Test-Umgebungen
**Detailliertes Error Reporting**: Umfassende Statusinformationen
### Build-Optimierungen (build.gradle.kts)
**SINGLE SOURCE OF TRUTH**: Alle Dependencies über libs.versions.toml
**Build Info Generation**: Automatische Build-Metadaten
**Modern Kotlin Compiler**: Optimierte Compiler-Einstellungen
**Dependency Optimization**: Bereinigung redundanter Dependencies
### Docker-Optimierungen (Dockerfile)
**Multi-Stage Build**: Spring Boot Layer-Extraktion für 90%+ besseres Caching
**Security Hardening**: Non-root User, Security Updates
**OCI Compliance**: Vollständige Container-Metadaten
**Production-Ready**: Optimierte JVM-Settings für Container-Umgebung
### Metriken-Integration (GatewayMetricsConfig.kt)
**Comprehensive Micrometer Integration**: Vollständige Metriken-Erfassung mit automatischem Prometheus Export
**Request/Response Time Tracking**: Detaillierte Performance-Metriken mit Percentile-Auswertung
**Error Rate Monitoring**: Intelligente Fehler-Klassifikation und -Tracking
**Path Normalization**: Kardinalitäts-kontrolle für dynamische API-Pfade
**Circuit Breaker Metrics**: Integration mit Resilience4j Event-Tracking
**Custom Business Metrics**: Erweiterbare Metrik-Architektur für fachliche KPIs
### Dokumentation
**OpenAPI 3.0.3 Spezifikation**: Vollständige API-Dokumentation mit Members Service
**Interactive Swagger UI**: Modern dokumentierte API-Endpunkte
**Static HTML Documentation**: Responsive, moderne Dokumentations-Website
**Health Monitoring Integration**: Real-time Status-Informationen
## Performance und Reliability
### Netty Server Optimierungen
- **Connection Timeouts**: 5 Sekunden für optimale Responsiveness
- **Idle Timeout**: 15 Sekunden für effiziente Resource-Nutzung
- **Elastic Connection Pool**: Automatische Skalierung basierend auf Load
### Circuit Breaker Konfiguration
- **Sliding Window**: 100 Anfragen für Default, service-spezifische Anpassungen
- **Failure Rate Threshold**: 50% für Standard-Services, 30% für Auth-Service
- **Half-Open State**: 3 Test-Anfragen für Service-Recovery
### JVM Optimierungen (Container)
```bash
JAVA_OPTS="-server -Xmx512m -Xms256m -XX:+UseG1GC
-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
```
## API Gateway Request Flow
Ein typischer Anfrage-Flow:
1. **Client Request**: `https://api.meldestelle.at/api/members/123`
2. **Gateway Empfang**: Anfrage wird vom Spring Cloud Gateway empfangen
3. **Filter-Pipeline**:
- **Security Filter**: JWT-Validierung
- **Rate Limiting Filter**: Anfrage-Limits prüfen
- **Correlation Filter**: Trace-ID generieren
- **Logging Filter**: Request-Details erfassen
4. **Service Discovery**: Consul-Abfrage für verfügbare `members-service` Instanzen
5. **Load Balancing**: Intelligente Auswahl einer gesunden Instanz
6. **Circuit Breaker**: Überwachung der Service-Verfügbarkeit
7. **Request Forwarding**: Weiterleitung an Backend Service
8. **Response Processing**: Antwort-Verarbeitung und Header-Enrichment
9. **Client Response**: Strukturierte Antwort an Client
## Monitoring und Health Checks
### Actuator Endpunkte
- `/actuator/health` - Umfassender Health Status aller Services
- `/actuator/metrics` - Prometheus-kompatible Metriken
- `/actuator/info` - Anwendungs- und Build-Informationen
- `/actuator/gateway` - Gateway-spezifische Routing-Informationen
- `/actuator/circuitbreakers` - Circuit Breaker Status
### Key Performance Indicators (KPIs)
#### Automatisch erfasste Metriken
- **Request Throughput**: `gateway_requests_total` - Anfragen pro Sekunde nach Method/Path
- **Response Times**: `gateway_request_duration` - P50, P90, P95, P99 Percentile nach Status
- **Error Rates**: `gateway_errors_total` - 4xx/5xx Response Codes mit Error-Type Klassifikation
- **Circuit Breaker Events**: `gateway_circuit_breaker_events_total` - Resilience Pattern Aktivierungen
- **Service Availability**: Upstream Service Health via Health Indicators
#### Verfügbare Metric Tags für detaillierte Analyse
- **method**: HTTP-Method (GET, POST, PUT, DELETE, etc.)
- **path**: Normalisierter API-Pfad (z.B. `/api/horses/{id}`)
- **status**: HTTP-Status-Code (200, 404, 500, etc.)
- **status_series**: Status-Gruppe (2xx, 3xx, 4xx, 5xx)
- **error_type**: Fehler-Klassifikation (client_error, server_error)
- **service**: Automatisches "gateway" Tag
- **component**: Automatisches "infrastructure" Tag
#### Prometheus Query Beispiele
```promql
# Request Rate pro Endpunkt
rate(gateway_requests_total[5m])
# 95. Percentile Response Time
histogram_quantile(0.95, rate(gateway_request_duration_bucket[5m]))
# Error Rate nach Service
rate(gateway_errors_total[5m]) / rate(gateway_requests_total[5m])
# Circuit Breaker Aktivierungen
increase(gateway_circuit_breaker_events_total[1h])
```
## Security Features
### JWT Authentication
- **Bearer Token Validation**: Automatische JWT-Verifikation
- **Role Extraction**: User-Rolle für Backend Services verfügbar
- **Token Refresh**: Unterstützung für Token-Erneuerung
- **Public Endpoints**: Konfigurierbare Ausnahmen für öffentliche APIs
### Security Headers
```yaml
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Cache-Control: no-cache, no-store, must-revalidate
```
## Development und Testing
### Local Development
**WICHTIG:** Alle Befehle müssen aus dem Projekt-Root-Verzeichnis (`/home/stefan/WsMeldestelle/Meldestelle`) ausgeführt werden.
```bash
# Sicherstellen, dass Sie im richtigen Verzeichnis sind
cd /home/stefan/WsMeldestelle/Meldestelle
# Gateway starten
./gradlew :infrastructure:gateway:bootRun
# Mit Docker
docker build -t meldestelle/gateway:latest -f infrastructure/gateway/Dockerfile .
docker run -p 8081:8081 meldestelle/gateway:latest
```
📖 **Detaillierte Startup-Anleitung:** Siehe `GATEWAY-STARTUP-GUIDE.md` im Projekt-Root für vollständige Befehle und Fehlerbehebung.
### Testing
```bash
# Unit Tests
./gradlew :infrastructure:gateway:test
# Integration Tests (mit Testcontainers)
./gradlew :infrastructure:gateway:integrationTest
```
## Konfiguration
### Environment Variables
```bash
SPRING_PROFILES_ACTIVE=prod
CONSUL_HOST=consul.meldestelle.at
CONSUL_PORT=8500
GATEWAY_ADMIN_USER=admin
GATEWAY_ADMIN_PASSWORD=secure-password
```
### Profile-spezifische Konfiguration
- **dev**: Entwicklungsumgebung mit Debug-Logging
- **test**: Test-Umgebung mit Mock Services
- **prod**: Produktionsumgebung mit allen Security Features
## Deployment
### Docker Deployment
```bash
# Multi-stage Build mit Layer Caching
docker build -t meldestelle/gateway:1.0.0 \
-f infrastructure/gateway/Dockerfile .
# Container starten
docker run -d \
--name gateway \
-p 8081:8081 \
-e SPRING_PROFILES_ACTIVE=prod \
-e CONSUL_HOST=consul \
meldestelle/gateway:1.0.0
```
### Kubernetes Deployment
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
spec:
replicas: 3
selector:
matchLabels:
app: api-gateway
template:
spec:
containers:
- name: gateway
image: meldestelle/gateway:1.0.0
ports:
- containerPort: 8081
livenessProbe:
httpGet:
path: /actuator/health
port: 8081
initialDelaySeconds: 90
periodSeconds: 30
```
## Troubleshooting
### Häufige Probleme
**Service Discovery Issues**
- Consul Connectivity prüfen
- Service Registration Status überprüfen
- DNS Resolution testen
**Circuit Breaker Activation**
- Service Health Status prüfen
- Failure Rate Threshold analysieren
- Manual Circuit Breaker Reset über Actuator
**Performance Issues**
- Connection Pool Metrics analysieren
- JVM Heap Usage monitoring
- Request Rate Limiting überprüfen
**Metriken und Monitoring Issues**
- Prometheus Scraping Endpunkt prüfen: `/actuator/prometheus`
- Metrics Registry Status überprüfen: `/actuator/metrics`
- GatewayMetricsWebFilter Aktivierung validieren
- Metric Tags auf Kardinalitäts-Explosion prüfen
- Path Normalization bei unerwarteten Metric-Namen
### Logging und Debugging
```bash
# Logs mit Korrelations-IDs
docker logs gateway | grep "correlationId"
# Circuit Breaker Status
curl http://localhost:8081/actuator/circuitbreakers
# Health Details
curl http://localhost:8081/actuator/health
```
## Zukünftige Erweiterungen
### Geplante Features
- **OAuth2/OIDC Integration**: Erweiterte Authentifizierung
- **GraphQL Gateway**: Unified GraphQL Interface
- **Caching Layer**: Redis-basiertes Response Caching
- **Request/Response Transformation**: Dynamic Content Modification
### Performance Optimierungen
- **HTTP/2 Support**: Moderne Protocol-Unterstützung
- **Connection Pooling Tuning**: Erweiterte Pool-Konfiguration
- **Reactive Streams Optimization**: Backpressure Handling
## Dokumentation und Ressourcen
### API Dokumentation
- **Swagger UI**: `/swagger` - Interactive API Documentation
- **OpenAPI Spec**: `/openapi` - Machine-readable API Specification
- **Static Documentation**: `/docs` - Comprehensive Documentation Hub
### Monitoring Dashboards
- **Health Status**: `/actuator/health` - Real-time Service Health
- **Metrics**: `/actuator/metrics` - Prometheus Metrics
- **Gateway Routes**: `/actuator/gateway/routes` - Active Route Information
---
**Letzte Aktualisierung**: 14. August 2025
**Version**: 1.1.0
**Maintainer**: Meldestelle Development Team
---
Diese Dokumentation wurde umfassend aktualisiert und um die neue Micrometer Metrics Integration (GatewayMetricsConfig.kt) erweitert. Sie dokumentiert alle implementierten Optimierungen einschließlich der vollständigen Observability-Architektur mit automatischer Request/Response Zeit Messung, Error Rate Tracking und Custom Business Metrics.
@@ -27,7 +27,7 @@ dependencies {
// Stellt sicher, dass alle Versionen aus der zentralen BOM kommen.
api(platform(projects.platform.platformBom))
// Implementiert die provider-agnostische Caching-API.
implementation(projects.infrastructure.cache.cacheApi)
implementation(projects.backend.infrastructure.cache.cacheApi)
// OPTIMIERUNG: Verwendung des `redis-cache`-Bundles aus libs.versions.toml.
// Dieses Bundle enthält Spring Data Redis, Lettuce und Jackson-Module.
implementation(libs.bundles.redis.cache)
@@ -22,7 +22,7 @@ dependencies {
// Stellt sicher, dass alle Versionen aus der zentralen BOM kommen
implementation(platform(projects.platform.platformBom))
// Implementiert die provider-agnostische Event-Store-API
api(projects.infrastructure.eventStore.eventStoreApi)
api(projects.backend.infrastructure.eventStore.eventStoreApi)
// Benötigt Zugriff auf Core-Module für Domänen-Events und Utilities
implementation(projects.core.coreDomain)
implementation(projects.core.coreUtils)
@@ -43,8 +43,8 @@ dependencies {
testImplementation(libs.kotlinx.serialization.json)
testImplementation(libs.reactor.test)
// Für Integration Tests mit beiden Redis-Modulen
testImplementation(projects.infrastructure.cache.cacheApi)
testImplementation(projects.infrastructure.cache.redisCache)
testImplementation(projects.backend.infrastructure.cache.cacheApi)
testImplementation(projects.backend.infrastructure.cache.redisCache)
}
// === Task Configuration ===
@@ -23,8 +23,8 @@ ARG VERSION
FROM gradle:${GRADLE_VERSION}-jdk${JAVA_VERSION}-alpine AS builder
# Re-declare build arguments for this stage
ARG BUILD_DATE
ARG VERSION
ARG BUILD_DATE
LABEL stage=builder
LABEL service="api-gateway"
@@ -57,6 +57,7 @@ RUN chmod +x gradlew
COPY platform/ platform/
COPY core/ core/
# Copy infrastructure directories (required by settings.gradle.kts)
# Copy infrastructure directories (required by settings.gradle.kts)
COPY infrastructure/ infrastructure/
@@ -65,6 +66,7 @@ COPY domains/ domains/
# Copy services directories (required by settings.gradle.kts)
COPY services/ services/
COPY backend/ backend/
# Copy client directories (required by settings.gradle.kts)
COPY clients/ clients/
@@ -78,16 +80,16 @@ COPY build.gradle.kts ./
# Download and cache dependencies with BuildKit cache mount (removed deprecated flag)
RUN --mount=type=cache,target=/home/gradle/.gradle/caches \
--mount=type=cache,target=/home/gradle/.gradle/wrapper \
./gradlew :infrastructure:gateway:dependencies --info
./gradlew :backend:gateway:dependencies --info
# Build the application with optimizations and build cache (removed deprecated flag)
RUN --mount=type=cache,target=/home/gradle/.gradle/caches \
--mount=type=cache,target=/home/gradle/.gradle/wrapper \
./gradlew :infrastructure:gateway:bootJar --info
./gradlew :backend:gateway:bootJar --info
# Extract JAR layers for better caching in runtime stage
RUN mkdir -p build/dependency && \
(cd build/dependency; java -Djarmode=layertools -jar /workspace/infrastructure/gateway/build/libs/*.jar extract)
(cd build/dependency; java -Djarmode=layertools -jar /workspace/backend/gateway/build/libs/*.jar extract)
# ===================================================================
# Runtime Stage
@@ -19,7 +19,7 @@ dependencies {
// === Core Dependencies ===
implementation(projects.core.coreUtils)
implementation(projects.platform.platformDependencies)
implementation(projects.infrastructure.monitoring.monitoringClient)
implementation(projects.backend.infrastructure.monitoring.monitoringClient)
// === GATEWAY-SPEZIFISCHE ABHÄNGIGKEITEN ===
implementation(libs.bundles.spring.cloud.gateway)

Some files were not shown because too many files have changed in this diff Show More