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
+63
View File
@@ -0,0 +1,63 @@
# ==========================================
# Meldestelle - Environment Configuration
# ==========================================
# Profil: DEVELOPMENT (Lokal)
# --- PROJEKT EINSTELLUNGEN ---
COMPOSE_PROJECT_NAME=meldestelle
# Restart Policy: 'no' für Dev (Fehler sehen), 'always' für Prod
# RESTART_POLICY=no
# --- POSTGRESQL (Datenbank) ---
POSTGRES_USER=pg-user
POSTGRES_PASSWORD=pg-password
POSTGRES_DB=meldestelle
# Port Mapping: Host:Container.
# Prod: 127.0.0.1:5432 (nur localhost) oder leer lassen
POSTGRES_PORT=5432:5432
# --- REDIS (Cache) ---
# Prod: 127.0.0.1:6379 oder leer lassen
REDIS_PORT=6379:6379
# --- KEYCLOAK (Identity Provider) ---
KC_ADMIN_USER=kc-admin
KC_ADMIN_PASSWORD=kc-password
KC_HOSTNAME=localhost
KC_PORT=8180:8080
# --- PGADMIN (DB GUI) ---
PGADMIN_EMAIL=user@domain.com
PGADMIN_PASSWORD=strong-password
PGADMIN_PORT=8888:80
# --- PROMETHEUS (Metriken) ---
PROMETHEUS_PORT=9090:9090
# --- GRAFANA (Monitoring GUI) ---
GF_ADMIN_USER=gf-admin
GF_ADMIN_PASSWORD=gf-password
GF_PORT=3000:3000
# --- SERVICE DISCOVERY (Consul) ---
CONSUL_PORT=8500:8500
# --- API GATEWAY ---
GATEWAY_PORT=8081:8081
GATEWAY_DEBUG_PORT=5005:5005
GATEWAY_SERVER_PORT=8081
# --- MICROSERVICES ---
PING_SERVICE_PORT=8082:8082
PING_DEBUG_PORT=5006:5006
# --- WEB CLIENTS ---
# Web-App (Nginx inside container listens on 80)
WEB_APP_PORT=8080:80
# Desktop-App (VNC + noVNC)
DESKTOP_APP_VNC_PORT=5901:5901
DESKTOP_APP_NOVNC_PORT=6080:6080
# Optional: Redis Passwort aktivieren (setzt --requirepass)
# REDIS_PASSWORD=change-me-strong
+49
View File
@@ -1,3 +1,31 @@
<<<<<<< HEAD
# ==========================================
# Meldestelle Docker Compose Environment
# Single Source of Truth (SSoT)
# ==========================================
# --- PROJECT ---
COMPOSE_PROJECT_NAME=meldestelle
# --- PORT MAPPINGS (host:container) ---
POSTGRES_PORT=5432:5432
REDIS_PORT=6379:6379
KC_PORT=8180:8080
PGADMIN_PORT=8888:80
PROMETHEUS_PORT=9090:9090
GF_PORT=3000:3000
CONSUL_PORT=8500:8500
GATEWAY_PORT=8081:8081
GATEWAY_DEBUG_PORT=5005:5005
GATEWAY_SERVER_PORT=8081
PING_SERVICE_PORT=8082:8082
PING_DEBUG_PORT=5006:5006
WEB_APP_PORT=4000:4000
DESKTOP_APP_VNC_PORT=5901:5901
DESKTOP_APP_NOVNC_PORT=6080:6080
# --- POSTGRES ---
=======
# Core project name used as prefix for container names
COMPOSE_PROJECT_NAME=meldestelle
@@ -18,15 +46,35 @@ DESKTOP_APP_VNC_PORT=5900:5900
DESKTOP_APP_NOVNC_PORT=6080:6080
# Postgres
>>>>>>> origin/main
POSTGRES_USER=meldestelle
POSTGRES_PASSWORD=meldestelle
POSTGRES_DB=meldestelle
<<<<<<< HEAD
# --- REDIS ---
# Optional password for Redis; leave empty to disable authentication in dev
REDIS_PASSWORD=
# --- KEYCLOAK ---
=======
# Keycloak
>>>>>>> origin/main
KC_ADMIN_USER=admin
KC_ADMIN_PASSWORD=admin
KC_HOSTNAME=localhost
<<<<<<< HEAD
# --- PGADMIN ---
PGADMIN_EMAIL=admin@example.com
PGADMIN_PASSWORD=admin
# --- GRAFANA ---
GF_ADMIN_USER=admin
GF_ADMIN_PASSWORD=admin
# --- DOCKER BUILD OVERRIDES (optional) ---
=======
# PgAdmin
PGADMIN_EMAIL=admin@example.com
PGADMIN_PASSWORD=admin
@@ -36,6 +84,7 @@ GF_ADMIN_USER=admin
GF_ADMIN_PASSWORD=admin
# Docker build versions (optional overrides)
>>>>>>> origin/main
DOCKER_GRADLE_VERSION=9.1.0
DOCKER_JAVA_VERSION=21
DOCKER_NODE_VERSION=22.21.0
+153
View File
@@ -0,0 +1,153 @@
name: meldestelle-hardcoded
services:
# --- DATENBANK ---
postgres:
image: postgres:16-alpine
container_name: meldestelle-postgres
restart: unless-stopped
ports:
- "5432:5432"
environment:
POSTGRES_USER: pg-user
POSTGRES_PASSWORD: pg-password
POSTGRES_DB: meldestelle
volumes:
- postgres-data:/var/lib/postgresql/data
# Falls du Init-Scripte hast, lassen wir die erstmal weg,
# um Fehlerquellen zu reduzieren, oder lassen den Pfad, falls er existiert:
- ./docker/core/postgres:/docker-entrypoint-initdb.d:Z
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U pg-user -d meldestelle" ]
interval: 1s
timeout: 5s
retries: 3
start_period: 30s
networks:
- meldestelle-network
# --- DATENBANK-MANAGEMENT-TOOL ---
pgadmin:
image: dpage/pgadmin4:8
container_name: pgadmin4_container
restart: unless-stopped
ports:
- "8888:80"
environment:
PGADMIN_DEFAULT_EMAIL: user@domain.com
PGADMIN_DEFAULT_PASSWORD: strong-password
volumes:
- pgadmin-data:/var/lib/pgadmin
healthcheck:
test: [ "CMD-SHELL", "wget --spider -q http://localhost:80/ || exit 1" ]
interval: 1s
timeout: 5s
retries: 3
start_period: 30s
networks:
- meldestelle-network
# --- CACHE ---
redis:
image: redis:7-alpine
container_name: meldestelle-redis
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yes
healthcheck:
test: [ "CMD", "redis-cli" ]
interval: 1s
timeout: 5s
retries: 3
networks:
- meldestelle-network
# --- IDENTITY PROVIDER (Wartet auf Postgres) ---
keycloak:
image: quay.io/keycloak/keycloak:26.4
container_name: meldestelle-keycloak
restart: unless-stopped
environment:
KC_HEALTH_ENABLED: true
KC_METRICS_ENABLED: true
KC_BOOTSTRAP_ADMIN_USERNAME: kc-admin
KC_BOOTSTRAP_ADMIN_PASSWORD: kc-password
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/meldestelle
KC_DB_USERNAME: pg-user
KC_DB_PASSWORD: pg-password
KC_HOSTNAME: localhost
ports:
- "8180:8080"
depends_on:
postgres:
condition: service_healthy
volumes:
- ./docker/core/keycloak:/opt/keycloak/data/import:Z
command: start-dev --import-realm
healthcheck:
test: [ "CMD-SHELL", "exec 3<>/dev/tcp/127.0.0.1/9000" ]
interval: 20s
timeout: 10s
retries: 5
start_period: 60s
networks:
- meldestelle-network
# --- MONITORING ---
prometheus:
image: prom/prometheus:v2.54.1
container_name: meldestelle-prometheus
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- prometheus-data:/prometheus
- ./docker/monitoring/prometheus:/etc/prometheus:Z
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.retention.time=15d
healthcheck:
test: [ "CMD", "wget", "--spider", "-q", "http://localhost:9090/-/healthy" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
- meldestelle-network
grafana:
image: grafana/grafana:11.3.0
container_name: meldestelle-grafana
environment:
GF_SECURITY_ADMIN_USER: gf-admin
GF_SECURITY_ADMIN_PASSWORD: gf-password
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
- ./docker/monitoring/grafana:/etc/grafana/provisioning:Z
depends_on:
- prometheus
healthcheck:
test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
- meldestelle-network
volumes:
postgres-data:
pgadmin-data:
redis-data:
prometheus-data:
grafana-data:
networks:
meldestelle-network:
driver: bridge
+36
View File
@@ -0,0 +1,36 @@
# syntax=docker/dockerfile:1.8
# ===================================================================
# Production-Ready Keycloak Dockerfile
# ===================================================================
# Based on: quay.io/keycloak/keycloak:26.4.2
# Features:
# - Pre-built optimized image (faster startup)
# - Security hardening
# - Custom theme support
# - Health monitoring
# ===================================================================
ARG KEYCLOAK_IMAGE_TAG
FROM quay.io/keycloak/keycloak:${KEYCLOAK_IMAGE_TAG}
LABEL maintainer="Meldestelle Development Team"
LABEL description="Production-ready Keycloak for Meldestelle authentication"
LABEL version="${KEYCLOAK_IMAGE_TAG}"
# Set environment variables for build
ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
ENV KC_DB=postgres
WORKDIR /opt/keycloak
# Pre-build Keycloak for faster startup
RUN /opt/keycloak/bin/kc.sh build \
--db=postgres \
--health-enabled=true \
--metrics-enabled=true
# Set user
USER 1000
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
@@ -17,6 +17,10 @@ services:
volumes:
- postgres-data:/var/lib/postgresql/data
- ./core/postgres:/docker-entrypoint-initdb.d:Z
# Central postgres.conf from config (optional)
- ../config/postgres/postgresql.conf:/etc/postgresql/postgresql.conf:Z
# Use central postgresql.conf if present
command: ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"]
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" ]
interval: 5s
@@ -36,7 +40,10 @@ services:
- "${REDIS_PORT}"
volumes:
- redis-data:/data
command: redis-server --appendonly yes
# Central redis config
- ../config/redis/redis.conf:/usr/local/etc/redis/redis.conf:Z
# Use central redis.conf and optionally add --requirepass if REDIS_PASSWORD is set
command: ["sh", "-lc", "exec redis-server /usr/local/etc/redis/redis.conf ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}"]
healthcheck:
test: [ "CMD", "redis-cli" ]
interval: 5s
@@ -112,7 +119,8 @@ services:
- "${PROMETHEUS_PORT}"
volumes:
- prometheus-data:/prometheus
- ./monitoring/prometheus:/etc/prometheus:Z
# Use central config as single source of truth
- ../config/monitoring/prometheus:/etc/prometheus:Z
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.retention.time=15d
@@ -138,7 +146,10 @@ services:
- "${GF_PORT}"
volumes:
- grafana-data:/var/lib/grafana
- ./monitoring/grafana:/etc/grafana/provisioning:Z
# Provisioning (datasources/dashboards) from central config
- ../config/monitoring/grafana/provisioning:/etc/grafana/provisioning:Z
# Dashboards directory (referenced by provisioning file path: /var/lib/grafana/dashboards)
- ../config/monitoring/grafana/dashboards:/var/lib/grafana/dashboards:Z
depends_on:
- prometheus
healthcheck:
@@ -176,7 +187,7 @@ services:
api-gateway:
build:
context: ..
dockerfile: dockerfiles/infrastructure/gateway/Dockerfile
dockerfile: backend/infrastructure/gateway/Dockerfile
args:
# Build-Args aus deinen .env Dateien (werden hier statisch benötigt für den Build)
GRADLE_VERSION: 9.1.0
@@ -195,13 +206,13 @@ services:
# --- VERBINDUNGEN ---
# Keycloak URL (INTERN im Docker Netzwerk!)
# Beachte: http://container-name:8080 (nicht localhost, nicht 8180)
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: http://${COMPOSE_PROJECT_NAME}-keycloak:8080/realms/meldestelle
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: http://keycloak:8080/realms/meldestelle
SPRING_CLOUD_CONSUL_HOST: consul
SPRING_CLOUD_CONSUL_PORT: 8500
# WICHTIG: Das Gateway muss wissen, wie es von anderen Containern erreicht wird (nicht localhost!)
SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME: api-gateway
# Postgres Verbindung (für Routes/Session, falls nötig)
SPRING_DATASOURCE_URL: jdbc:postgresql://${COMPOSE_PROJECT_NAME}-postgres:5432/${POSTGRES_DB}
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB}
SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER}
SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD}
# Logging
@@ -225,7 +236,7 @@ services:
ping-service:
build:
context: ..
dockerfile: dockerfiles/services/ping-service/Dockerfile
dockerfile: backend/services/ping/Dockerfile
args:
GRADLE_VERSION: 9.1.0
JAVA_VERSION: 21
@@ -247,13 +258,13 @@ services:
SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME: ping-service
# - DATENBANK VERBINDUNG -
SPRING_DATASOURCE_URL: jdbc:postgresql://${COMPOSE_PROJECT_NAME}-postgres:5432/${POSTGRES_DB}
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB}
SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER}
SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD}
SPRING_JPA_HIBERNATE_DDL_AUTO: validate
# --- REDIS ---
SPRING_DATA_REDIS_HOST: ${COMPOSE_PROJECT_NAME}-redis
SPRING_DATA_REDIS_HOST: redis
SPRING_DATA_REDIS_PORT: 6379
depends_on:
consul:
@@ -273,7 +284,7 @@ services:
web-app:
build:
context: ..
dockerfile: dockerfiles/clients/web-app/Dockerfile
dockerfile: docker/frontends/web-app/Dockerfile
args:
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION:-9.1.0}
JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21}
@@ -284,6 +295,9 @@ services:
restart: unless-stopped
ports:
- "${WEB_APP_PORT}"
volumes:
# Mount production nginx config (can be adjusted per env)
- ../config/nginx/nginx.prod.conf:/etc/nginx/nginx.conf:Z,ro
depends_on:
api-gateway:
condition: service_started
@@ -295,7 +309,7 @@ services:
desktop-app:
build:
context: ..
dockerfile: dockerfiles/clients/desktop-app/Dockerfile
dockerfile: docker/frontends/desktop-app/Dockerfile
container_name: ${COMPOSE_PROJECT_NAME}-desktop-app
restart: unless-stopped
environment:
+94
View File
@@ -0,0 +1,94 @@
# ===================================================================
# Multi-Stage Dockerfile für Meldestelle Desktop-App (VNC)
# ===================================================================
# ===================================================================
# Stage 1: Build Stage - Kotlin Desktop-App kompilieren
# ===================================================================
FROM gradle:8-jdk21-alpine AS builder
WORKDIR /app
# Kopiere Gradle-Konfiguration und Wrapper
COPY build.gradle.kts settings.gradle.kts gradle.properties ./
COPY gradle ./gradle
COPY gradlew ./
# Kopiere alle notwendigen Module für Multi-Modul-Projekt
COPY frontend ./frontend
COPY backend ./backend
COPY core ./core
COPY domains ./domains
COPY platform ./platform
COPY docs ./docs
# Setze Gradle-Wrapper Berechtigung
RUN chmod +x ./gradlew
# Dependencies downloaden (für besseres Caching)
RUN ./gradlew :frontend:shells:meldestelle-portal:dependencies --no-configure-on-demand
# Desktop-App kompilieren (createDistributable für native Distribution)
RUN ./gradlew :frontend:shells:meldestelle-portal:createDistributable --no-configure-on-demand
# ===================================================================
# Stage 2: Runtime Stage - Ubuntu mit VNC + noVNC
# ===================================================================
FROM ubuntu:22.04
# Verhindere interaktive Installationen
ENV DEBIAN_FRONTEND=noninteractive
# Installiere System-Dependencies
RUN apt-get update && apt-get install -y \
openjdk-21-jdk \
xvfb \
x11vnc \
novnc \
websockify \
xfce4 \
xfce4-goodies \
curl \
wget \
unzip \
supervisor \
&& rm -rf /var/lib/apt/lists/*
# Arbeitsverzeichnis
WORKDIR /app
# Kopiere kompilierte Desktop-App von Build-Stage
COPY --from=builder /app/frontend/shells/meldestelle-portal/build/compose/binaries/main/desktop/ ./desktop-app/
# Kopiere Scripts
COPY dockerfiles/clients/desktop-app/entrypoint.sh /entrypoint.sh
COPY dockerfiles/clients/desktop-app/health-check.sh /opt/health-check.sh
COPY dockerfiles/clients/desktop-app/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Setze Permissions
RUN chmod +x /entrypoint.sh /opt/health-check.sh
# Erstelle VNC-User
RUN useradd -m -s /bin/bash vncuser && \
mkdir -p /home/vncuser/.vnc && \
chown -R vncuser:vncuser /home/vncuser && \
chown -R vncuser:vncuser /app
# VNC und noVNC Ports
EXPOSE 5901 6080
# Environment Variables
ENV DISPLAY=:99
ENV VNC_PORT=5901
ENV NOVNC_PORT=6080
ENV API_BASE_URL=http://api-gateway:8081
# Health-Check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD /opt/health-check.sh
# User wechseln
USER vncuser
# Entrypoint
ENTRYPOINT ["/entrypoint.sh"]
+104
View File
@@ -0,0 +1,104 @@
#!/bin/bash
# ===================================================================
# Entrypoint-Script für Meldestelle Desktop-App (VNC)
# ===================================================================
set -e
# Logging-Funktion
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
log "Starting Meldestelle Desktop-App VNC Container..."
# Environment-Variablen setzen
export DISPLAY=${DISPLAY:-:99}
export VNC_PORT=${VNC_PORT:-5901}
export NOVNC_PORT=${NOVNC_PORT:-6080}
export API_BASE_URL=${API_BASE_URL:-http://api-gateway:8081}
log "Environment:"
log " DISPLAY: $DISPLAY"
log " VNC_PORT: $VNC_PORT"
log " NOVNC_PORT: $NOVNC_PORT"
log " API_BASE_URL: $API_BASE_URL"
# Erstelle .Xauthority wenn nicht vorhanden
touch /home/vncuser/.Xauthority
# 1. Starte X11 Virtual Display (Xvfb)
log "Starting Xvfb on display $DISPLAY..."
Xvfb $DISPLAY -screen 0 1280x1024x24 -ac +extension GLX +render -noreset &
XVFB_PID=$!
# Warte bis X11 bereit ist
sleep 3
# 2. Starte Desktop Environment (XFCE4)
log "Starting XFCE4 desktop environment..."
startxfce4 &
XFCE_PID=$!
# Warte bis Desktop bereit ist
sleep 5
# 3. Starte VNC Server
log "Starting VNC server on port $VNC_PORT..."
x11vnc -display $DISPLAY -forever -usepw -create -rfbport $VNC_PORT -nopw -shared -bg
VNC_PID=$!
# 4. Starte noVNC Web Interface
log "Starting noVNC web interface on port $NOVNC_PORT..."
websockify --web=/usr/share/novnc/ $NOVNC_PORT localhost:$VNC_PORT &
NOVNC_PID=$!
# 5. Warte bis Services bereit sind
sleep 10
# 6. Starte Desktop-App
log "Starting Meldestelle Desktop-App..."
cd /app/desktop-app
export API_BASE_URL=$API_BASE_URL
# Finde die ausführbare Datei
if [ -f "client/bin/client" ]; then
DESKTOP_APP="client/bin/client"
elif [ -f "bin/client" ]; then
DESKTOP_APP="bin/client"
elif [ -f "client" ]; then
DESKTOP_APP="client"
else
log "ERROR: Desktop-App executable not found!"
log "Contents of /app/desktop-app:"
ls -la /app/desktop-app/
exit 1
fi
log "Found desktop app: $DESKTOP_APP"
chmod +x "$DESKTOP_APP"
# Starte Desktop-App
./"$DESKTOP_APP" &
APP_PID=$!
log "All services started successfully!"
log "VNC: vnc://localhost:$VNC_PORT"
log "noVNC: http://localhost:$NOVNC_PORT/vnc.html"
# Cleanup-Funktion
cleanup() {
log "Shutting down services..."
kill $APP_PID 2>/dev/null || true
kill $NOVNC_PID 2>/dev/null || true
kill $VNC_PID 2>/dev/null || true
kill $XFCE_PID 2>/dev/null || true
kill $XVFB_PID 2>/dev/null || true
exit 0
}
# Signal-Handler
trap cleanup SIGTERM SIGINT
# Warten auf Prozesse
wait $APP_PID
@@ -0,0 +1,63 @@
#!/bin/bash
# ===================================================================
# Health-Check-Script für Meldestelle Desktop-App (VNC)
# ===================================================================
set -e
# Environment-Variablen
VNC_PORT=${VNC_PORT:-5901}
NOVNC_PORT=${NOVNC_PORT:-6080}
DISPLAY=${DISPLAY:-:99}
# Logging-Funktion
log() {
echo "[HEALTH] $1"
}
# 1. Überprüfe X11 Display
if ! xdpyinfo -display $DISPLAY >/dev/null 2>&1; then
log "ERROR: X11 display $DISPLAY is not running"
exit 1
fi
log "✓ X11 display $DISPLAY is running"
# 2. Überprüfe VNC Server
if ! netstat -ln | grep -q ":$VNC_PORT "; then
log "ERROR: VNC server is not listening on port $VNC_PORT"
exit 1
fi
log "✓ VNC server is running on port $VNC_PORT"
# 3. Überprüfe noVNC Web Interface
if ! curl -f -s "http://localhost:$NOVNC_PORT/" > /dev/null 2>&1; then
log "ERROR: noVNC web interface is not responding on port $NOVNC_PORT"
exit 1
fi
log "✓ noVNC web interface is running on port $NOVNC_PORT"
# 4. Überprüfe ob Desktop-App läuft (optional, da sie crashen könnte)
if pgrep -f "client" >/dev/null 2>&1; then
log "✓ Desktop-App is running"
else
log "⚠ Desktop-App is not running (may have crashed or not started yet)"
# Nicht als Fehler behandeln, da die App crashen könnte
fi
# 5. Überprüfe Xvfb
if ! pgrep -f "Xvfb" >/dev/null 2>&1; then
log "ERROR: Xvfb is not running"
exit 1
fi
log "✓ Xvfb is running"
# 6. Überprüfe XFCE4
if ! pgrep -f "xfce4" >/dev/null 2>&1; then
log "WARNING: XFCE4 desktop might not be running"
# Nicht als kritischer Fehler behandeln
else
log "✓ XFCE4 desktop environment is running"
fi
log "All critical services are healthy"
exit 0
@@ -0,0 +1,54 @@
[supervisord]
nodaemon=true
user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
[program:xvfb]
command=Xvfb :99 -screen 0 1280x1024x24 -ac +extension GLX +render -noreset
user=vncuser
autostart=true
autorestart=true
priority=100
stdout_logfile=/var/log/supervisor/xvfb.log
stderr_logfile=/var/log/supervisor/xvfb.log
[program:xfce4]
command=startxfce4
user=vncuser
environment=DISPLAY=":99"
autostart=true
autorestart=true
priority=200
stdout_logfile=/var/log/supervisor/xfce4.log
stderr_logfile=/var/log/supervisor/xfce4.log
[program:vnc]
command=x11vnc -display :99 -forever -usepw -create -rfbport 5901 -nopw -shared
user=vncuser
environment=DISPLAY=":99"
autostart=true
autorestart=true
priority=300
stdout_logfile=/var/log/supervisor/vnc.log
stderr_logfile=/var/log/supervisor/vnc.log
[program:novnc]
command=websockify --web=/usr/share/novnc/ 6080 localhost:5901
user=vncuser
autostart=true
autorestart=true
priority=400
stdout_logfile=/var/log/supervisor/novnc.log
stderr_logfile=/var/log/supervisor/novnc.log
[program:desktop-app]
command=/app/desktop-app/client/bin/client
user=vncuser
environment=DISPLAY=":99",API_BASE_URL="http://api-gateway:8081"
directory=/app/desktop-app
autostart=true
autorestart=false
priority=500
stdout_logfile=/var/log/supervisor/desktop-app.log
stderr_logfile=/var/log/supervisor/desktop-app.log
+83
View File
@@ -0,0 +1,83 @@
# ===================================================================
# Multi-Stage Dockerfile für Meldestelle Web-App (Kotlin/JS)
# ===================================================================
# ===================================================================
# Stage 1: Build Stage - Kotlin/JS kompilieren
# ===================================================================
# Build args (build-time only)
ARG GRADLE_VERSION
ARG JAVA_VERSION
ARG NODE_VERSION
ARG NGINX_IMAGE_TAG=1.28.0-alpine
# Toggle build profile: dev (default) or prod
ARG WEB_BUILD_PROFILE=dev
FROM gradle:${GRADLE_VERSION}-jdk${JAVA_VERSION} AS builder
# Install Node.js (version aligned with versions.toml)
# Derive major version from NODE_VERSION (e.g., 22.21.0 -> setup_22.x)
RUN apt-get update && apt-get install -y curl && \
NODE_MAJOR=$(echo "$NODE_VERSION" | cut -d. -f1) && \
curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash - && \
apt-get install -y nodejs && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Kopiere Gradle-Konfiguration und Wrapper
COPY build.gradle.kts settings.gradle.kts gradle.properties ./
COPY gradle ./gradle
COPY gradlew ./
# Kopiere alle notwendigen Module für Multi-Modul-Projekt
COPY frontend ./frontend
COPY backend ./backend
COPY core ./core
COPY domains ./domains
COPY platform ./platform
COPY docs ./docs
# Setze Gradle-Wrapper Berechtigung
RUN chmod +x ./gradlew
# Dependencies downloaden (für besseres Caching)
RUN ./gradlew :frontend:shells:meldestelle-portal:dependencies --no-configure-on-demand
# Kotlin/JS Web-App kompilieren (Profil wählbar über WEB_BUILD_PROFILE)
# - dev → jsBrowserDevelopmentExecutable (schneller, Source Maps)
# - prod → jsBrowserDistribution (minifiziert, optimiert)
RUN if [ "$WEB_BUILD_PROFILE" = "prod" ]; then \
./gradlew :frontend:shells:meldestelle-portal:jsBrowserDistribution --no-configure-on-demand -Pproduction=true; \
mkdir -p /app/web-dist && cp -r frontend/shells/meldestelle-portal/build/dist/js/productionExecutable/* /app/web-dist/; \
else \
./gradlew :frontend:shells:meldestelle-portal:jsBrowserDevelopmentExecutable --no-configure-on-demand; \
mkdir -p /app/web-dist && cp -r frontend/shells/meldestelle-portal/build/dist/js/developmentExecutable/* /app/web-dist/; \
fi
# ===================================================================
# Stage 2: Runtime Stage - Nginx für Static Files + API Proxy
# ===================================================================
# Build arg controls runtime base image tag (declared globally to allow usage in FROM)
FROM nginx:${NGINX_IMAGE_TAG}
# Installiere curl für Health-Checks
RUN apk add --no-cache curl
# Kopiere kompilierte Web-App von Build-Stage (vereinheitlichtes Ausgabeverzeichnis)
COPY --from=builder /app/web-dist/ /usr/share/nginx/html/
# Kopiere Nginx-Konfiguration
COPY dockerfiles/clients/web-app/nginx.conf /etc/nginx/nginx.conf
# Exponiere Port 4000 (statt Standard 80)
EXPOSE 4000
# Downloads (Platzhalter) ausliefern lassen
COPY dockerfiles/clients/web-app/downloads/ /usr/share/nginx/html/downloads/
# Health-Check für Container
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:4000/ || exit 1
# Starte Nginx
CMD ["nginx", "-g", "daemon off;"]
@@ -0,0 +1,30 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Meldestelle Desktop Downloads (Platzhalter)</title>
<style>
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, 'Helvetica Neue', Arial, 'Noto Sans', 'Liberation Sans', sans-serif; margin: 2rem; }
h1 { margin-bottom: .25rem; }
.muted { color: #666; }
ul { line-height: 1.8; }
.card { border: 1px solid #e5e7eb; border-radius: 8px; padding: 1rem 1.25rem; max-width: 720px; }
</style>
</head>
<body>
<h1>Desktop Downloads</h1>
<p class="muted">Platzhalter-Verzeichnis. Hier können zukünftig Installer/Archive der Desktop-App bereitgestellt werden.</p>
<div class="card">
<p>Lege deine Dateien in dieses Verzeichnis im Repository:</p>
<pre><code>dockerfiles/clients/web-app/downloads/</code></pre>
<p>Oder mounte in Docker Compose ein Host-Verzeichnis auf <code>/usr/share/nginx/html/downloads</code>.</p>
<p>Beispiele (geplant):</p>
<ul>
<li>Meldestelle-Setup-1.0.0.msi (Windows)</li>
<li>Meldestelle-1.0.0.dmg (macOS)</li>
<li>Meldestelle-1.0.0.deb (Linux)</li>
</ul>
</div>
</body>
</html>
+101
View File
@@ -0,0 +1,101 @@
# ===================================================================
# Nginx-Konfiguration für Meldestelle Web-App
# Static Files + API Proxy zu Gateway
# ===================================================================
# Worker-Prozesse (konfigurierbar über NGINX_WORKER_PROCESSES)
worker_processes auto;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Performance Optimizations
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Gzip Kompression für bessere Performance
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/xml+rss
application/json
application/wasm;
# Upstream für API Gateway
upstream api-gateway {
server api-gateway:8081;
}
# Server-Block für Web-App
server {
listen 4000;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Serve static files (Kotlin/JS compiled files)
location / {
try_files $uri $uri/ /index.html;
# Cache-Headers für statische Assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# WASM Files mit korrektem MIME-Type
location ~* \.wasm$ {
add_header Content-Type application/wasm;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
# Proxy API calls zu Gateway
location /api/ {
proxy_pass http://api-gateway;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# CORS Headers für API-Calls
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
# Handle preflight requests
if ($request_method = 'OPTIONS') {
return 204;
}
}
# Health-Check Endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
}
+157
View File
@@ -0,0 +1,157 @@
# syntax=docker/dockerfile:1.7
# ===================================================================
# Dockerfile for Meldestelle Monitoring Server
# Based on spring-boot-service template with monitoring specifics
# ===================================================================
# === CENTRALIZED BUILD ARGUMENTS ===
# Values sourced from docker/versions.toml and docker/build-args/
# Global arguments (docker/build-args/global.env)
ARG GRADLE_VERSION
ARG JAVA_VERSION
ARG BUILD_DATE
ARG VERSION
# Infrastructure-specific arguments (docker/build-args/infrastructure.env)
# Note: No runtime profiles as build ARGs
# ===================================================================
# Build Stage
# ===================================================================
FROM gradle:${GRADLE_VERSION}-jdk${JAVA_VERSION}-alpine AS builder
LABEL stage=builder
LABEL service=monitoring-server
LABEL maintainer="Meldestelle Development Team"
WORKDIR /workspace
# Gradle optimizations
ENV GRADLE_OPTS="-Dorg.gradle.caching=true \
-Dorg.gradle.daemon=false \
-Dorg.gradle.parallel=true \
-Dorg.gradle.configureondemand=true \
-Xmx2g"
# Copy build files in optimal order for caching
COPY gradlew gradlew.bat gradle.properties settings.gradle.kts ./
COPY gradle/ gradle/
# Make gradlew executable (required on Linux/Unix systems)
RUN chmod +x gradlew
COPY platform/ platform/
COPY core/ core/
COPY build.gradle.kts ./
# Copy monitoring dependencies
COPY infrastructure/monitoring/monitoring-client/ infrastructure/monitoring/monitoring-client/
COPY infrastructure/cache/ infrastructure/cache/
# Copy monitoring-server specific files
COPY infrastructure/monitoring/monitoring-server/build.gradle.kts infrastructure/monitoring/monitoring-server/
COPY infrastructure/monitoring/monitoring-server/src/ infrastructure/monitoring/monitoring-server/src/
# Build application
RUN ./gradlew :infrastructure:monitoring:monitoring-server:dependencies --no-daemon --info
RUN ./gradlew :infrastructure:monitoring:monitoring-server:bootJar --no-daemon --info
# ===================================================================
# Runtime Stage
# ===================================================================
FROM eclipse-temurin:${JAVA_VERSION}-jre-alpine AS runtime
# Comprehensive metadata
LABEL service="monitoring-server" \
version="1.0.0" \
description="Monitoring and Observability Server for Meldestelle" \
maintainer="Meldestelle Development Team" \
java.version="${JAVA_VERSION}"
# Build arguments for user configuration
ARG APP_USER=monitoruser
ARG APP_GROUP=monitorgroup
ARG APP_UID=1003
ARG APP_GID=1003
WORKDIR /app
# System setup with additional monitoring tools
RUN apk update && \
apk upgrade && \
apk add --no-cache curl jq tzdata ca-certificates netcat-openbsd && \
rm -rf /var/cache/apk/*
# Create non-root user for monitoring-server
RUN addgroup -g ${APP_GID} -S ${APP_GROUP} && \
adduser -u ${APP_UID} -S ${APP_USER} -G ${APP_GROUP} -h /app -s /bin/sh
# Create required directories with proper permissions
RUN mkdir -p /app/logs /app/tmp /app/config /app/metrics && \
chown -R ${APP_USER}:${APP_GROUP} /app
# Copy the built JAR from builder stage
COPY --from=builder --chown=${APP_USER}:${APP_GROUP} \
/workspace/infrastructure/monitoring/monitoring-server/build/libs/*.jar app.jar
# Switch to non-root user
USER ${APP_USER}
# Expose monitoring-server port and debug port
EXPOSE 8088 5005
# Enhanced health check for monitoring service
HEALTHCHECK --interval=15s --timeout=5s --start-period=60s --retries=3 \
CMD curl -fsS --max-time 3 http://localhost:8088/actuator/health/readiness || exit 1
# Optimized JVM settings for monitoring workloads (aligned with service standards)
ENV JAVA_OPTS="-XX:MaxRAMPercentage=80.0 \
-XX:+UseG1GC \
-XX:+UseStringDeduplication \
-XX:+UseContainerSupport \
-XX:G1HeapRegionSize=16m \
-XX:+OptimizeStringConcat \
-XX:+UseCompressedOops \
-Djava.security.egd=file:/dev/./urandom \
-Djava.awt.headless=true \
-Dfile.encoding=UTF-8 \
-Duser.timezone=Europe/Vienna \
-Dmanagement.endpoints.web.exposure.include=health,info,metrics,prometheus"
# Monitoring-server specific Spring Boot configuration
ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS
ENV SERVER_PORT=8088
ENV MANAGEMENT_SERVER_PORT=8088
ENV LOGGING_LEVEL_ROOT=INFO
ENV LOGGING_LEVEL_AT_MOCODE=DEBUG
# Monitoring-focused startup command with debug support
ENTRYPOINT ["sh", "-c", "\
echo 'Starting Meldestelle Monitoring Server on port 8088...'; \
echo 'Metrics endpoint: http://localhost:8088/actuator/metrics'; \
echo 'Prometheus endpoint: http://localhost:8088/actuator/prometheus'; \
if [ \"${DEBUG:-false}\" = \"true\" ]; then \
echo 'Debug mode enabled on port 5005'; \
exec java $JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar app.jar; \
else \
exec java $JAVA_OPTS -jar app.jar; \
fi"]
# ===================================================================
# Build and Usage Instructions
# ===================================================================
# Build:
# docker build -t meldestelle/monitoring-server:latest -f infrastructure/monitoring/monitoring-server/Dockerfile .
#
# Run standalone:
# docker run -p 8083:8083 --name monitoring-server meldestelle/monitoring-server:latest
#
# Run with debug:
# docker run -p 8083:8083 -p 5005:5005 -e DEBUG=true --name monitoring-server meldestelle/monitoring-server:latest
#
# Access endpoints:
# Health: http://localhost:8083/actuator/health
# Metrics: http://localhost:8083/actuator/metrics
# Prometheus: http://localhost:8083/actuator/prometheus
# ===================================================================
@@ -0,0 +1,141 @@
# ===================================================================
# Multi-stage Dockerfile Template for Kotlin Multiplatform Web Client
# Features: Kotlin/JS compilation, Nginx serving, development support, centralized version management
# Version: 3.0.0 - Central Version Management Implementation
# ===================================================================
# IMPORTANT: Build arguments are now managed centrally via docker/versions.toml
# Use: docker-compose build or scripts/docker-build.sh for automated version injection
# === CENTRALIZED BUILD ARGUMENTS ===
# Values sourced from docker/versions.toml and docker/build-args/
# Global arguments (docker/build-args/global.env)
ARG GRADLE_VERSION
ARG JAVA_VERSION
ARG BUILD_DATE
ARG VERSION
# Client-specific arguments (docker/build-args/clients.env)
ARG NODE_VERSION
ARG NGINX_VERSION
# Client-specific build arguments (can be overridden at build time)
ARG CLIENT_PATH=client/web-app
ARG CLIENT_MODULE=client:web-app
ARG CLIENT_NAME=web-app
# ===================================================================
# Build Stage - Kotlin/JS Compilation
# ===================================================================
FROM gradle:${GRADLE_VERSION}-jdk${JAVA_VERSION}-alpine AS kotlin-builder
# Re-declare build arguments for kotlin-builder stage
ARG CLIENT_PATH=client/web-app
ARG CLIENT_MODULE=client:web-app
ARG CLIENT_NAME=web-app
ARG NODE_VERSION
LABEL stage=kotlin-builder
LABEL maintainer="Meldestelle Development Team"
WORKDIR /workspace
# Install specific Node.js version for Kotlin/JS compatibility
RUN apk add --no-cache wget ca-certificates && \
wget -q -O - https://unofficial-builds.nodejs.org/download/release/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64-musl.tar.xz | \
tar -xJ -C /usr/local --strip-components=1 && \
apk del wget ca-certificates && \
rm -rf /var/cache/apk/* && \
npm config set cache /tmp/.npm-cache && \
npm config set progress false && \
npm config set audit false
# Gradle optimizations for Kotlin Multiplatform builds
ENV GRADLE_OPTS="-Dorg.gradle.caching=true \
-Dorg.gradle.daemon=false \
-Dorg.gradle.parallel=true \
-Dorg.gradle.configureondemand=true \
-Dorg.gradle.jvmargs=-Xmx3g \
-Dkotlin.compiler.execution.strategy=in-process"
# Kotlin/JS and Node.js environment variables
ENV NODE_OPTIONS="--max-old-space-size=4096" \
NPM_CONFIG_CACHE="/tmp/.npm-cache" \
KOTLIN_JS_GENERATE_EXTERNALS=false
# Copy build configuration files first for optimal caching
COPY gradlew gradlew.bat gradle.properties settings.gradle.kts ./
COPY gradle/ gradle/
COPY build.gradle.kts ./
# Copy platform and core dependencies
COPY platform/ platform/
COPY core/ core/
# Copy client modules in dependency order
COPY client/common-ui/ client/common-ui/
COPY ${CLIENT_PATH}/ ${CLIENT_PATH}/
# Clear npm cache and verify Node.js installation
RUN npm cache clean --force && \
node --version && npm --version
# Download dependencies in a separate layer
RUN ./gradlew :${CLIENT_MODULE}:dependencies --no-daemon --info --stacktrace
# Build web application with production optimizations and better error handling
RUN ./gradlew :${CLIENT_MODULE}:jsBrowserProductionWebpack --no-daemon --info --stacktrace --debug
# Verify build output
RUN ls -la /workspace/${CLIENT_PATH}/build/dist/ || (echo "Build failed - no dist directory found" && exit 1)
# ===================================================================
# Production Stage - Nginx serving
# ===================================================================
FROM nginx:${NGINX_VERSION} AS runtime
# Re-declare build arguments for runtime stage
ARG CLIENT_PATH=client/web-app
ARG CLIENT_MODULE=client:web-app
ARG CLIENT_NAME=web-app
# Metadata
LABEL service="${CLIENT_NAME}" \
version="1.0.0" \
description="Kotlin Multiplatform Web Client for Meldestelle" \
maintainer="Meldestelle Development Team"
# Security and system setup
RUN apk update && \
apk upgrade && \
apk add --no-cache curl jq && \
rm -rf /var/cache/apk/*
# Remove default nginx content and logs
RUN rm -rf /usr/share/nginx/html/* && \
rm -f /var/log/nginx/*.log
# Copy built web application from builder stage
COPY --from=kotlin-builder /workspace/${CLIENT_PATH}/build/dist/ /usr/share/nginx/html/
# Copy nginx configuration
COPY ${CLIENT_PATH}/nginx.conf /etc/nginx/nginx.conf
# Set proper permissions for nginx
RUN chown -R nginx:nginx /usr/share/nginx/html /var/cache/nginx /var/run /var/log/nginx && \
chmod -R 755 /usr/share/nginx/html
# Switch to nginx user for security
USER nginx
# Health check specifically for the web application
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD curl -f http://localhost/health || exit 1
# Expose HTTP port
EXPOSE 80
# Start nginx with proper signal handling for graceful shutdowns
STOPSIGNAL SIGQUIT
# Run nginx in foreground with error handling
CMD ["sh", "-c", "nginx -t && exec nginx -g 'daemon off;'"]
@@ -0,0 +1,147 @@
# syntax=docker/dockerfile:1.7
# ===================================================================
# Multi-stage Dockerfile Template for Spring Boot Services
# Features: Security hardening, monitoring support, optimal caching, centralized version management
# Version: 3.0.0 - Central Version Management Implementation
# ===================================================================
# IMPORTANT: Build arguments are now managed centrally via docker/versions.toml
# Use: docker-compose build or scripts/docker-build.sh for automated version injection
# === CENTRALIZED BUILD ARGUMENTS ===
# Values sourced from docker/versions.toml and docker/build-args/
# Global arguments (docker/build-args/global.env)
ARG GRADLE_VERSION
ARG JAVA_VERSION
ARG BUILD_DATE
ARG VERSION
# Service-specific arguments (docker/build-args/services.env or infrastructure.env)
# Note: No runtime profiles/ports as build ARGs
ARG SERVICE_PATH=.
ARG SERVICE_NAME=spring-boot-service
# ===================================================================
# Build Stage
# ===================================================================
FROM gradle:${GRADLE_VERSION}-jdk${JAVA_VERSION}-alpine AS builder
# Re-declare build arguments for this stage
ARG SERVICE_PATH=.
ARG SERVICE_NAME=spring-boot-service
LABEL stage=builder
LABEL maintainer="Meldestelle Development Team"
WORKDIR /workspace
# Gradle optimizations
ENV GRADLE_OPTS="-Dorg.gradle.caching=true \
-Dorg.gradle.daemon=false \
-Dorg.gradle.parallel=true \
-Dorg.gradle.configureondemand=true \
-Xmx2g"
# Copy build files in optimal order for caching
COPY gradlew gradlew.bat gradle.properties settings.gradle.kts ./
COPY gradle/ gradle/
COPY platform/ platform/
COPY build.gradle.kts ./
# Create standalone project structure when using template generically
RUN if [ "${SERVICE_PATH}" = "." ]; then \
echo "Creating isolated standalone Spring Boot application..."; \
mkdir -p /tmp/standalone-app/src/main/kotlin/com/example /tmp/standalone-app/src/main/resources; \
cd /tmp/standalone-app; \
echo 'plugins { id("org.springframework.boot") version "3.2.0"; id("io.spring.dependency-management") version "1.1.4"; kotlin("jvm") version "2.2.0"; kotlin("plugin.spring") version "2.2.0" }' > build.gradle.kts; \
echo 'group = "com.example"; version = "1.0.0"; java { sourceCompatibility = JavaVersion.VERSION_21 }' >> build.gradle.kts; \
echo 'repositories { mavenCentral() }' >> build.gradle.kts; \
echo 'dependencies { implementation("org.springframework.boot:spring-boot-starter-web"); testImplementation("org.springframework.boot:spring-boot-starter-test") }' >> build.gradle.kts; \
echo 'package com.example; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.runApplication; @SpringBootApplication class Application; fun main(args: Array<String>) { runApplication<Application>(*args) }' > src/main/kotlin/com/example/Application.kt; \
echo 'rootProject.name = "standalone-app"' > settings.gradle.kts; \
cp /workspace/gradlew /workspace/gradlew.bat .; \
cp -r /workspace/gradle .; \
echo "Building standalone application..."; \
./gradlew bootJar --no-daemon --info; \
cp build/libs/*.jar /workspace/app.jar; \
else \
echo "Building specific service: ${SERVICE_NAME}"; \
./gradlew :${SERVICE_NAME}:dependencies --no-daemon --info; \
./gradlew :${SERVICE_NAME}:bootJar --no-daemon --info; \
cp ${SERVICE_PATH}/build/libs/*.jar /workspace/app.jar; \
fi
# ===================================================================
# Runtime Stage
# ===================================================================
FROM eclipse-temurin:${JAVA_VERSION}-jre-alpine AS runtime
# Metadata
LABEL service="${SERVICE_NAME}" \
version="1.0.0" \
maintainer="Meldestelle Development Team" \
java.version="${JAVA_VERSION}"
# Build arguments
ARG APP_USER=appuser
ARG APP_GROUP=appgroup
ARG APP_UID=1001
ARG APP_GID=1001
WORKDIR /app
# System setup
RUN apk update && \
apk upgrade && \
apk add --no-cache curl jq tzdata && \
rm -rf /var/cache/apk/*
# Non-root user creation
RUN addgroup -g ${APP_GID} -S ${APP_GROUP} && \
adduser -u ${APP_UID} -S ${APP_USER} -G ${APP_GROUP} -h /app -s /bin/sh
# Directory setup
RUN mkdir -p /app/logs /app/tmp && \
chown -R ${APP_USER}:${APP_GROUP} /app
# Re-declare build arguments for runtime stage
ARG SERVICE_PATH=.
ARG SERVICE_NAME=spring-boot-service
# Copy JAR (different locations for standalone vs service-specific builds)
COPY --from=builder --chown=${APP_USER}:${APP_GROUP} \
/workspace/app.jar app.jar
USER ${APP_USER}
# Expose ports (runtime port configured via environment)
EXPOSE 8080 5005
# Health check
HEALTHCHECK --interval=15s --timeout=3s --start-period=40s --retries=3 \
CMD curl -fsS --max-time 2 http://localhost:${SERVER_PORT:-8080}/actuator/health/readiness || exit 1
# JVM configuration
ENV JAVA_OPTS="-XX:MaxRAMPercentage=80.0 \
-XX:+UseG1GC \
-XX:+UseStringDeduplication \
-XX:+UseContainerSupport \
-Djava.security.egd=file:/dev/./urandom \
-Djava.awt.headless=true \
-Dfile.encoding=UTF-8 \
-Duser.timezone=UTC \
-Dmanagement.endpoints.web.exposure.include=health,info,metrics,prometheus"
# Spring Boot configuration
ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS
ENV LOGGING_LEVEL_ROOT=INFO
ENV SERVER_PORT=8080
# Startup command with debug support
ENTRYPOINT ["sh", "-c", "\
if [ \"${DEBUG:-false}\" = \"true\" ]; then \
echo 'Starting ${SERVICE_NAME} in DEBUG mode on port 5005...'; \
exec java $JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar app.jar; \
else \
exec java $JAVA_OPTS -jar app.jar; \
fi"]