From df5919fac83bed12e3ba63dce22cb6a73d790e7e Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 31 Jul 2025 14:09:22 +0200 Subject: [PATCH] feat(build): Refactor infrastructure modules and establish single source of truth This commit introduces a major refactoring of the build system and the core infrastructure modules. The primary goal is to establish a strict "Single Source of Truth" for all dependencies using Gradle Version Catalogs and to create a clean, maintainable, and scalable foundation for all current and future services. ### 1. Centralized Dependency Management (`libs.versions.toml`) - **Established Single Source of Truth:** All dependency versions are now exclusively managed in `gradle/libs.versions.toml`. Hardcoded versions have been removed from all build scripts. - **Introduced Gradle Bundles:** To simplify module dependencies, several bundles have been created (e.g., `testing-jvm`, `redis-cache`, `spring-cloud-gateway`, `monitoring-client`). This drastically reduces boilerplate in the `build.gradle.kts` files and improves readability. - **Cleaned up Aliases:** All library and plugin aliases have been standardized for consistency. ### 2. Infrastructure Module Refactoring All infrastructure modules (`core`, `platform`, `auth`, `cache`, `event-store`, `messaging`, `monitoring`, `gateway`) have been refactored to align with the new dependency management strategy. - **Simplified Build Scripts:** The `build.gradle.kts` for each module now uses the new bundles and aliases, making them significantly cleaner and easier to understand. - **Consistent Structure:** The architecture of each module now clearly follows the Port-Adapter pattern where applicable (e.g., `cache-api`/`redis-cache`). - **Standardized `platform-bom`:** The project's own Bill of Materials (`platform-bom`) now also includes the Spring Cloud BOM, ensuring version consistency for all Spring-related dependencies. ### 3. Added Infrastructure Documentation To improve onboarding and architectural understanding, a dedicated `README-*.md` file has been created for each refactored infrastructure module: - `README-CORE.md` - `README-PLATFORM.md` - `README-INFRA-AUTH.md` - `README-INFRA-CACHE.md` - `README-INFRA-EVENT-STORE.md` - `README-INFRA-MESSAGING.md` - `README-INFRA-MONITORING.md` - `README-INFRA-GATEWAY.md` These documents explain the purpose, architecture, and usage of each component within the system. This lays the groundwork for our "Tracer Bullet" development approach. --- build.gradle.kts | 110 +----------------- core/core-domain/build.gradle.kts | 41 +++---- core/core-utils/build.gradle.kts | 65 +++++------ .../Tracer-Bullet_Checkliste.md | 94 +++++++++++++++ gradle/libs.versions.toml | 70 +++++++++-- infrastructure/auth/README-INFRA-AUTH.md | 51 ++++++++ .../auth/auth-client/build.gradle.kts | 22 ++-- .../auth/auth-server/build.gradle.kts | 37 +++--- infrastructure/cache/README-INFRA-CACHE.md | 76 ++++++++++++ .../cache/cache-api/build.gradle.kts | 10 +- .../cache/redis-cache/build.gradle.kts | 22 ++-- .../event-store/README-INFRA-EVENT-STORE.md | 70 +++++++++++ .../event-store-api/build.gradle.kts | 10 +- .../redis-event-store/build.gradle.kts | 30 +++-- .../gateway/README-INFRA-GATEWAY.md | 55 +++++++++ infrastructure/gateway/build.gradle.kts | 47 ++++++-- .../messaging/README-INFRA-MESSAGING.md | 81 +++++++++++++ .../messaging-client/build.gradle.kts | 20 ++-- .../messaging-config/build.gradle.kts | 24 ++-- .../monitoring/README-INFRA-MONITORING.md | 49 ++++++++ .../monitoring-client/build.gradle.kts | 22 ++-- .../monitoring-server/build.gradle.kts | 31 +++-- platform/README-PLATFORM.md | 56 +++++++++ platform/platform-bom/build.gradle.kts | 29 +++-- .../platform-dependencies/build.gradle.kts | 33 ++++-- platform/platform-testing/build.gradle.kts | 28 +++-- settings.gradle.kts | 55 ++++----- 27 files changed, 882 insertions(+), 356 deletions(-) create mode 100644 docs/entwickungszyklus/Tracer-Bullet_Checkliste.md create mode 100644 infrastructure/auth/README-INFRA-AUTH.md create mode 100644 infrastructure/cache/README-INFRA-CACHE.md create mode 100644 infrastructure/event-store/README-INFRA-EVENT-STORE.md create mode 100644 infrastructure/gateway/README-INFRA-GATEWAY.md create mode 100644 infrastructure/messaging/README-INFRA-MESSAGING.md create mode 100644 infrastructure/monitoring/README-INFRA-MONITORING.md create mode 100644 platform/README-PLATFORM.md diff --git a/build.gradle.kts b/build.gradle.kts index bf83d447..b0fed89a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,124 +1,24 @@ -/* import java.util.Locale +// Defines plugins that are available to all subprojects. +// `apply false` means the plugin is not applied to the root project itself. plugins { - kotlin("jvm") version "2.1.21" apply false - kotlin("plugin.spring") version "2.1.21" apply false - id("org.springframework.boot") version "3.2.3" apply false - id("io.spring.dependency-management") version "1.1.4" apply false - base -} - -allprojects { - group = "at.mocode.meldestelle" - version = "0.1.0-SNAPSHOT" -} - -subprojects { - repositories { - mavenCentral() - } - - // Enable dependency locking for all configurations - dependencyLocking { - lockAllConfigurations() - } - - // Add task to write lock files - tasks.register("resolveAndLockAll") { - doFirst { - require(gradle.startParameter.isWriteDependencyLocks) - } - doLast { - configurations.filter { - // Only lock configurations that can be resolved - it.isCanBeResolved - }.forEach { it.resolve() } - } - } - - // Configure Kotlin compiler options - tasks.withType().configureEach { - compilerOptions { - jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21) - freeCompilerArgs.add("-Xjsr305=strict") - } - } - - // Configure parallel test execution - tasks.withType().configureEach { - useJUnitPlatform() - // Enable parallel test execution - maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1 - // Optimize JVM args for tests - jvmArgs = listOf("-Xmx512m", "-XX:+UseG1GC") - } - - // Define a custom integrationTest task - tasks.register("integrationTest") { - description = "Runs integration tests." - group = "verification" - - // Use the same configuration as the test task - useJUnitPlatform() - maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1 - jvmArgs = listOf("-Xmx512m", "-XX:+UseG1GC") - - // Include all tests that have "Integration" in their name - include("** / *Integration*Test.kt") - - // Exclude unit tests (but keep integration tests) - exclude("** / *Test.kt") - include("** / *IntegrationTest.kt") - - // Set system properties for integration tests - systemProperty("spring.profiles.active", "integration-test") - systemProperty("redis.host", "localhost") - systemProperty("redis.port", "6379") - - // Generate reports in a separate directory - reports { - html.required.set(true) - junitXml.required.set(true) - } - - // This task should run after the regular test task - // We don't use mustRunAfter here to avoid reference issues - } -} -*/ - -import java.util.Locale - -plugins { - // KORREKTUR: Wir entfernen die hartcodierten Versionen und verwenden stattdessen - // die Aliase aus dem Version Catalog. `apply false` bleibt, da die Plugins - // hier nur für die Unterprojekte deklariert werden. alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.kotlin.multiplatform) apply false alias(libs.plugins.compose.multiplatform) apply false alias(libs.plugins.compose.compiler) apply false - base } -//allprojects { -// group = "at.mocode.meldestelle" -// version = "0.1.0-SNAPSHOT" -// -// repositories { -// mavenCentral() -// google() // Wichtig für Compose-Abhängigkeiten -// } -//} - +// Common configuration for all subprojects in this build. subprojects { - // Konfigurationen, die für alle Untermodule gelten. + // Enforce Java 21 for all Kotlin compilation tasks. tasks.withType().configureEach { compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21) } } + // Configure all test tasks to use the JUnit Platform (for JUnit 5). tasks.withType().configureEach { useJUnitPlatform() } diff --git a/core/core-domain/build.gradle.kts b/core/core-domain/build.gradle.kts index edfd636a..be0ac9e2 100644 --- a/core/core-domain/build.gradle.kts +++ b/core/core-domain/build.gradle.kts @@ -1,30 +1,23 @@ +// Dieses Modul definiert die Kern-Domänenobjekte des Shared Kernels. +// Es enthält keine Implementierungsdetails, nur reine Datenklassen und Enums. plugins { - // KORREKTUR: Von JVM zu Multiplattform wechseln - alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.serialization) } -// KORREKTUR: Diesen Block hinzufügen, um die Ziele zu definieren -kotlin { - jvm() - js(IR) { - browser() - } +dependencies { + // Stellt sicher, dass dieses Modul Zugriff auf die im zentralen Katalog + // definierten Bibliotheken hat. + api(projects.platform.platformDependencies) - sourceSets { - val commonMain by getting { - dependencies { - // Die Abhängigkeiten kommen hier rein - api(projects.platform.platformDependencies) - api(libs.uuid) - api(libs.kotlinx.serialization.json) - api(libs.kotlinx.datetime) - } - } - val commonTest by getting { - dependencies { - implementation(projects.platform.platformTesting) - } - } - } + // Kern-Abhängigkeiten für das Domänen-Modell. + // `api` wird verwendet, damit Services, die `core-domain` einbinden, + // diese Typen ebenfalls direkt nutzen können. + api(libs.uuid) + api(libs.kotlinx.serialization.json) + api(libs.kotlinx.datetime) + + // Stellt die Test-Bibliotheken bereit. + testImplementation(projects.platform.platformTesting) + testImplementation(libs.bundles.testing.jvm) } diff --git a/core/core-utils/build.gradle.kts b/core/core-utils/build.gradle.kts index 5c325eab..a6bf8776 100644 --- a/core/core-utils/build.gradle.kts +++ b/core/core-utils/build.gradle.kts @@ -1,41 +1,34 @@ +// Dieses Modul stellt gemeinsame technische Hilfsfunktionen bereit, +// wie z.B. Konfigurations-Management, Datenbank-Verbindungen und Service Discovery. plugins { - // KORREKTUR: Von JVM zu Multiplattform wechseln - alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.kotlin.jvm) } -kotlin { - jvm() - js(IR) { - browser() - } +dependencies { + // Abhängigkeit zum platform-Modul für zentrale Versionsverwaltung + api(projects.platform.platformDependencies) + // Abhängigkeit zum core-domain-Modul, um dessen Typen zu verwenden + api(projects.core.coreDomain) - sourceSets { - val commonMain by getting { - dependencies { - // Diese sind plattformunabhängig und können geteilt werden - api(projects.platform.platformDependencies) - api(projects.core.coreDomain) - api(libs.kotlinx.coroutines.core) - api(libs.bignum) - } - } - val jvmMain by getting { - dependencies { - // DIESE SIND NUR FÜR DIE JVM! - api(libs.exposed.core) - api(libs.exposed.dao) - api(libs.exposed.jdbc) - api(libs.exposed.kotlin.datetime) - api(libs.hikari.cp) - api(libs.flyway.core) - api(libs.flyway.postgresql) - api(libs.consul.client) - } - } - val commonTest by getting { - dependencies { - implementation(projects.platform.platformTesting) - } - } - } + // Asynchronität + api(libs.kotlinx.coroutines.core) + + // Datenbank-Management + // OPTIMIERUNG: Verwendung von Bundles für Exposed und Flyway + api(libs.bundles.exposed) + api(libs.bundles.flyway) + api(libs.hikari.cp) + + // Service Discovery + api(libs.consul.client) + + // Logging + api(libs.kotlin.logging.jvm) + + // Utilities + api(libs.bignum) // Für BigDecimal Serialisierung + + // Testing + testImplementation(projects.platform.platformTesting) + testImplementation(libs.bundles.testing.jvm) } diff --git a/docs/entwickungszyklus/Tracer-Bullet_Checkliste.md b/docs/entwickungszyklus/Tracer-Bullet_Checkliste.md new file mode 100644 index 00000000..20ab5e8e --- /dev/null +++ b/docs/entwickungszyklus/Tracer-Bullet_Checkliste.md @@ -0,0 +1,94 @@ +✅ TODO-Checkliste: Architektur-Validierung ("Tracer Bullet") +Phase 1: Backend-Infrastruktur vorbereiten +[ ] Gradle-Setup bereinigen: + +[ ] In settings.gradle.kts sicherstellen, dass nur die platform-, core- und infrastructure-Module aktiv sind. Alle anderen (fachliche Services, Clients) müssen auskommentiert sein. + +[ ] Konfiguration finalisieren: + +[ ] Die AppConfig.kt mithilfe von Erweiterungsfunktionen (wie in PropertiesExtensions.kt) bereinigen, um Boilerplate-Code zu reduzieren. + +[ ] Die Konfiguration um advertisedHost für den ServerConfig erweitern. + +[ ] Logging-Infrastruktur implementieren: + +[ ] Eine Logging-Bibliothek (z.B. SLF4J mit Logback) zu den platform-Abhängigkeiten hinzufügen. + +[ ] Alle println-Aufrufe, insbesondere in ServiceRegistration.kt, durch strukturierte Logger-Aufrufe (logger.info, logger.error) ersetzen. + +[ ] Gateway starten und testen: + +[ ] Sicherstellen, dass der :infrastructure:gateway-Service gestartet werden kann. + +Phase 2: "Ping-Service" als Test-Modul erstellen +[ ] Modul in Gradle anlegen: + +[ ] In settings.gradle.kts eine neue Zeile hinzufügen: include(":temp:ping-service"). + +[ ] Ein build.gradle.kts für das neue Modul erstellen. Es benötigt Abhängigkeiten zu :core:core-utils und einem Web-Framework (z.B. Spring Boot, wie es im :masterdata-service verwendet wird). + +[ ] Service-Implementierung: + +[ ] Einen PingController mit einem GET /ping Endpunkt erstellen. + +[ ] Die Endpunkt-Logik soll ein einfaches JSON zurückgeben, z.B. {"status": "pong", "timestamp": "..."}. + +[ ] Einen logger.info("Ping endpoint called")-Aufruf in die Methode einfügen. + +[ ] Service-Anwendung erstellen: + +[ ] Eine main-Funktion für den Service erstellen, die: + +[ ] Die AppConfig lädt. + +[ ] Den ServiceRegistrar initialisiert und den Service bei Consul registriert. + +[ ] Den eingebetteten Web-Server startet. + +Phase 3: Minimalen Client für den Test anbinden +[ ] Client-Modul in Gradle aktivieren: + +[ ] Den Kommentar für :client:web-app in settings.gradle.kts entfernen. + +[ ] UI-Implementierung: + +[ ] Eine einfache Seite in der Web-App erstellen. + +[ ] Einen Button mit der Aufschrift "Ping Backend" hinzufügen. + +[ ] Client-Logik: + +[ ] Eine Funktion implementieren, die bei Klick auf den Button einen HTTP-Request an das Gateway sendet (z.B. http://localhost:GATEWAY_PORT/ping). + +[ ] Die Antwort des Backends entgegennehmen und den status-Wert ("pong") auf der Seite anzeigen. + +Phase 4: Gesamtsystem testen und aufräumen +[ ] Systemstart: + +[ ] Die Docker-Infrastruktur starten: docker-compose up -d. + +[ ] Den :infrastructure:gateway-Service starten. + +[ ] Den :temp:ping-service starten. + +[ ] Den :client:web-app-Service starten. + +[ ] End-to-End-Test: + +[ ] Die Web-App im Browser öffnen. + +[ ] Auf den "Ping Backend"-Button klicken. + +[ ] Erwartetes Ergebnis: Die Seite zeigt "pong" an. + +[ ] Validierung: + +[ ] Im Consul UI (üblicherweise http://localhost:8500) prüfen, ob der ping-service korrekt registriert ist. + +[ ] Die Logs des Gateways und des ping-service auf die erwarteten Log-Meldungen überprüfen. + +[ ] Aufräumen: + +[ ] Wenn alles funktioniert, den aktuellen Stand in Git committen (z.B. "feat: Add stable infrastructure baseline"). + +[ ] Das :temp:ping-service-Modul und das :client:web-app-Modul in settings.gradle.kts wieder auskommentieren, um den Boden für den ersten echten Fach-Service vorzubereiten. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 59d464cc..60cb3d6f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ # This file is the SINGLE SOURCE OF TRUTH for all project dependencies. # It allows for centralized version management and ensures consistency. -# Last updated: 2025-07-30 +# Last updated: 2025-07-31 [versions] # --- Kotlin Ecosystem --- @@ -11,6 +11,7 @@ kotlinLogging = "3.0.5" # --- Spring Ecosystem --- springBoot = "3.2.5" +springCloud = "2023.0.1" # NEU: Version für Spring Cloud springDependencyManagement = "1.1.5" springdoc = "2.5.0" @@ -32,6 +33,13 @@ lettuce = "6.3.1.RELEASE" # --- Service Discovery & Monitoring --- consulClient = "1.5.3" micrometer = "1.12.2" +micrometerTracing = "1.2.5" # NEU +zipkin = "2.24.4" # NEU (Verwendet eine neuere, kompatible Version) +zipkinReporter = "2.16.4" # NEU + +# --- Authentication --- +auth0Jwt = "4.4.0" +keycloak = "23.0.0" # --- Testing --- junitJupiter = "5.10.2" @@ -47,22 +55,22 @@ caffeine = "3.1.8" reactorKafka = "1.3.22" jackson = "2.17.0" jakartaAnnotation = "2.1.1" -auth0Jwt = "4.4.0" [libraries] # --- Platform BOMs (Bill of Materials) --- kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" } kotlinx-coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version.ref = "kotlinx" } spring-boot-dependencies = { module = "org.springframework.boot:spring-boot-dependencies", version.ref = "springBoot" } +spring-cloud-dependencies = { module = "org.springframework.cloud:spring-cloud-dependencies", version.ref = "springCloud" } # NEU # --- Kotlin & Coroutines --- kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } -kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx" } -kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx" } -kotlinx-coroutines-reactor = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-reactor", version.ref = "kotlinx" } +kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core" } # Version from BOM +kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing" } # Version from BOM +kotlinx-coroutines-reactor = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-reactor" } # Version from BOM kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx" } kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" } -kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx" } +kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test" } # Version from BOM # --- Ktor Server --- ktor-server-core = { module = "io.ktor:ktor-server-core-jvm", version.ref = "ktor" } @@ -88,19 +96,27 @@ ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" } ktor-client-contentNegotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } ktor-client-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } -# --- Spring Boot --- +# --- Spring Boot (Versions from spring-boot-dependencies BOM) --- spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web" } spring-boot-starter-validation = { module = "org.springframework.boot:spring-boot-starter-validation" } spring-boot-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator" } spring-boot-starter-data-jpa = { module = "org.springframework.boot:spring-boot-starter-data-jpa" } +spring-boot-starter-data-redis = { module = "org.springframework.boot:spring-boot-starter-data-redis" } spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test" } spring-boot-starter-oauth2-client = { module = "org.springframework.boot:spring-boot-starter-oauth2-client" } +spring-boot-starter-oauth2-resource-server = { module = "org.springframework.boot:spring-boot-starter-oauth2-resource-server" } spring-boot-starter-security = { module = "org.springframework.boot:spring-boot-starter-security" } +spring-boot-starter-json = { module = "org.springframework.boot:spring-boot-starter-json" } +spring-kafka = { module = "org.springframework.kafka:spring-kafka" } spring-security-oauth2-jose = { module = "org.springframework.security:spring-security-oauth2-jose" } spring-web = { module = "org.springframework:spring-web" } springdoc-openapi-starter-common = { module = "org.springdoc:springdoc-openapi-starter-common", version.ref = "springdoc" } springdoc-openapi-starter-webmvc-ui = { module = "org.springdoc:springdoc-openapi-starter-webmvc-ui", version.ref = "springdoc" } +# --- Spring Cloud --- +spring-cloud-starter-gateway = { module = "org.springframework.cloud:spring-cloud-starter-gateway" } # NEU +spring-cloud-starter-consul-discovery = { module = "org.springframework.cloud:spring-cloud-starter-consul-discovery" } # NEU + # --- Database & Persistence --- exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" } exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" } @@ -117,6 +133,15 @@ lettuce-core = { module = "io.lettuce:lettuce-core", version.ref = "lettuce" } # --- Service Discovery & Monitoring --- consul-client = { module = "com.orbitz.consul:consul-client", version.ref = "consulClient" } micrometer-prometheus = { module = "io.micrometer:micrometer-registry-prometheus", version.ref = "micrometer" } +micrometer-tracing-bridge-brave = { module = "io.micrometer:micrometer-tracing-bridge-brave", version.ref = "micrometerTracing" } # NEU +zipkin-reporter-brave = { module = "io.zipkin.reporter2:zipkin-reporter-brave", version.ref = "zipkinReporter" } # NEU +zipkin-sender-okhttp3 = { module = "io.zipkin.reporter2:zipkin-sender-okhttp3", version.ref = "zipkinReporter" } # NEU +zipkin-server = { module = "io.zipkin:zipkin-server", version.ref = "zipkin" } # NEU +zipkin-autoconfigure-ui = { module = "io.zipkin:zipkin-autoconfigure-ui", version.ref = "zipkin" } # NEU + +# --- Authentication --- +auth0-java-jwt = { module = "com.auth0:java-jwt", version.ref = "auth0Jwt" } +keycloak-admin-client = { module = "org.keycloak:keycloak-admin-client", version.ref = "keycloak" } # --- Utilities --- uuid = { module = "com.benasher44:uuid", version.ref = "uuid" } @@ -128,7 +153,6 @@ reactor-kafka = { module = "io.projectreactor.kafka:reactor-kafka", version.ref jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" } jackson-datatype-jsr310 = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", version.ref = "jackson" } jakarta-annotation-api = { module = "jakarta.annotation:jakarta.annotation-api", version.ref = "jakartaAnnotation" } -auth0-java-jwt = { module = "com.auth0:java-jwt", version.ref = "auth0Jwt" } # --- Compose UI --- compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "composeMultiplatform" } @@ -140,17 +164,43 @@ compose-materialIconsExtended = { module = "org.jetbrains.compose.material:mater compose-html-core = { module = "org.jetbrains.compose.html:html-core", version.ref = "composeMultiplatform" } compose-desktop-currentOs = { module = "org.jetbrains.compose.desktop:desktop", version.ref = "composeMultiplatform" } -# --- Testinging --- +# --- Testing --- junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junitJupiter" } junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junitJupiter" } junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junitJupiter" } -junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junitJupiter" } +junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher" } # Version from BOM mockk = { module = "io.mockk:mockk", version.ref = "mockk" } assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj" } testcontainers-core = { module = "org.testcontainers:testcontainers", version.ref = "testcontainers" } testcontainers-junit-jupiter = { module = "org.testcontainers:junit-jupiter", version.ref = "testcontainers" } testcontainers-postgresql = { module = "org.testcontainers:postgresql", version.ref = "testcontainers" } +[bundles] +# OPTIMIERUNG: Bündelt gängige Abhängigkeitsgruppen. +# Dies vereinfacht die build.gradle.kts-Dateien der Module erheblich. +ktor-server-essentials = [ + "ktor-server-core", "ktor-server-netty", "ktor-server-contentNegotiation", + "ktor-server-serialization-kotlinx-json", "ktor-server-statusPages", "ktor-server-callLogging" +] +ktor-client-essentials = ["ktor-client-core", "ktor-client-cio", "ktor-client-contentNegotiation", "ktor-client-serialization-kotlinx-json"] +exposed = ["exposed-core", "exposed-dao", "exposed-jdbc", "exposed-kotlin-datetime"] +flyway = ["flyway-core", "flyway-postgresql"] +spring-boot-essentials = ["spring-boot-starter-web", "spring-boot-starter-validation", "spring-boot-starter-actuator"] +redis-cache = ["spring-boot-starter-data-redis", "lettuce-core", "jackson-module-kotlin", "jackson-datatype-jsr310"] +kafka-config = ["spring-kafka", "spring-boot-starter-json", "jackson-module-kotlin", "jackson-datatype-jsr310"] +testing-jvm = ["junit-jupiter-api", "junit-jupiter-engine", "mockk", "assertj-core", "kotlinx-coroutines-test"] +testcontainers = ["testcontainers-core", "testcontainers-junit-jupiter", "testcontainers-postgresql"] +# NEU: Bündelt alle Abhängigkeiten, die ein Service für Metriken und Tracing benötigt. +monitoring-client = [ + "spring-boot-starter-actuator", + "micrometer-prometheus", + "micrometer-tracing-bridge-brave", + "zipkin-reporter-brave", + "zipkin-sender-okhttp3" +] +# NEU: Bündelt die Kernabhängigkeiten für das Spring Cloud Gateway. +spring-cloud-gateway = ["spring-cloud-starter-gateway", "spring-cloud-starter-consul-discovery"] + [plugins] kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } diff --git a/infrastructure/auth/README-INFRA-AUTH.md b/infrastructure/auth/README-INFRA-AUTH.md new file mode 100644 index 00000000..77d85819 --- /dev/null +++ b/infrastructure/auth/README-INFRA-AUTH.md @@ -0,0 +1,51 @@ +# Infrastructure/Auth Module + +## Überblick + +Das **Auth-Modul** ist die zentrale Komponente für die gesamte Authentifizierung und Autorisierung innerhalb der Meldestelle-Systemlandschaft. Es ist verantwortlich für die Absicherung von APIs, die Validierung von Benutzeridentitäten und die Verwaltung von Berechtigungen. + +Als Identity Provider wird **Keycloak** verwendet. Dieses Modul kapselt die gesamte Interaktion mit Keycloak und stellt dem Rest des Systems eine einheitliche und vereinfachte Sicherheitsschicht zur Verfügung. + +## Architektur + +Das Auth-Modul ist in zwei spezialisierte Komponenten aufgeteilt, um eine klare Trennung der Verantwortlichkeiten zu gewährleisten: + + +infrastructure/auth/ +├── auth-client/ # Wiederverwendbare Bibliothek für die JWT-Validierung +└── auth-server/ # Eigenständiger Service für Benutzerverwaltung & Token-Austausch + + +### `auth-client` + +Dieses Modul ist eine **wiederverwendbare Bibliothek** und kein eigenständiger Service. Es enthält die gesamte Logik, die andere Microservices (wie `masterdata-service`, `members-service` etc.) benötigen, um ihre Endpunkte abzusichern. + +**Hauptaufgaben:** +* **JWT-Validierung:** Stellt Spring Security Konfigurationen bereit, um eingehende JWTs (ausgestellt von Keycloak) zu validieren. Es prüft die Signatur, den Aussteller (Issuer) und die Gültigkeitsdauer des Tokens. +* **Rechte-Extraktion:** Extrahiert die Rollen und Berechtigungen des Benutzers aus dem validierten Token. +* **Security Context:** Befüllt den `SecurityContextHolder` von Spring, sodass in den Controllern einfach auf den authentifizierten Benutzer zugegriffen werden kann (z.B. mit `@AuthenticationPrincipal`). + +Jeder Microservice, der geschützte Endpunkte anbietet, bindet dieses Modul als Abhängigkeit ein. + +### `auth-server` + +Dies ist ein **eigenständiger Spring Boot Microservice**, der als Brücke zwischen dem Meldestelle-System und Keycloak agiert. + +**Hauptaufgaben:** +* **Benutzer-API:** Stellt eine REST-API zur Verfügung, um Benutzer zu verwalten (z.B. Registrierung, Profil-Updates). Diese API kommuniziert im Hintergrund über den `keycloak-admin-client` mit Keycloak. +* **Token-Endpunkte:** Kann Endpunkte für den Austausch oder die Erneuerung von Tokens bereitstellen (Token Exchange). +* **Zentraler Login-Punkt (Optional):** Kann als zentraler Punkt für Login-Weiterleitungen im OAuth2/OIDC-Flow dienen. + +Durch die Kapselung der Keycloak-spezifischen Logik im `auth-server` müssen die anderen Fach-Services nichts über die Interna der Benutzerverwaltung wissen. Sie interagieren nur mit der sauberen API des `auth-server`. + +## Zusammenspiel im System + +1. Ein **Benutzer** meldet sich über eine Client-Anwendung an und erhält ein JWT von **Keycloak**. +2. Die **Client-Anwendung** sendet eine Anfrage an einen Microservice (z.B. `masterdata-service`) und fügt das JWT als Bearer-Token in den `Authorization`-Header ein. +3. Der **Microservice**, der `auth-client` als Abhängigkeit hat, validiert das Token automatisch. +4. Wenn der Microservice Benutzerdaten ändern muss, ruft er nicht direkt Keycloak auf, sondern die sichere REST-API des **`auth-server`**. + +Diese Architektur entkoppelt die Fach-Services von der Komplexität der Identitätsverwaltung und schafft eine robuste, zentrale Sicherheitsinfrastruktur. + +--- +**Letzte Aktualisierung**: 31. Juli 2025 diff --git a/infrastructure/auth/auth-client/build.gradle.kts b/infrastructure/auth/auth-client/build.gradle.kts index 701d39d3..237aa88f 100644 --- a/infrastructure/auth/auth-client/build.gradle.kts +++ b/infrastructure/auth/auth-client/build.gradle.kts @@ -1,27 +1,31 @@ +// Dieses Modul enthält die clientseitige Logik für die Authentifizierung. +// Es stellt Konfigurationen und Beans bereit, um mit einem OAuth2/OIDC-Provider +// wie Keycloak zu interagieren und JWTs zu validieren. plugins { -// kotlin("jvm") -// kotlin("plugin.spring") - alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.spring) - - // KORREKTUR: Dieses Plugin ist entscheidend. Es schaltet den `springBoot`-Block - // und alle Spring-Boot-spezifischen Gradle-Tasks frei. alias(libs.plugins.spring.boot) - - // Dependency Management für konsistente Spring-Versionen alias(libs.plugins.spring.dependencyManagement) } dependencies { + // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen. + implementation(platform(projects.platform.platformBom)) + + // Stellt gemeinsame Abhängigkeiten wie Coroutines und Logging bereit. implementation(projects.platform.platformDependencies) - implementation(projects.core.coreDomain) + + // Stellt Domänenobjekte und technische Utilities bereit. implementation(projects.core.coreUtils) + // Spring Security für OAuth2-Client-Funktionalität und JWT-Verarbeitung. implementation(libs.spring.boot.starter.oauth2.client) implementation(libs.spring.boot.starter.security) implementation(libs.spring.security.oauth2.jose) + + // Bibliothek zur einfachen Handhabung von JWTs. implementation(libs.auth0.java.jwt) + // Stellt alle Test-Abhängigkeiten gebündelt bereit. testImplementation(projects.platform.platformTesting) } diff --git a/infrastructure/auth/auth-server/build.gradle.kts b/infrastructure/auth/auth-server/build.gradle.kts index 383c60b3..928ea7ed 100644 --- a/infrastructure/auth/auth-server/build.gradle.kts +++ b/infrastructure/auth/auth-server/build.gradle.kts @@ -1,33 +1,40 @@ +// Dieses Modul ist ein eigenständiger Spring Boot Service, der als +// zentraler Authentifizierungs- und Autorisierungs-Server agiert. +// Er kommuniziert mit Keycloak und stellt Endpunkte für die Benutzerverwaltung bereit. plugins { -// kotlin("jvm") -// kotlin("plugin.spring") -// id("org.springframework.boot") - alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.spring) - - // KORREKTUR: Dieses Plugin ist entscheidend. Es schaltet den `springBoot`-Block - // und alle Spring-Boot-spezifischen Gradle-Tasks frei. alias(libs.plugins.spring.boot) - - // Dependency Management für konsistente Spring-Versionen alias(libs.plugins.spring.dependencyManagement) } -// Configure main class for bootJar task +// Konfiguriert die Hauptklasse für das ausführbare JAR. springBoot { mainClass.set("at.mocode.infrastructure.auth.AuthServerApplicationKt") } dependencies { + // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen. + implementation(platform(projects.platform.platformBom)) + + // Stellt gemeinsame Abhängigkeiten bereit. implementation(projects.platform.platformDependencies) + + // Nutzt die Client-Logik für die Kommunikation mit Keycloak. implementation(projects.infrastructure.auth.authClient) - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter-security") - implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server") - implementation("org.springframework.boot:spring-boot-starter-actuator") - implementation("org.keycloak:keycloak-admin-client:23.0.0") + // Spring Boot Starter für einen Web-Service. + // OPTIMIERUNG: Verwendung des `spring-boot-essentials`-Bundles. + implementation(libs.bundles.spring.boot.essentials) + // Spring Security für die Absicherung des Servers. + implementation(libs.spring.boot.starter.security) + implementation(libs.spring.boot.starter.oauth2.resource.server) + + // Keycloak Admin Client zur Verwaltung von Benutzern und Realms. + implementation(libs.keycloak.admin.client) + + + // Stellt alle Test-Abhängigkeiten gebündelt bereit. testImplementation(projects.platform.platformTesting) } diff --git a/infrastructure/cache/README-INFRA-CACHE.md b/infrastructure/cache/README-INFRA-CACHE.md new file mode 100644 index 00000000..998dee54 --- /dev/null +++ b/infrastructure/cache/README-INFRA-CACHE.md @@ -0,0 +1,76 @@ +# Infrastructure/Cache Module + +## Überblick + +Das **Cache-Modul** stellt eine zentrale und wiederverwendbare Caching-Infrastruktur für alle Microservices des Meldestelle-Systems bereit. Caching ist eine entscheidende Technik zur Verbesserung der Anwendungsleistung, zur Reduzierung der Latenz und zur Entlastung von Backend-Systemen wie der primären PostgreSQL-Datenbank. + +## Architektur: Port-Adapter-Muster + +Das Modul folgt streng dem **Port-Adapter-Muster** (auch als Hexagonale Architektur bekannt), um eine saubere Trennung zwischen der Caching-Schnittstelle (dem "Port") und der konkreten Implementierung (dem "Adapter") zu gewährleisten. + + +infrastructure/cache/ +├── cache-api/ # Der "Port": Definiert die Caching-Schnittstelle +└── redis-cache/ # Der "Adapter": Implementiert die Schnittstelle mit Redis + + +### `cache-api` + +Dieses Modul ist der **abstrakte Teil** der Architektur. Es definiert den "Vertrag" für das Caching, ohne sich um die zugrunde liegende Technologie zu kümmern. + +* **Zweck:** Definiert ein oder mehrere Interfaces, z.B. `CacheService`, mit generischen Methoden wie `get(key)`, `set(key, value, ttl)` und `evict(key)`. +* **Vorteil:** Jeder Service im System programmiert nur gegen dieses Interface. Die Geschäftslogik ist vollständig von der Caching-Technologie entkoppelt. Ein Austausch des Caching-Providers (z.B. von Redis zu Caffeine) würde keine Änderungen in den Fach-Services erfordern. + +### `redis-cache` + +Dieses Modul ist die **konkrete Implementierung** der in `cache-api` definierten Schnittstellen. + +* **Zweck:** Stellt eine Spring-basierte Konfiguration und eine Implementierung des `CacheService`-Interfaces bereit, die **Redis** als Datenspeicher verwendet. Es nutzt Spring Data Redis und den Lettuce-Client für die Kommunikation. +* **Technologie:** Verwendet Jackson für die Serialisierung der zu cachenden Objekte in das JSON-Format, bevor sie in Redis gespeichert werden. +* **Vorteil:** Kapselt die gesamte Redis-spezifische Logik an einem einzigen Ort. + +## Verwendung in anderen Modulen + +Ein Microservice, der Caching nutzen möchte, geht wie folgt vor: + +1. **Abhängigkeit deklarieren:** Das Service-Modul (z.B. `masterdata-service`) fügt eine `implementation`-Abhängigkeit zu `:infrastructure:cache:redis-cache` in seiner `build.gradle.kts` hinzu. + + ```kotlin + // In masterdata-service/build.gradle.kts + dependencies { + implementation(projects.infrastructure.cache.redisCache) + } + ``` + +2. **Interface injizieren:** Im Service-Code wird nur das Interface aus `cache-api` per Dependency Injection angefordert, nicht die konkrete Redis-Klasse. + + ```kotlin + // In einem Use Case oder Service + @Service + class MasterdataService( + private val cache: CacheService // Nur das Interface wird verwendet! + ) { + fun findCountryById(id: String): Country? { + val cacheKey = "country:$id" + // 1. Versuche, aus dem Cache zu lesen + val cachedCountry = cache.get(cacheKey) + if (cachedCountry != null) { + return cachedCountry + } + + // 2. Wenn nicht im Cache, aus der DB lesen + val dbCountry = countryRepository.findById(id) + + // 3. Ergebnis in den Cache schreiben für zukünftige Anfragen + if (dbCountry != null) { + cache.set(cacheKey, dbCountry, ttl = 3600) // Cache für 1 Stunde + } + return dbCountry + } + } + ``` + +Diese Architektur stellt sicher, dass die Geschäftslogik sauber und von Infrastrukturdetails unberührt bleibt. + +--- +**Letzte Aktualisierung**: 31. Juli 2025 diff --git a/infrastructure/cache/cache-api/build.gradle.kts b/infrastructure/cache/cache-api/build.gradle.kts index cddfad5b..e31e3f3c 100644 --- a/infrastructure/cache/cache-api/build.gradle.kts +++ b/infrastructure/cache/cache-api/build.gradle.kts @@ -1,8 +1,16 @@ +// Dieses Modul definiert die provider-agnostische Caching-API. +// Es enthält nur Interfaces (z.B. `CacheService`) und Datenmodelle, +// aber keine konkrete Implementierung. plugins { - kotlin("jvm") + alias(libs.plugins.kotlin.jvm) } dependencies { + // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen. + implementation(platform(projects.platform.platformBom)) + // Stellt gemeinsame Abhängigkeiten wie Logging bereit. implementation(projects.platform.platformDependencies) + + // Stellt Test-Abhängigkeiten bereit. testImplementation(projects.platform.platformTesting) } diff --git a/infrastructure/cache/redis-cache/build.gradle.kts b/infrastructure/cache/redis-cache/build.gradle.kts index 881dcc81..022e80fb 100644 --- a/infrastructure/cache/redis-cache/build.gradle.kts +++ b/infrastructure/cache/redis-cache/build.gradle.kts @@ -1,27 +1,23 @@ +// Dieses Modul stellt eine konkrete Implementierung der `cache-api` +// unter Verwendung von Redis als Caching-Backend bereit. plugins { -// kotlin("jvm") -// kotlin("plugin.spring") - alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.spring) - - // KORREKTUR: Dieses Plugin ist entscheidend. Es schaltet den `springBoot`-Block - // und alle Spring-Boot-spezifischen Gradle-Tasks frei. alias(libs.plugins.spring.boot) - - // Dependency Management für konsistente Spring-Versionen alias(libs.plugins.spring.dependencyManagement) } 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("org.springframework.boot:spring-boot-starter-data-redis") - implementation("io.lettuce:lettuce-core") - implementation("com.fasterxml.jackson.module:jackson-module-kotlin") - implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") + // 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) + // Stellt alle Test-Abhängigkeiten gebündelt bereit. testImplementation(projects.platform.platformTesting) - testImplementation("org.testcontainers:testcontainers") } diff --git a/infrastructure/event-store/README-INFRA-EVENT-STORE.md b/infrastructure/event-store/README-INFRA-EVENT-STORE.md new file mode 100644 index 00000000..f25c4cfa --- /dev/null +++ b/infrastructure/event-store/README-INFRA-EVENT-STORE.md @@ -0,0 +1,70 @@ +# Infrastructure/Event-Store Module + +## Überblick + +Das **Event-Store-Modul** ist eine kritische Komponente der Infrastruktur, die für die Persistenz und Veröffentlichung von Domänen-Events zuständig ist. Es bildet die technische Grundlage für **Event Sourcing** und eine allgemeine **event-getriebene Architektur**. Anstatt nur den aktuellen Zustand einer Entität zu speichern, speichert der Event Store die gesamte Kette von Ereignissen (Events), die zu diesem Zustand geführt haben. + +## Architektur: Port-Adapter-Muster + +Wie schon das Cache-Modul, folgt auch der Event Store streng dem **Port-Adapter-Muster**, um eine maximale Entkopplung von der konkreten Speichertechnologie zu erreichen. + + +infrastructure/event-store/ +├── event-store-api/ # Der "Port": Definiert die Event-Store-Schnittstelle +└── redis-event-store/ # Der "Adapter": Implementiert die Schnittstelle mit Redis Streams + + +### `event-store-api` + +Dieses Modul ist der **abstrakte "Port"** der Architektur. Es definiert den Vertrag, wie der Rest der Anwendung mit dem Event Store interagiert. + +* **Zweck:** Definiert Interfaces wie `EventStore` (zum Speichern und Laden von Event-Streams) und `EventPublisher` (zum Veröffentlichen von Events an interessierte Listener). Es ist eng mit den `DomainEvent`-Definitionen aus dem `:core:core-domain`-Modul verknüpft. +* **Vorteil:** Die Fach-Services (z.B. `members-application`) sind vollständig von der Implementierung des Event Stores entkoppelt. Sie wissen nicht, ob die Events in Redis, Kafka oder einer relationalen Datenbank gespeichert werden. + +### `redis-event-store` + +Dieses Modul ist der **konkrete "Adapter"**, der die in `event-store-api` definierten Schnittstellen implementiert. + +* **Zweck:** Stellt eine Implementierung des `EventStore` bereit, die **Redis Streams** als zugrunde liegenden Datenspeicher verwendet. Redis Streams sind eine leistungsstarke Datenstruktur, die sich ideal für die Implementierung eines append-only Logs eignet, wie es für einen Event Store benötigt wird. +* **Technologie:** Nutzt Spring Data Redis und den Lettuce-Client für die performante Kommunikation mit Redis. Die Domänen-Events werden vor der Speicherung mittels Jackson in ein JSON-Format serialisiert. +* **Vorteil:** Kapselt die gesamte Redis-spezifische Logik. Ein zukünftiger Wechsel zu einem anderen Event-Store-System (z.B. Apache Kafka) würde nur den Austausch dieses einen Moduls erfordern. + +## Verwendung in anderen Modulen + +Ein Anwendungs-Service, der Event Sourcing verwendet, interagiert wie folgt mit dem Modul: + +1. **Abhängigkeit deklarieren:** Das Service-Modul (z.B. `members-application`) fügt eine `implementation`-Abhängigkeit zu `:infrastructure:event-store:redis-event-store` in seiner `build.gradle.kts` hinzu. + +2. **Interface injizieren:** Im Service-Code wird nur das `EventStore`-Interface aus der `event-store-api` injiziert. + + ```kotlin + // In einem Use Case oder Application Service + @Service + class MemberApplicationService( + private val eventStore: EventStore, // Nur das Interface wird verwendet! + private val eventPublisher: EventPublisher + ) { + fun registerNewMember(command: RegisterMemberCommand): Member { + // 1. Geschäftslogik ausführen und ein oder mehrere Events erzeugen + val memberRegisteredEvent = MemberRegisteredEvent( + memberId = UUID.randomUUID(), + name = command.name, + // ... + ) + + // 2. Das Event im Event Store speichern + eventStore.save(memberRegisteredEvent) + + // 3. Das Event veröffentlichen, damit andere Teile des Systems + // (z.B. ein E-Mail-Service) darauf reagieren können. + eventPublisher.publish(memberRegisteredEvent) + + // ... + } + } + ``` + +Diese Architektur ermöglicht eine hochgradig entkoppelte, skalierbare und resiliente Systemlandschaft, die auf asynchroner Kommunikation basiert. + +--- +**Letzte Aktualisierung**: 31. Juli 2025 diff --git a/infrastructure/event-store/event-store-api/build.gradle.kts b/infrastructure/event-store/event-store-api/build.gradle.kts index 15b432b5..60497d27 100644 --- a/infrastructure/event-store/event-store-api/build.gradle.kts +++ b/infrastructure/event-store/event-store-api/build.gradle.kts @@ -1,13 +1,19 @@ +// Dieses Modul definiert die provider-agnostische API für den Event Store. +// Es enthält die Interfaces (z.B. `EventStore`, `EventPublisher`) und die +// Domänen-Events aus `core-domain`, die gespeichert und publiziert werden. plugins { - kotlin("jvm") + alias(libs.plugins.kotlin.jvm) } dependencies { - // Apply platform BOM for version management + // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen. implementation(platform(projects.platform.platformBom)) + // Abhängigkeit zu den Core-Modulen, um auf Domänenobjekte (Events) + // und technische Hilfsklassen zugreifen zu können. implementation(projects.core.coreDomain) implementation(projects.core.coreUtils) + // Stellt alle Test-Abhängigkeiten gebündelt bereit. testImplementation(projects.platform.platformTesting) } diff --git a/infrastructure/event-store/redis-event-store/build.gradle.kts b/infrastructure/event-store/redis-event-store/build.gradle.kts index 5e13ab38..41ddab5e 100644 --- a/infrastructure/event-store/redis-event-store/build.gradle.kts +++ b/infrastructure/event-store/redis-event-store/build.gradle.kts @@ -1,33 +1,31 @@ +// Dieses Modul stellt eine konkrete Implementierung der `event-store-api` +// unter Verwendung von Redis Streams als Event-Store-Backend bereit. plugins { -// kotlin("jvm") -// kotlin("plugin.spring") - alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.spring) - - // KORREKTUR: Dieses Plugin ist entscheidend. Es schaltet den `springBoot`-Block - // und alle Spring-Boot-spezifischen Gradle-Tasks frei. alias(libs.plugins.spring.boot) - - // Dependency Management für konsistente Spring-Versionen alias(libs.plugins.spring.dependencyManagement) } dependencies { - // Apply platform BOM for version management + // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen. implementation(platform(projects.platform.platformBom)) + // Implementiert die provider-agnostische Event-Store-API. implementation(projects.infrastructure.eventStore.eventStoreApi) + // Benötigt Zugriff auf Core-Module für Domänen-Events und Utilities. implementation(projects.core.coreDomain) implementation(projects.core.coreUtils) - implementation("org.springframework.boot:spring-boot-starter-data-redis") - implementation("io.lettuce:lettuce-core") - implementation("com.fasterxml.jackson.module:jackson-module-kotlin") - implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") - implementation("javax.annotation:javax.annotation-api:1.3.2") + // OPTIMIERUNG: Wiederverwendung des `redis-cache`-Bundles, da es die + // gleichen Technologien (Spring Data Redis, Lettuce, Jackson) verwendet. + implementation(libs.bundles.redis.cache) + // Stellt Jakarta Annotations bereit (z.B. @PostConstruct), die von Spring verwendet werden. + implementation(libs.jakarta.annotation.api) + + // Stellt alle Test-Abhängigkeiten gebündelt bereit. testImplementation(projects.platform.platformTesting) - testImplementation("org.testcontainers:testcontainers") - testImplementation("org.testcontainers:junit-jupiter") + // Stellt Testcontainers für Integrationstests mit einer echten Redis-Instanz bereit. + testImplementation(libs.bundles.testcontainers) } diff --git a/infrastructure/gateway/README-INFRA-GATEWAY.md b/infrastructure/gateway/README-INFRA-GATEWAY.md new file mode 100644 index 00000000..a6b91c00 --- /dev/null +++ b/infrastructure/gateway/README-INFRA-GATEWAY.md @@ -0,0 +1,55 @@ +## Infrastructure/Gateway Module +Ü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. + +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. + +Hauptverantwortlichkeiten +Das Gateway ist verantwortlich für die Handhabung aller Cross-Cutting Concerns (übergreifende Belange), die für mehrere oder alle Microservices gelten. Dies entlastet die Fach-Services von technischen Aufgaben. + +Dynamisches Routing: +Das Gateway ist mit dem Consul Service Discovery integriert. Es fragt bei Consul an, welche Services unter welcher Adresse verfügbar sind, und leitet eingehende Anfragen dynamisch an die entsprechenden, gesunden Service-Instanzen weiter. +Beispiel: Eine Anfrage an /api/members/... wird automatisch an eine Instanz des members-service weitergeleitet. + +## Sicherheit und Authentifizierung: +Das Gateway ist der Security Enforcement Point. Es bindet das :infrastructure:auth:auth-client-Modul ein, um jede eingehende Anfrage zu überprüfen: + +Es validiert das im Authorization-Header mitgesendete JWT. + +Anfragen ohne gültiges Token werden mit einem 401 Unauthorized-Fehler abgewiesen. + +Nur validierte Anfragen mit einem gültigen Token werden an die internen Services weitergeleitet. + +Rate Limiting: +Es schützt die Backend-Services vor Überlastung, indem es die Anzahl der Anfragen pro Client oder pro IP-Adresse begrenzt. + +Monitoring und Tracing: +Durch die Einbindung des :infrastructure:monitoring:monitoring-client-Moduls generiert das Gateway Metriken über eingehenden Traffic und ist der Startpunkt für Distributed Traces. Jede Anfrage erhält eine eindeutige Trace-ID, die über alle folgenden Service-Aufrufe hinweg mitgeführt wird. + +CORS-Management: +Verwaltet zentral die Cross-Origin Resource Sharing (CORS)-Richtlinien, um festzulegen, welche Web-Frontends auf die API zugreifen dürfen. + +Zusammenspiel im System +Ein typischer Anfrage-Flow sieht wie folgt aus: + +Ein Client (z.B. die Web-App) sendet eine Anfrage an https://api.meldestelle.at/members/123. + +Das API-Gateway empfängt die Anfrage. + +Gateway-Filter-Kette: +a. Der Security-Filter validiert das JWT. +b. Der Logging/Tracing-Filter startet einen neuen Trace. +c. Der Rate-Limiting-Filter prüft, ob das Limit überschritten ist. + +Der Routing-Filter schaut in Consul nach, wo der members-service läuft (z.B. unter 172.18.0.5:8081). + +Das Gateway leitet die Anfrage an die interne Service-Instanz weiter. + +Die Antwort des members-service wird auf dem gleichen Weg zurück an den Client gesendet. + +Diese Architektur schafft ein sicheres, robustes und wartbares System, indem sie die Komplexität der Infrastruktur vor den Fach-Services verbirgt. + +Letzte Aktualisierung: 31. Juli 2025 diff --git a/infrastructure/gateway/build.gradle.kts b/infrastructure/gateway/build.gradle.kts index 783570c2..0b2a449c 100644 --- a/infrastructure/gateway/build.gradle.kts +++ b/infrastructure/gateway/build.gradle.kts @@ -1,9 +1,9 @@ -plugins { +/*plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.serialization) alias(libs.plugins.ktor) - application alias(libs.plugins.spring.dependencyManagement) + application } application { @@ -12,18 +12,13 @@ application { dependencies { api(platform(libs.spring.boot.dependencies)) - // --- Interne Module --- - // Der Gateway benötigt nur die Kern-Definitionen und Utilities. implementation(projects.platform.platformDependencies) implementation(projects.core.coreDomain) implementation(projects.core.coreUtils) - // Der Gateway nutzt den Auth-Client, um Tokens zu validieren. + implementation(projects.infrastructure.auth.authClient) implementation(projects.infrastructure.monitoring.monitoringClient) - // !!! WICHTIG: KEINE direkten Abhängigkeiten zu den Domänen- oder - // Infrastruktur-Modulen der Backend-Services mehr! - // --- Ktor Server --- implementation(libs.ktor.server.core) implementation(libs.ktor.server.netty) @@ -44,7 +39,7 @@ dependencies { // --- Ktor Client (damit der Gateway Anfragen an die Backend-Services weiterleiten kann) --- implementation(libs.ktor.client.core) - implementation(libs.ktor.client.cio) // CIO ist eine gute, asynchrone Engine + implementation(libs.ktor.client.cio) implementation(libs.ktor.client.contentNegotiation) implementation(libs.ktor.client.serialization.kotlinx.json) @@ -54,4 +49,38 @@ dependencies { // --- Testing --- testImplementation(projects.platform.platformTesting) testImplementation(libs.ktor.server.tests) +}*/ + +// Dieses Modul ist das API-Gateway und der einzige öffentliche Einstiegspunkt +// für alle externen Anfragen an das Meldestelle-System. +plugins { + alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.kotlin.spring) + alias(libs.plugins.spring.boot) + alias(libs.plugins.spring.dependencyManagement) +} + +// Konfiguriert die Hauptklasse für das ausführbare JAR. +springBoot { + mainClass.set("at.mocode.infrastructure.gateway.GatewayApplicationKt") +} + +dependencies { + // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen. + implementation(platform(projects.platform.platformBom)) + // Stellt gemeinsame Abhängigkeiten bereit. + implementation(projects.platform.platformDependencies) + + // OPTIMIERUNG: Verwendung des `spring-cloud-gateway`-Bundles. + // Es enthält den Gateway-Starter und den Consul Discovery Client. + implementation(libs.bundles.spring.cloud.gateway) + + // Bindet die wiederverwendbare Logik zur JWT-Validierung ein. + implementation(projects.infrastructure.auth.authClient) + + // Bindet die wiederverwendbare Logik für Metriken und Tracing ein. + implementation(projects.infrastructure.monitoring.monitoringClient) + + // Stellt alle Test-Abhängigkeiten gebündelt bereit. + testImplementation(projects.platform.platformTesting) } diff --git a/infrastructure/messaging/README-INFRA-MESSAGING.md b/infrastructure/messaging/README-INFRA-MESSAGING.md new file mode 100644 index 00000000..bceee1f7 --- /dev/null +++ b/infrastructure/messaging/README-INFRA-MESSAGING.md @@ -0,0 +1,81 @@ +# Infrastructure/Messaging Module + +## Überblick + +Das **Messaging-Modul** stellt die Infrastruktur für die asynchrone Kommunikation zwischen den Microservices des Meldestelle-Systems bereit. Es nutzt **Apache Kafka** als hochperformanten, verteilten Message-Broker. Dieses Modul ist entscheidend für die Entkopplung von Services und die Implementierung von Mustern wie Publish/Subscribe, um eine skalierbare und resiliente Architektur zu ermöglichen. + +## Architektur + +Ähnlich wie andere Infrastruktur-Module ist auch dieses in zwei spezialisierte Komponenten aufgeteilt, um Konfiguration von der Client-Logik zu trennen: + + +infrastructure/messaging/ +├── messaging-config/ # Stellt die zentrale Kafka-Konfiguration bereit +└── messaging-client/ # Stellt wiederverwendbare Producer- und Consumer-Clients bereit + + +### `messaging-config` + +Dieses Modul ist die Basis für jede Kafka-Interaktion. Es ist dafür verantwortlich, die gesamte **Konfiguration** zu zentralisieren. + +* **Zweck:** Definiert Spring-Beans für die grundlegende Kafka-Konfiguration. Dazu gehören: + * Die Adresse der Kafka-Broker (`bootstrap-servers`). + * Konfiguration für Serializer und Deserializer (z.B. `JsonSerializer` von Spring Kafka), um sicherzustellen, dass alle Services Nachrichten im selben Format (JSON) austauschen. + * Konfiguration für Topics, Partitionen und Replikationsfaktoren. +* **Vorteil:** Jeder Service, der Kafka nutzt, kann sich auf diese zentrale Konfiguration verlassen, was die Konsistenz sicherstellt und die Einrichtung neuer Producer oder Consumer vereinfacht. + +### `messaging-client` + +Dieses Modul baut auf `messaging-config` auf und stellt **wiederverwendbare High-Level-Komponenten** für die Interaktion mit Kafka bereit. + +* **Zweck:** Stellt einfach zu verwendende Klassen oder Services zur Verfügung, z.B. einen `KafkaProducerService` zum Senden von Nachrichten und einen `KafkaConsumerService` zum Empfangen von Nachrichten. Es nutzt **Project Reactor** (`reactor-kafka`), um eine reaktive und nicht-blockierende Verarbeitung von Nachrichten zu ermöglichen. +* **Vorteil:** Kapselt die Komplexität der Kafka-Producer- und -Consumer-API. Ein Fach-Service muss nur noch eine Methode wie `producer.sendMessage("topic", message)` aufrufen, ohne sich um die Details der Verbindung, Serialisierung oder Fehlerbehandlung kümmern zu müssen. + +## Verwendung in anderen Modulen + +Ein Microservice, der Nachrichten senden oder empfangen möchte, geht wie folgt vor: + +1. **Abhängigkeit deklarieren:** Das Service-Modul (z.B. `events-service`) fügt eine `implementation`-Abhängigkeit zu `:infrastructure:messaging:messaging-client` in seiner `build.gradle.kts` hinzu. + +2. **Client-Service injizieren:** Im Service-Code wird der `KafkaProducerService` oder `KafkaConsumerService` per Dependency Injection angefordert. + + ```kotlin + // Beispiel für das Senden einer Nachricht + @Service + class EventNotificationService( + private val kafkaProducer: KafkaProducerService + ) { + fun notifyNewEvent(eventDetails: EventDetails) { + val topic = "new-events-topic" + // Einfacher Aufruf zum Senden der Nachricht. + // Die Komplexität der Serialisierung und des Sendens ist gekapselt. + kafkaProducer.sendMessage(topic, eventDetails.id, eventDetails) + .subscribe( + { result -> logger.info("Message sent successfully to topic '{}'", topic) }, + { error -> logger.error("Failed to send message to topic '{}'", topic, error) } + ) + } + } + ```kotlin + // Beispiel für das Empfangen von Nachrichten + @Component + class EventListener( + private val kafkaConsumer: KafkaConsumerService + ) { + @PostConstruct + fun listenForEvents() { + val topic = "new-events-topic" + // Reaktiv auf eingehende Nachrichten lauschen. + kafkaConsumer.receiveMessages(topic) + .subscribe { event -> + logger.info("Received new event with ID: {}", event.id) + // Geschäftslogik zur Verarbeitung des Events... + } + } + } + ``` + +Diese Architektur ermöglicht eine saubere, robuste und hochgradig entkoppelte Kommunikation zwischen den Diensten. + +--- +**Letzte Aktualisierung**: 31. Juli 2025 diff --git a/infrastructure/messaging/messaging-client/build.gradle.kts b/infrastructure/messaging/messaging-client/build.gradle.kts index f70a08ff..ca359c25 100644 --- a/infrastructure/messaging/messaging-client/build.gradle.kts +++ b/infrastructure/messaging/messaging-client/build.gradle.kts @@ -1,25 +1,23 @@ +// Dieses Modul stellt High-Level-Clients (Producer/Consumer) für die +// Interaktion mit Apache Kafka bereit. Es baut auf der `messaging-config` auf. plugins { -// kotlin("jvm") -// kotlin("plugin.spring") - alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.spring) - - // KORREKTUR: Dieses Plugin ist entscheidend. Es schaltet den `springBoot`-Block - // und alle Spring-Boot-spezifischen Gradle-Tasks frei. alias(libs.plugins.spring.boot) - - // Dependency Management für konsistente Spring-Versionen alias(libs.plugins.spring.dependencyManagement) } dependencies { + // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen. + implementation(platform(projects.platform.platformBom)) + // Stellt gemeinsame Abhängigkeiten bereit. implementation(projects.platform.platformDependencies) + // Baut auf der zentralen Kafka-Konfiguration auf und erbt deren Abhängigkeiten. implementation(projects.infrastructure.messaging.messagingConfig) - implementation("org.springframework.kafka:spring-kafka") - implementation("io.projectreactor.kafka:reactor-kafka") - implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + // Fügt die reaktive Kafka-Implementierung hinzu (Project Reactor). + implementation(libs.reactor.kafka) + // Stellt alle Test-Abhängigkeiten gebündelt bereit. testImplementation(projects.platform.platformTesting) } diff --git a/infrastructure/messaging/messaging-config/build.gradle.kts b/infrastructure/messaging/messaging-config/build.gradle.kts index 416f4a98..70ed670a 100644 --- a/infrastructure/messaging/messaging-config/build.gradle.kts +++ b/infrastructure/messaging/messaging-config/build.gradle.kts @@ -1,25 +1,23 @@ +// Dieses Modul stellt die zentrale, wiederverwendbare Konfiguration +// für die Verbindung mit Apache Kafka bereit (z.B. Bootstrap-Server, Serializer). plugins { -// kotlin("jvm") -// kotlin("plugin.spring") - alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.spring) - - // KORREKTUR: Dieses Plugin ist entscheidend. Es schaltet den `springBoot`-Block - // und alle Spring-Boot-spezifischen Gradle-Tasks frei. alias(libs.plugins.spring.boot) - - // Dependency Management für konsistente Spring-Versionen alias(libs.plugins.spring.dependencyManagement) } dependencies { - implementation(projects.platform.platformDependencies) + // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen. + api(platform(projects.platform.platformBom)) + // Stellt gemeinsame Abhängigkeiten bereit. + api(projects.platform.platformDependencies) - implementation("org.springframework.kafka:spring-kafka") - implementation("org.springframework.boot:spring-boot-starter-json") - implementation("com.fasterxml.jackson.module:jackson-module-kotlin") - implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") + // OPTIMIERUNG: Verwendung des `kafka-config`-Bundles. + // `api` wird verwendet, damit der `messaging-client` diese Konfigurationen + // und Abhängigkeiten (wie Jackson) direkt nutzen kann. + api(libs.bundles.kafka.config) + // Stellt alle Test-Abhängigkeiten gebündelt bereit. testImplementation(projects.platform.platformTesting) } diff --git a/infrastructure/monitoring/README-INFRA-MONITORING.md b/infrastructure/monitoring/README-INFRA-MONITORING.md new file mode 100644 index 00000000..8557015e --- /dev/null +++ b/infrastructure/monitoring/README-INFRA-MONITORING.md @@ -0,0 +1,49 @@ +# Infrastructure/Monitoring Module + +## Überblick + +Das **Monitoring-Modul** ist die Grundlage für die **Observability** (Beobachtbarkeit) der gesamten Meldestelle-Systemlandschaft. In einer verteilten Microservice-Architektur ist es unerlässlich, Einblicke in das Verhalten, die Leistung und die Gesundheit der einzelnen Dienste zu haben. Dieses Modul stellt die Werkzeuge für zwei der drei Säulen der Observability bereit: **Metriken** und **Distributed Tracing**. + +* **Metriken:** Quantitative Daten über die Leistung von Services (z.B. CPU-Auslastung, Antwortzeiten, Fehlerraten). +* **Distributed Tracing:** Verfolgung einer einzelnen Anfrage über mehrere Service-Grenzen hinweg, um Engpässe und Fehlerquellen zu identifizieren. + +## Architektur + +Das Modul ist in eine wiederverwendbare Client-Bibliothek und einen zentralen Server aufgeteilt: + + +infrastructure/monitoring/ +├── monitoring-client/ # Bibliothek, die jeder Service einbindet +└── monitoring-server/ # Eigenständiger Service, der den Zipkin-Server hostet + + +### `monitoring-client` + +Dies ist eine **wiederverwendbare Bibliothek**, die von **jedem einzelnen Microservice** (z.B. `masterdata-service`, `gateway`) als Abhängigkeit eingebunden werden muss. + +* **Zweck:** Instrumentiert den Service automatisch, um Metriken und Traces zu generieren. +* **Technologien:** + * **Spring Boot Actuator:** Stellt einen `/actuator/prometheus`-Endpunkt bereit, an dem Metriken im Prometheus-Format abgerufen werden können. + * **Micrometer:** Eine Fassade für Metriken, die es ermöglicht, Anwendungsmetriken zu sammeln (z.B. HTTP-Request-Zeiten, JVM-Statistiken). + * **Brave & Zipkin Reporter:** Instrumentiert den Code für Distributed Tracing und sendet die gesammelten Spans (Teile eines Traces) an den Zipkin-Server. +* **Vorteil:** Entwickler müssen sich nicht aktiv um die Implementierung von Monitoring kümmern. Durch das Einbinden dieser Bibliothek erhält jeder Service automatisch grundlegende Observability. + +### `monitoring-server` + +Dies ist ein **eigenständiger Spring Boot Service**, der eine zentrale Komponente des Monitoring-Stacks hostet. + +* **Zweck:** Hostet den **Zipkin-Server** inklusive seiner grafischen Benutzeroberfläche. Alle `monitoring-client`-Instanzen senden ihre Tracing-Daten an diesen Server. Entwickler können dann in der Zipkin-UI die gesamten Anfrage-Flows visualisieren und analysieren. + +## Zusammenspiel im Ökosystem + +Das vollständige Monitoring-Setup besteht aus mehreren Teilen: + +1. Jeder **Microservice** bindet `:infrastructure:monitoring:monitoring-client` ein und stellt Metriken unter `/actuator/prometheus` bereit und sendet Traces an Zipkin. +2. Der **`:infrastructure:monitoring:monitoring-server`** empfängt die Traces und stellt die Zipkin-UI zur Verfügung. +3. Ein **Prometheus-Server** (definiert in `docker-compose.yml`) ist so konfiguriert, dass er periodisch die `/actuator/prometheus`-Endpunkte aller Microservices abfragt ("scraped") und die Metriken in seiner Zeitreihen-Datenbank speichert. +4. Ein **Grafana-Server** (definiert in `docker-compose.yml`) visualisiert die in Prometheus gespeicherten Metriken in anpassbaren Dashboards. + +Diese Kombination aus Micrometer, Prometheus, Zipkin und Grafana bildet einen leistungsstarken, branchenüblichen "Observability Stack". + +--- +**Letzte Aktualisierung**: 31. Juli 2025 diff --git a/infrastructure/monitoring/monitoring-client/build.gradle.kts b/infrastructure/monitoring/monitoring-client/build.gradle.kts index 38429263..dd9a1038 100644 --- a/infrastructure/monitoring/monitoring-client/build.gradle.kts +++ b/infrastructure/monitoring/monitoring-client/build.gradle.kts @@ -1,26 +1,22 @@ +// Dieses Modul ist eine wiederverwendbare Bibliothek, die von jedem Microservice +// eingebunden wird, um Metriken und Tracing-Daten zu exportieren. plugins { -// kotlin("jvm") -// kotlin("plugin.spring") - alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.spring) - - // KORREKTUR: Dieses Plugin ist entscheidend. Es schaltet den `springBoot`-Block - // und alle Spring-Boot-spezifischen Gradle-Tasks frei. alias(libs.plugins.spring.boot) - - // Dependency Management für konsistente Spring-Versionen alias(libs.plugins.spring.dependencyManagement) } dependencies { + // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen. + implementation(platform(projects.platform.platformBom)) + // Stellt gemeinsame Abhängigkeiten bereit. implementation(projects.platform.platformDependencies) - implementation("org.springframework.boot:spring-boot-starter-actuator") - implementation("io.micrometer:micrometer-registry-prometheus") - implementation("io.zipkin.reporter2:zipkin-reporter-brave") - implementation("io.zipkin.reporter2:zipkin-sender-okhttp3") - implementation("io.micrometer:micrometer-tracing-bridge-brave") + // OPTIMIERUNG: Verwendung des `monitoring-client`-Bundles. + // Es enthält Spring Boot Actuator, Micrometer Prometheus und Zipkin Tracing. + implementation(libs.bundles.monitoring.client) + // Stellt alle Test-Abhängigkeiten gebündelt bereit. testImplementation(projects.platform.platformTesting) } diff --git a/infrastructure/monitoring/monitoring-server/build.gradle.kts b/infrastructure/monitoring/monitoring-server/build.gradle.kts index 36392ab5..1f4f24c1 100644 --- a/infrastructure/monitoring/monitoring-server/build.gradle.kts +++ b/infrastructure/monitoring/monitoring-server/build.gradle.kts @@ -1,33 +1,32 @@ +// Dieses Modul ist ein eigenständiger Spring Boot Service, der den +// Zipkin-Server mit seiner UI hostet, um Tracing-Daten zu visualisieren. plugins { -// kotlin("jvm") -// kotlin("plugin.spring") -// id("org.springframework.boot") - alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.spring) - - // KORREKTUR: Dieses Plugin ist entscheidend. Es schaltet den `springBoot`-Block - // und alle Spring-Boot-spezifischen Gradle-Tasks frei. alias(libs.plugins.spring.boot) - - // Dependency Management für konsistente Spring-Versionen alias(libs.plugins.spring.dependencyManagement) - } -// Configure main class for bootJar task +// Konfiguriert die Hauptklasse für das ausführbare JAR. springBoot { mainClass.set("at.mocode.infrastructure.monitoring.MonitoringServerApplicationKt") } dependencies { + // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen. + implementation(platform(projects.platform.platformBom)) + // Stellt gemeinsame Abhängigkeiten bereit. implementation(projects.platform.platformDependencies) - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter-actuator") - implementation("io.micrometer:micrometer-registry-prometheus") - implementation("io.zipkin.java:zipkin-server:2.12.9") - implementation("io.zipkin.java:zipkin-autoconfigure-ui:2.12.9") + // Spring Boot Starter für einen einfachen Web-Service. + implementation(libs.spring.boot.starter.web) + implementation(libs.spring.boot.starter.actuator) + // Abhängigkeiten für den Zipkin-Server und seine UI. + // OPTIMIERUNG: Versionen werden jetzt zentral über libs.versions.toml verwaltet. + implementation(libs.zipkin.server) + implementation(libs.zipkin.autoconfigure.ui) + + // Stellt alle Test-Abhängigkeiten gebündelt bereit. testImplementation(projects.platform.platformTesting) } diff --git a/platform/README-PLATFORM.md b/platform/README-PLATFORM.md new file mode 100644 index 00000000..6e6b217a --- /dev/null +++ b/platform/README-PLATFORM.md @@ -0,0 +1,56 @@ +# Platform Module + +## Überblick + +Das **Platform-Modul** ist das Rückgrat der Build-Infrastruktur des Meldestelle-Projekts. Seine alleinige Aufgabe ist die zentrale Verwaltung und Bereitstellung von Abhängigkeiten und deren Versionen. Dies stellt sicher, dass alle Module im gesamten Projekt dieselben Bibliotheksversionen verwenden, was Inkonsistenzen ("JAR Hell") verhindert und die Wartbarkeit drastisch verbessert. + +Das Modul agiert als eine interne "Single Source of Truth" für alle externen Bibliotheken. + +## Architektur + +Das Platform-Modul ist in drei spezialisierte Untermodule aufgeteilt, die jeweils eine klare Aufgabe haben: + + +platform/ +├── platform-bom/ # Bill of Materials (BOM) - Erzwingt Versionen +├── platform-dependencies/ # Bündelt gemeinsame Laufzeit-Abhängigkeiten +└── platform-testing/ # Bündelt gemeinsame Test-Abhängigkeiten + + +### `platform-bom` + +Dies ist das wichtigste Modul der Plattform. Es ist als "Bill of Materials" (BOM) konfiguriert und nutzt das `java-platform`-Plugin von Gradle. + +* **Zweck:** Definiert eine umfassende Liste von Abhängigkeiten und deren exakten, geprüften Versionen. Es importiert auch andere wichtige BOMs (z.B. von Spring Boot und Kotlin). +* **Funktionsweise:** Andere Module importieren diese BOM mit `platform(projects.platform.platformBom)`. Gradle sorgt dann dafür, dass alle transitiven und deklarierten Abhängigkeiten den in der BOM festgelegten Versionen entsprechen. +* **Vorteil:** Absolute Versionskontrolle über das gesamte Projekt. + +### `platform-dependencies` + +Ein einfaches "Sammelmodul", das die am häufigsten benötigten Laufzeit-Abhängigkeiten bündelt. + +* **Zweck:** Vereinfacht die `build.gradle.kts`-Dateien der Service-Module. Anstatt 5-6 einzelne `kotlinx`- und Logging-Bibliotheken hinzuzufügen, genügt eine einzige Abhängigkeit zu diesem Modul. +* **Verwendung:** + ```kotlin + // In einem Service-Modul + dependencies { + implementation(projects.platform.platformDependencies) + } + ``` + +### `platform-testing` + +Analog zu `platform-dependencies`, aber speziell für Test-Bibliotheken. + +* **Zweck:** Stellt ein konsistentes Set an Test-Frameworks (JUnit 5, MockK, AssertJ) und Werkzeugen (Testcontainers) für alle Module bereit. +* **Verwendung:** + ```kotlin + // In einem Service-Modul + dependencies { + testImplementation(projects.platform.platformTesting) + } + ``` +* **Optimierung:** Dieses Modul nutzt die in `libs.versions.toml` definierten `[bundles]`, um die Build-Datei extrem kurz und lesbar zu halten. + +--- +**Letzte Aktualisierung**: 31. Juli 2025 diff --git a/platform/platform-bom/build.gradle.kts b/platform/platform-bom/build.gradle.kts index c58e4fcc..bb7a2c8c 100644 --- a/platform/platform-bom/build.gradle.kts +++ b/platform/platform-bom/build.gradle.kts @@ -1,22 +1,28 @@ +// Dieses Modul definiert die "Bill of Materials" (BOM) für das gesamte Projekt. +// Es nutzt das `java-platform`-Plugin, um eine zentrale Liste von Abhängigkeitsversionen +// zu erstellen, die von allen anderen Modulen importiert wird. +// Dies ist die ultimative "Single Source of Truth" für Versionen. plugins { `java-platform` - `maven-publish` + `maven-publish` // Nützlich, falls die BOM extern veröffentlicht werden soll } javaPlatform { + // Erlaubt die Deklaration von Abhängigkeiten in einer Plattform. allowDependencies() } dependencies { - // KORREKTUR: Alle BOMs werden jetzt über Aliase aus der libs.versions.toml bezogen. + // Importiert andere wichtige BOMs. Die Versionen werden durch diese + // importierten Plattformen transitiv verwaltet. api(platform(libs.spring.boot.dependencies)) + api(platform(libs.spring.cloud.dependencies)) // NEU: Spring Cloud BOM hinzugefügt api(platform(libs.kotlin.bom)) api(platform(libs.kotlinx.coroutines.bom)) + // `constraints` erzwingt spezifische Versionen für einzelne Bibliotheken. + // Alle Versionen werden sicher aus `libs.versions.toml` bezogen. constraints { - // KORREKTUR: Alle Abhängigkeiten verwenden jetzt Aliase. - // Keine einzige hartcodierte Version mehr in dieser Datei! - // --- Utilities & Other --- api(libs.caffeine) api(libs.reactor.kafka) @@ -26,16 +32,16 @@ dependencies { api(libs.consul.client) api(libs.kotlin.logging.jvm) api(libs.jakarta.annotation.api) + api(libs.auth0.java.jwt) + api(libs.logback.classic) // --- Spring & SpringDoc --- api(libs.springdoc.openapi.starter.common) api(libs.springdoc.openapi.starter.webmvc.ui) // --- Database & Persistence --- - api(libs.exposed.core) - api(libs.exposed.dao) - api(libs.exposed.jdbc) - api(libs.exposed.kotlin.datetime) + api(libs.bundles.exposed) + api(libs.bundles.flyway) api(libs.postgresql.driver) api(libs.hikari.cp) api(libs.h2.driver) @@ -50,12 +56,11 @@ dependencies { api(libs.jackson.datatype.jsr310) // --- Testcontainers --- - api(libs.testcontainers.core) - api(libs.testcontainers.junit.jupiter) - api(libs.testcontainers.postgresql) + api(libs.bundles.testcontainers) } } +// Konfiguration für das Veröffentlichen der BOM (optional, aber gute Praxis). publishing { publications { create("maven") { diff --git a/platform/platform-dependencies/build.gradle.kts b/platform/platform-dependencies/build.gradle.kts index 4ab8baa8..63073c36 100644 --- a/platform/platform-dependencies/build.gradle.kts +++ b/platform/platform-dependencies/build.gradle.kts @@ -1,3 +1,5 @@ +/* +// Multiplatform plugins { alias(libs.plugins.kotlin.multiplatform) } @@ -11,12 +13,6 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - // KORREKTUR: Die explizite `platform()`-Abhängigkeit wird hier entfernt. - // Die Versionen aus der BOM werden trotzdem angewendet. - - // KORREKTUR: `stdlib` und `reflect` werden entfernt. - // `stdlib` wird automatisch hinzugefügt. - api(libs.kotlinx.coroutines.core) api(libs.kotlinx.serialization.json) api(libs.kotlinx.datetime) @@ -25,11 +21,30 @@ kotlin { val jvmMain by getting { dependencies { - api("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") - - // KORREKTUR: Hartcodierte Version durch Alias ersetzen api(libs.kotlin.logging.jvm) + api(libs.kotlinx.coroutines.reactor) } } } } +*/ + +// Dieses Modul ist ein reines "Sammelmodul". +// Es hat keinen eigenen Code, sondern bündelt nur gemeinsame Laufzeit-Abhängigkeiten, +// die von den meisten JVM-Modulen benötigt werden. +plugins { + alias(libs.plugins.kotlin.jvm) +} + +dependencies { + // Importiert die zentrale BOM, um konsistente Versionen zu gewährleisten. + api(platform(projects.platform.platformBom)) + + // Stellt die wichtigsten Kotlin(x)-Bibliotheken via `api` bereit, + // damit jedes Modul, das von `platform-dependencies` abhängt, diese automatisch erhält. + api(libs.kotlinx.coroutines.core) + api(libs.kotlinx.serialization.json) + api(libs.kotlinx.datetime) + api(libs.kotlin.logging.jvm) + api(libs.kotlinx.coroutines.reactor) +} diff --git a/platform/platform-testing/build.gradle.kts b/platform/platform-testing/build.gradle.kts index 7147e5e3..3dcd8e15 100644 --- a/platform/platform-testing/build.gradle.kts +++ b/platform/platform-testing/build.gradle.kts @@ -1,26 +1,21 @@ -plugins { - // KORREKTUR: 'java-library' und 'kotlin("jvm")' ersetzen +/*plugins { alias(libs.plugins.kotlin.multiplatform) } kotlin { - // KORREKTUR: JVM- und JS-Ziele definieren jvm() js(IR) { browser() } sourceSets { - // Diese Abhängigkeiten sind für alle Plattformen (JVM, JS) verfügbar val commonTest by getting { dependencies { - // Die 'kotlin("test")'-Abhängigkeit ist der Standardweg für KMP-Tests implementation(kotlin("test")) api(libs.kotlinx.coroutines.test) } } - // Diese Abhängigkeiten sind NUR für die JVM-Tests verfügbar val jvmTest by getting { dependencies { api(libs.junit.jupiter.api) @@ -28,7 +23,6 @@ kotlin { api(libs.junit.jupiter.params) api(libs.junit.platform.launcher) - // KORREKTUR: Alle hartcodierten Versionen durch Aliase ersetzen api(libs.mockk) api(libs.assertj.core) api(libs.spring.boot.starter.test) @@ -40,4 +34,24 @@ kotlin { } } } +}*/ + +// Dieses Modul bündelt alle für JVM-Tests notwendigen Abhängigkeiten. +// Jedes Modul, das Tests enthält, sollte dieses Modul mit `testImplementation` einbinden. +plugins { + alias(libs.plugins.kotlin.jvm) +} + +dependencies { + // Importiert die zentrale BOM für konsistente Versionen. + api(platform(projects.platform.platformBom)) + + // OPTIMIERUNG: Verwendung von Bundles, um die Konfiguration zu vereinfachen. + // Diese Bundles sind in `libs.versions.toml` definiert. + api(libs.bundles.testing.jvm) + api(libs.bundles.testcontainers) + + // Einzelne Test-Abhängigkeiten, die nicht in den Haupt-Bundles enthalten sind. + api(libs.spring.boot.starter.test) + api(libs.h2.driver) // H2 wird oft für In-Memory-Tests benötigt. } diff --git a/settings.gradle.kts b/settings.gradle.kts index d6aba257..24b008ae 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,25 +17,6 @@ pluginManagement { dependencyResolutionManagement { - /*repositories { - mavenCentral() - google { - mavenContent { - includeGroupAndSubgroups("androidx") - includeGroupAndSubgroups("com.android") - includeGroupAndSubgroups("com.google") - } - } - // Add JitPack repository - maven { - url = uri("https://jitpack.io") - } - // Add Sonatype snapshots repository - maven { - url = uri("https://oss.sonatype.org/content/repositories/snapshots/") - } - }*/ - repositories { mavenCentral() google() @@ -44,15 +25,30 @@ dependencyResolutionManagement { } } +// Core modules +include(":core:core-domain") +include(":core:core-utils") + // Platform modules include(":platform:platform-bom") include(":platform:platform-dependencies") include(":platform:platform-testing") -// Core modules -include(":core:core-domain") -include(":core:core-utils") +// Infrastructure modules +include(":infrastructure:gateway") +include(":infrastructure:auth:auth-client") +include(":infrastructure:auth:auth-server") +include(":infrastructure:messaging:messaging-client") +include(":infrastructure:messaging:messaging-config") +include(":infrastructure:cache:cache-api") +include(":infrastructure:cache:redis-cache") +include(":infrastructure:event-store:event-store-api") +include(":infrastructure:event-store:redis-event-store") +include(":infrastructure:monitoring:monitoring-client") +include(":infrastructure:monitoring:monitoring-server") +/* +// Temporär deaktivierte Fach-Module // Members modules include(":members:members-domain") include(":members:members-application") @@ -81,22 +77,11 @@ include(":masterdata:masterdata-infrastructure") include(":masterdata:masterdata-api") include(":masterdata:masterdata-service") -// Infrastructure modules -include(":infrastructure:gateway") -include(":infrastructure:auth:auth-client") -include(":infrastructure:auth:auth-server") -include(":infrastructure:messaging:messaging-client") -include(":infrastructure:messaging:messaging-config") -include(":infrastructure:cache:cache-api") -include(":infrastructure:cache:redis-cache") -include(":infrastructure:event-store:event-store-api") -include(":infrastructure:event-store:redis-event-store") -include(":infrastructure:monitoring:monitoring-client") -include(":infrastructure:monitoring:monitoring-server") - // Client modules include(":client:common-ui") include(":client:web-app") include(":client:desktop-app") // Legacy modules have been removed after successful migration + + */