fixing Frontend und libs.versions.toml

This commit is contained in:
2025-10-07 15:26:12 +02:00
parent 829d0fe8ec
commit 245584ee82
20 changed files with 4151 additions and 60 deletions
+1 -1
View File
@@ -134,7 +134,7 @@ DATA_PATH=./data
DEBUG=false DEBUG=false
# Enable Wasm compilation for client applications # Enable Wasm compilation for client applications
enableWasm=false ENABLE_WASM=false
# =================================================================== # ===================================================================
# Production Deployment Settings # Production Deployment Settings
+102 -2
View File
@@ -1,5 +1,14 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat @file:OptIn(ExperimentalKotlinGradlePluginApi::class)
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
/**
* Dieses Modul ist der "Host". Es kennt alle Features und die Shared-Module und
* setzt sie zu einer lauffähigen Anwendung zusammen.
*/
plugins { plugins {
alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.composeCompiler) alias(libs.plugins.composeCompiler)
@@ -8,19 +17,59 @@ plugins {
} }
kotlin { kotlin {
val enableWasm = providers.gradleProperty("enableWasm").orNull == "true"
jvmToolchain(21)
// JVM Target für Desktop // JVM Target für Desktop
jvm() jvm {
binaries {
executable {
mainClass.set("MainKt")
}
}
}
// JavaScript Target für Web // JavaScript Target für Web
js(IR) { js(IR) {
browser { browser {
commonWebpackConfig {
cssSupport { enabled = true }
// Webpack-Mode abhängig von Build-Typ
mode = if (project.hasProperty("production"))
KotlinWebpackConfig.Mode.PRODUCTION
else
KotlinWebpackConfig.Mode.DEVELOPMENT
}
webpackTask { webpackTask {
mainOutputFileName = "web-app.js" mainOutputFileName = "web-app.js"
output.libraryTarget = "commonjs2"
}
// Development Server konfigurieren
runTask {
mainOutputFileName.set("web-app.js")
}
// Browser-Tests komplett deaktivieren (Configuration Cache kompatibel)
testTask {
// enabled = false
useKarma {
useChromeHeadless()
environment("CHROME_BIN", "/usr/bin/google-chrome-stable")
}
} }
} }
binaries.executable() binaries.executable()
} }
// WASM, nur wenn explizit aktiviert
if (enableWasm) {
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs { browser() }
}
sourceSets { sourceSets {
commonMain.dependencies { commonMain.dependencies {
// Shared modules // Shared modules
@@ -35,6 +84,10 @@ kotlin {
implementation(compose.material3) implementation(compose.material3)
implementation(compose.ui) implementation(compose.ui)
implementation(compose.components.resources) implementation(compose.components.resources)
implementation(compose.materialIconsExtended)
// ViewModel lifecycle
implementation(libs.androidx.lifecycle.viewmodelCompose)
// Coroutines // Coroutines
implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.coroutines.core)
@@ -46,14 +99,61 @@ kotlin {
jvmMain.dependencies { jvmMain.dependencies {
implementation(compose.desktop.currentOs) implementation(compose.desktop.currentOs)
implementation(libs.kotlinx.coroutines.swing) implementation(libs.kotlinx.coroutines.swing)
implementation(libs.kotlinx.coroutines.core)
} }
jsMain.dependencies { jsMain.dependencies {
implementation(compose.html.core) implementation(compose.html.core)
} }
// WASM SourceSet, nur wenn aktiviert
if (enableWasm) {
val wasmJsMain = getByName("wasmJsMain")
wasmJsMain.dependencies {
implementation(libs.ktor.client.js) // WASM verwendet JS-Client [cite: 7]
// ✅ HINZUFÜGEN: Compose für shared UI components für WASM
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
}
}
commonTest.dependencies {
implementation(libs.kotlin.test)
}
} }
} }
// KMP Compile-Optionen
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
freeCompilerArgs.addAll(
"-opt-in=kotlin.RequiresOptIn",
"-Xskip-metadata-version-check" // Für bleeding-edge Versionen
)
}
}
//// Configure duplicate handling strategy for distribution tasks
//tasks.withType<Tar> {
// duplicatesStrategy = DuplicatesStrategy.EXCLUDE
//}
//
//tasks.withType<Zip> {
// duplicatesStrategy = DuplicatesStrategy.EXCLUDE
//}
// Duplicate-Handling für Distribution
tasks.withType<Copy> {
duplicatesStrategy = DuplicatesStrategy.WARN // Statt EXCLUDE
}
tasks.withType<Sync> {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
// Desktop Application Configuration // Desktop Application Configuration
compose.desktop { compose.desktop {
application { application {
+3833
View File
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
{
"devDependencies": {
"@types/jest": "^29.2.5",
"jest": "^29.3.1"
},
"scripts": {
"test": "jest"
},
"dependencies": {
"webpack-bundle-analyzer": "^4.10.2"
}
}
+44 -3
View File
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
/** /**
* Dieses Modul kapselt die gesamte UI und Logik für das Authentication-Feature. * Dieses Modul kapselt die gesamte UI und Logik für das Authentication-Feature.
* Es kennt seine eigenen technischen Abhängigkeiten (Ktor, Coroutines) * Es kennt seine eigenen technischen Abhängigkeiten (Ktor, Coroutines)
@@ -28,33 +30,43 @@ kotlin {
} }
} }
// WASM, nur wenn explizit aktiviert
if (enableWasm) { if (enableWasm) {
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class) @OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs { wasmJs { browser() }
browser()
}
} }
sourceSets { sourceSets {
commonMain.dependencies { commonMain.dependencies {
// UI Kit // UI Kit
implementation(project(":clients:shared:common-ui")) implementation(project(":clients:shared:common-ui"))
// Compose dependencies // Compose dependencies
implementation(compose.runtime) implementation(compose.runtime)
implementation(compose.foundation) implementation(compose.foundation)
implementation(compose.material3) implementation(compose.material3)
implementation(compose.ui) implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.materialIconsExtended)
// Ktor client for HTTP calls // Ktor client for HTTP calls
implementation(libs.ktor.client.core) implementation(libs.ktor.client.core)
implementation(libs.ktor.client.contentNegotiation) implementation(libs.ktor.client.contentNegotiation)
implementation(libs.ktor.client.serialization.kotlinx.json) implementation(libs.ktor.client.serialization.kotlinx.json)
implementation(libs.ktor.client.logging)
implementation(libs.ktor.client.auth)
// Coroutines and serialization // Coroutines and serialization
implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json) implementation(libs.kotlinx.serialization.json)
// DateTime for multiplatform time handling // DateTime for multiplatform time handling
implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.datetime)
// ViewModel lifecycle // ViewModel lifecycle
implementation(libs.androidx.lifecycle.viewmodelCompose) implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
} }
commonTest.dependencies { commonTest.dependencies {
@@ -65,6 +77,8 @@ kotlin {
jvmTest.dependencies { jvmTest.dependencies {
implementation(libs.mockk) implementation(libs.mockk)
implementation(projects.platform.platformTesting)
implementation(libs.bundles.testing.jvm)
} }
jvmMain.dependencies { jvmMain.dependencies {
@@ -73,6 +87,33 @@ kotlin {
jsMain.dependencies { jsMain.dependencies {
implementation(libs.ktor.client.js) implementation(libs.ktor.client.js)
implementation(libs.ktor.client.auth)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.kotlinx.datetime)
}
// WASM SourceSet, nur wenn aktiviert
if (enableWasm) {
val wasmJsMain = getByName("wasmJsMain")
wasmJsMain.dependencies {
implementation(libs.ktor.client.js) // WASM verwendet JS-Client [cite: 7]
// ✅ HINZUFÜGEN: Compose für shared UI components für WASM
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
}
} }
} }
} }
// KMP Compile-Optionen
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
freeCompilerArgs.addAll(
"-opt-in=kotlin.RequiresOptIn"
)
}
}
+42 -4
View File
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
/** /**
* Dieses Modul kapselt die gesamte UI und Logik für das Ping-Feature. * Dieses Modul kapselt die gesamte UI und Logik für das Ping-Feature.
* Es kennt seine eigenen technischen Abhängigkeiten (Ktor, Coroutines) * Es kennt seine eigenen technischen Abhängigkeiten (Ktor, Coroutines)
@@ -28,55 +30,91 @@ kotlin {
} }
} }
// WASM, nur wenn explizit aktiviert
if (enableWasm) { if (enableWasm) {
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class) @OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs { wasmJs { browser() }
browser()
}
} }
sourceSets { sourceSets {
commonMain.dependencies { commonMain.dependencies {
// Contract from backend // Contract from backend
implementation(projects.services.ping.pingApi) implementation(projects.services.ping.pingApi)
// UI Kit // UI Kit
implementation(project(":clients:shared:common-ui")) implementation(project(":clients:shared:common-ui"))
// Compose dependencies // Compose dependencies
implementation(compose.runtime) implementation(compose.runtime)
implementation(compose.foundation) implementation(compose.foundation)
implementation(compose.material3) implementation(compose.material3)
implementation(compose.ui) implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.materialIconsExtended)
// Ktor client for HTTP calls // Ktor client for HTTP calls
implementation(libs.ktor.client.core) implementation(libs.ktor.client.core)
implementation(libs.ktor.client.contentNegotiation) implementation(libs.ktor.client.contentNegotiation)
implementation(libs.ktor.client.serialization.kotlinx.json) implementation(libs.ktor.client.serialization.kotlinx.json)
implementation(libs.ktor.client.logging)
implementation(libs.ktor.client.auth)
// Coroutines and serialization // Coroutines and serialization
implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.datetime)
implementation(libs.kotlinx.serialization.json) implementation(libs.kotlinx.serialization.json)
// ViewModel lifecycle // ViewModel lifecycle
implementation(libs.androidx.lifecycle.viewmodelCompose) implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
} }
commonTest.dependencies { commonTest.dependencies {
implementation(libs.kotlin.test) implementation(libs.kotlin.test)
implementation(libs.kotlinx.coroutines.test) implementation(libs.kotlinx.coroutines.test)
implementation("io.ktor:ktor-client-mock:${libs.versions.ktor.get()}") implementation("io.ktor:ktor-client-mock:${libs.versions.ktor.get()}")
} }
jvmTest.dependencies { jvmTest.dependencies {
implementation(libs.mockk) implementation(libs.mockk)
implementation(projects.platform.platformTesting)
implementation(libs.bundles.testing.jvm)
} }
jvmMain.dependencies { jvmMain.dependencies {
implementation(libs.ktor.client.cio) implementation(libs.ktor.client.cio)
// Auth-Models Zugriff (nur für JVM) // Auth-Models Zugriff (nur für JVM)
implementation(project(":infrastructure:auth:auth-client")) //implementation(project(":infrastructure:auth:auth-client"))
} }
jsMain.dependencies { jsMain.dependencies {
implementation(libs.ktor.client.js) implementation(libs.ktor.client.js)
} }
// WASM SourceSet, nur wenn aktiviert
if (enableWasm) {
val wasmJsMain = getByName("wasmJsMain")
wasmJsMain.dependencies {
implementation(libs.ktor.client.js) // WASM verwendet JS-Client [cite: 7]
// ✅ HINZUFÜGEN: Compose für shared UI components für WASM
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
}
}
}
}
// KMP Compile-Optionen
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
freeCompilerArgs.addAll(
"-opt-in=kotlin.RequiresOptIn"
)
} }
} }
+60 -9
View File
@@ -1,19 +1,36 @@
@file:OptIn(ExperimentalKotlinGradlePluginApi::class)
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
/**
* Shared Module: Gemeinsame Libraries und Utilities für alle Client-Features
* KEINE EXECUTABLE - ist eine Library für andere Module
*/
plugins { plugins {
alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.kotlinSerialization) alias(libs.plugins.kotlinSerialization)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
} }
kotlin { kotlin {
val enableWasm = providers.gradleProperty("enableWasm").orNull == "true"
jvmToolchain(21) jvmToolchain(21)
// JVM Target für Desktop
jvm() jvm()
// JavaScript Target für Web
js(IR) { js(IR) {
browser() browser()
nodejs()
} }
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs { // WASM, nur wenn explizit aktiviert
browser() if (enableWasm) {
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs { browser() }
} }
sourceSets { sourceSets {
@@ -25,14 +42,15 @@ kotlin {
implementation(libs.kotlinx.serialization.json) implementation(libs.kotlinx.serialization.json)
// HTTP Client // HTTP Client
implementation(libs.ktor.client.core) // implementation(libs.ktor.client.core)
implementation(libs.ktor.client.contentNegotiation) // implementation(libs.ktor.client.contentNegotiation)
implementation(libs.ktor.client.serialization.kotlinx.json) // implementation(libs.ktor.client.serialization.kotlinx.json)
implementation(libs.ktor.client.logging) // implementation(libs.ktor.client.logging)
implementation(libs.ktor.client.auth) // implementation(libs.ktor.client.auth)
// DateTime // DateTime
implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.datetime)
} }
commonTest.dependencies { commonTest.dependencies {
@@ -42,10 +60,43 @@ kotlin {
jsMain.dependencies { jsMain.dependencies {
implementation(libs.ktor.client.js) implementation(libs.ktor.client.js)
// Compose für shared UI components
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
} }
jvmMain.dependencies { jvmMain.dependencies {
implementation(libs.ktor.client.cio) implementation(libs.ktor.client.cio)
// Compose für shared UI components
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
}
// WASM SourceSet, nur wenn aktiviert
if (enableWasm) {
val wasmJsMain = getByName("wasmJsMain")
wasmJsMain.dependencies {
implementation(libs.ktor.client.js) // WASM verwendet JS-Client [cite: 7]
// ✅ HINZUFÜGEN: Compose für shared UI components für WASM
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
}
} }
} }
} }
// KMP Compile-Optionen
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
freeCompilerArgs.addAll(
"-opt-in=kotlin.RequiresOptIn"
)
}
}
+2 -2
View File
@@ -94,8 +94,8 @@ API_KEY=meldestelle-api-key-for-development
# ============================================================================= # =============================================================================
# 6. KEYCLOAK CONFIGURATION # 6. KEYCLOAK CONFIGURATION
# ============================================================================= # =============================================================================
KEYCLOAK_ADMIN=admin KC_BOOTSTRAP_ADMIN_USERNAME=admin
KEYCLOAK_ADMIN_PASSWORD=admin KC_BOOTSTRAP_ADMIN_PASSWORD=admin
KC_DB=postgres KC_DB=postgres
KC_DB_URL=jdbc:postgresql://postgres:5432/meldestelle KC_DB_URL=jdbc:postgresql://postgres:5432/meldestelle
KC_DB_SCHEMA=keycloak KC_DB_SCHEMA=keycloak
+9 -1
View File
@@ -21,12 +21,20 @@ kotlin {
} }
sourceSets { sourceSets {
// Opt-in to experimental Kotlin UUID API across all source sets
all {
languageSettings.optIn("kotlin.uuid.ExperimentalUuidApi")
}
commonMain.dependencies { commonMain.dependencies {
// Core dependencies (that aren't included in platform-dependencies) // Core dependencies (that aren't included in platform-dependencies)
api(libs.uuid) api(projects.core.coreUtils)
api(projects.core.coreDomain)
// Serialization and date-time for commonMain // Serialization and date-time for commonMain
api(libs.kotlinx.serialization.json) api(libs.kotlinx.serialization.json)
api(libs.kotlinx.datetime) api(libs.kotlinx.datetime)
} }
commonTest.dependencies { commonTest.dependencies {
@@ -1,12 +1,13 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.core.domain.event package at.mocode.core.domain.event
import at.mocode.core.domain.model.* import at.mocode.core.domain.model.*
import at.mocode.core.domain.serialization.KotlinInstantSerializer import at.mocode.core.domain.serialization.KotlinInstantSerializer
import com.benasher44.uuid.uuid4 import kotlinx.serialization.Serializable
import kotlin.time.Clock import kotlin.time.Clock
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
import kotlin.time.Instant import kotlin.time.Instant
import kotlinx.serialization.Serializable import kotlin.uuid.Uuid
/** /**
* Basis-Interface für alle Domain-Events im System. * Basis-Interface für alle Domain-Events im System.
@@ -32,7 +33,7 @@ abstract class BaseDomainEvent(
override val aggregateId: AggregateId, override val aggregateId: AggregateId,
override val eventType: EventType, override val eventType: EventType,
override val version: EventVersion, override val version: EventVersion,
override val eventId: EventId = EventId(uuid4()), override val eventId: EventId = EventId(Uuid.random()),
@Serializable(with = KotlinInstantSerializer::class) @Serializable(with = KotlinInstantSerializer::class)
override val timestamp: Instant, override val timestamp: Instant,
override val correlationId: CorrelationId? = null, override val correlationId: CorrelationId? = null,
@@ -43,7 +44,7 @@ abstract class BaseDomainEvent(
aggregateId: AggregateId, aggregateId: AggregateId,
eventType: EventType, eventType: EventType,
version: EventVersion, version: EventVersion,
eventId: EventId = EventId(uuid4()), eventId: EventId = EventId(Uuid.random()),
correlationId: CorrelationId? = null, correlationId: CorrelationId? = null,
causationId: CausationId? = null causationId: CausationId? = null
) : this( ) : this(
@@ -1,9 +1,10 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.core.domain.model package at.mocode.core.domain.model
import at.mocode.core.domain.serialization.UuidSerializer import at.mocode.core.domain.serialization.UuidSerializer
import com.benasher44.uuid.Uuid
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlin.jvm.JvmInline import kotlin.jvm.JvmInline
import kotlin.uuid.Uuid
/** /**
* Value-Classes für stark typisierte IDs und Fachwerte. * Value-Classes für stark typisierte IDs und Fachwerte.
@@ -1,7 +1,5 @@
package at.mocode.core.domain.serialization package at.mocode.core.domain.serialization
import com.benasher44.uuid.Uuid
import com.benasher44.uuid.uuidFrom
import kotlinx.datetime.LocalDate import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.LocalTime import kotlinx.datetime.LocalTime
@@ -13,6 +11,8 @@ import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
import kotlin.time.Instant import kotlin.time.Instant
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
/** /**
* Serializer für kotlin.time. Instant Objekte. * Serializer für kotlin.time. Instant Objekte.
@@ -35,6 +35,7 @@ object KotlinInstantSerializer : KSerializer<Instant> {
* Serializer für UUID Objekte. * Serializer für UUID Objekte.
* Konvertiert UUID zu/von String-Repräsentation. * Konvertiert UUID zu/von String-Repräsentation.
*/ */
@OptIn(ExperimentalUuidApi::class)
object UuidSerializer : KSerializer<Uuid> { object UuidSerializer : KSerializer<Uuid> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING) override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING)
@@ -43,7 +44,7 @@ object UuidSerializer : KSerializer<Uuid> {
} }
override fun deserialize(decoder: Decoder): Uuid { override fun deserialize(decoder: Decoder): Uuid {
return uuidFrom(decoder.decodeString()) return Uuid.parse(decoder.decodeString())
} }
} }
@@ -1,10 +1,11 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.core.utils package at.mocode.core.utils
import at.mocode.core.domain.model.* import at.mocode.core.domain.model.*
import com.benasher44.uuid.uuid4 import kotlin.time.Clock
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
import kotlin.time.Instant import kotlin.time.Instant
import kotlin.time.Clock import kotlin.uuid.Uuid
/** /**
* Extension-Funktionen für häufig verwendete Operationen im gesamten System. * Extension-Funktionen für häufig verwendete Operationen im gesamten System.
@@ -15,27 +16,27 @@ import kotlin.time.Clock
/** /**
* Erstellt eine neue EntityId mit einer zufälligen UUID. * Erstellt eine neue EntityId mit einer zufälligen UUID.
*/ */
fun EntityId.Companion.random(): EntityId = EntityId(uuid4()) fun EntityId.Companion.random(): EntityId = EntityId(Uuid.random())
/** /**
* Erstellt eine neue EventId mit einer zufälligen UUID. * Erstellt eine neue EventId mit einer zufälligen UUID.
*/ */
fun EventId.Companion.random(): EventId = EventId(uuid4()) fun EventId.Companion.random(): EventId = EventId(Uuid.random())
/** /**
* Erstellt eine neue AggregateId mit einer zufälligen UUID. * Erstellt eine neue AggregateId mit einer zufälligen UUID.
*/ */
fun AggregateId.Companion.random(): AggregateId = AggregateId(uuid4()) fun AggregateId.Companion.random(): AggregateId = AggregateId(Uuid.random())
/** /**
* Erstellt eine neue CorrelationId mit einer zufälligen UUID. * Erstellt eine neue CorrelationId mit einer zufälligen UUID.
*/ */
fun CorrelationId.Companion.random(): CorrelationId = CorrelationId(uuid4()) fun CorrelationId.Companion.random(): CorrelationId = CorrelationId(Uuid.random())
/** /**
* Erstellt eine neue CausationId mit einer zufälligen UUID. * Erstellt eine neue CausationId mit einer zufälligen UUID.
*/ */
fun CausationId.Companion.random(): CausationId = CausationId(uuid4()) fun CausationId.Companion.random(): CausationId = CausationId(Uuid.random())
// === String Extensions === // === String Extensions ===
+4 -2
View File
@@ -64,8 +64,10 @@ services:
# Using base image directly instead of custom Dockerfile # Using base image directly instead of custom Dockerfile
environment: environment:
# Admin Configuration # Admin Configuration
KEYCLOAK_ADMIN: admin # KEYCLOAK_ADMIN: admin # is deprecated
KEYCLOAK_ADMIN_PASSWORD: admin # KEYCLOAK_ADMIN_PASSWORD: admin # is deprecated
KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_BOOTSTRAP_ADMIN_USERNAME:-admin}
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_BOOTSTRAP_ADMIN_PASSWORD:-admin}
# Database Configuration # Database Configuration
KC_DB: postgres KC_DB: postgres
+1
View File
@@ -62,3 +62,4 @@ services.port.events=8085
dev.port.offset=0 dev.port.offset=0
# Set dev.port.offset=100 for second developer # Set dev.port.offset=100 for second developer
# Set dev.port.offset=200 for third developer # Set dev.port.offset=200 for third developer
enableWasm=false
+3 -3
View File
@@ -61,7 +61,7 @@ testcontainersKeycloak = "3.9.0"
resilience4j = "2.3.0" resilience4j = "2.3.0"
# --- Utilities --- # --- Utilities ---
uuid = "0.8.4" #uuid = "0.9.0"
bignum = "0.3.10" bignum = "0.3.10"
logback = "1.5.18" logback = "1.5.18"
caffeine = "3.2.2" caffeine = "3.2.2"
@@ -167,8 +167,8 @@ auth0-java-jwt = { module = "com.auth0:java-jwt", version.ref = "auth0Jwt" }
keycloak-admin-client = { module = "org.keycloak:keycloak-admin-client", version.ref = "keycloakAdminClient" } keycloak-admin-client = { module = "org.keycloak:keycloak-admin-client", version.ref = "keycloakAdminClient" }
# --- Utilities --- # --- Utilities ---
uuid = { module = "com.benasher44:uuid", version.ref = "uuid" } #uuid = { module = "com.benasher44:uuid", version.ref = "uuid" }
uuid-jvm = { module = "com.benasher44:uuid-jvm", version.ref = "uuid" } #uuid-jvm = { module = "com.benasher44:uuid-jvm", version.ref = "uuid" }
bignum = { module = "com.ionspin.kotlin:bignum", version.ref = "bignum" } bignum = { module = "com.ionspin.kotlin:bignum", version.ref = "bignum" }
logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "logback" }
logback-core = { module = "ch.qos.logback:logback-core", version.ref = "logback" } logback-core = { module = "ch.qos.logback:logback-core", version.ref = "logback" }
+1 -1
View File
@@ -26,7 +26,7 @@ dependencies {
api(libs.caffeine) api(libs.caffeine)
api(libs.reactor.kafka) api(libs.reactor.kafka)
api(libs.redisson) api(libs.redisson)
api(libs.uuid) // Removed legacy UUID library constraint (com.benasher44:uuid) since project uses Kotlin stdlib UUID
api(libs.bignum) api(libs.bignum)
// api(libs.consul.client) wird getauscht mir spring-cloud-starter-consul-discovery // api(libs.consul.client) wird getauscht mir spring-cloud-starter-consul-discovery
api(libs.spring.cloud.starter.consul.discovery) api(libs.spring.cloud.starter.consul.discovery)
@@ -1,3 +1,4 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.events.api.rest package at.mocode.events.api.rest
import at.mocode.core.domain.model.ApiResponse import at.mocode.core.domain.model.ApiResponse
@@ -9,8 +10,7 @@ import at.mocode.events.application.usecase.UpdateVeranstaltungUseCase
import at.mocode.events.domain.repository.VeranstaltungRepository import at.mocode.events.domain.repository.VeranstaltungRepository
import at.mocode.core.domain.serialization.UuidSerializer import at.mocode.core.domain.serialization.UuidSerializer
import at.mocode.core.utils.validation.ApiValidationUtils import at.mocode.core.utils.validation.ApiValidationUtils
import com.benasher44.uuid.Uuid import kotlin.uuid.Uuid
import com.benasher44.uuid.uuidFrom
import io.ktor.http.* import io.ktor.http.*
import io.ktor.server.request.* import io.ktor.server.request.*
import io.ktor.server.response.* import io.ktor.server.response.*
@@ -91,7 +91,7 @@ class VeranstaltungController(
// GET /api/events/{id} - Get event by ID // GET /api/events/{id} - Get event by ID
get("/{id}") { get("/{id}") {
try { try {
val eventId = uuidFrom(call.parameters["id"]!!) val eventId = Uuid.parse(call.parameters["id"]!!)
val request = GetVeranstaltungUseCase.GetVeranstaltungRequest(eventId) val request = GetVeranstaltungUseCase.GetVeranstaltungRequest(eventId)
val response = getVeranstaltungUseCase.execute(request) val response = getVeranstaltungUseCase.execute(request)
@@ -180,7 +180,7 @@ class VeranstaltungController(
// PUT /api/events/{id} - Update event // PUT /api/events/{id} - Update event
put("/{id}") { put("/{id}") {
try { try {
val eventId = uuidFrom(call.parameters["id"]!!) val eventId = Uuid.parse(call.parameters["id"]!!)
val updateRequest = call.receive<UpdateEventRequest>() val updateRequest = call.receive<UpdateEventRequest>()
// Validate input using shared validation utilities // Validate input using shared validation utilities
@@ -1,3 +1,4 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.horses.api.rest package at.mocode.horses.api.rest
import at.mocode.core.domain.model.ApiResponse import at.mocode.core.domain.model.ApiResponse
@@ -8,8 +9,7 @@ import at.mocode.horses.application.usecase.GetHorseUseCase
import at.mocode.horses.application.usecase.UpdateHorseUseCase import at.mocode.horses.application.usecase.UpdateHorseUseCase
import at.mocode.horses.domain.repository.HorseRepository import at.mocode.horses.domain.repository.HorseRepository
import at.mocode.core.utils.validation.ApiValidationUtils import at.mocode.core.utils.validation.ApiValidationUtils
import com.benasher44.uuid.Uuid import kotlin.uuid.Uuid
import com.benasher44.uuid.uuidFrom
import io.ktor.http.* import io.ktor.http.*
import io.ktor.server.request.* import io.ktor.server.request.*
import io.ktor.server.response.* import io.ktor.server.response.*
@@ -93,7 +93,7 @@ class HorseController(
// GET /api/horses/{id} - Get horse by ID // GET /api/horses/{id} - Get horse by ID
get("/{id}") { get("/{id}") {
try { try {
val horseId = uuidFrom(call.parameters["id"]!!) val horseId = Uuid.parse(call.parameters["id"]!!)
val horse = getHorseUseCase.getById(horseId) val horse = getHorseUseCase.getById(horseId)
if (horse != null) { if (horse != null) {
@@ -266,7 +266,7 @@ class HorseController(
// PUT /api/horses/{id} - Update horse // PUT /api/horses/{id} - Update horse
put("/{id}") { put("/{id}") {
try { try {
val horseId = uuidFrom(call.parameters["id"]!!) val horseId = Uuid.parse(call.parameters["id"]!!)
val updateData = call.receive<UpdateHorseRequest>() val updateData = call.receive<UpdateHorseRequest>()
// Validate input using shared validation utilities // Validate input using shared validation utilities
@@ -328,7 +328,7 @@ class HorseController(
// DELETE /api/horses/{id} - Delete horse // DELETE /api/horses/{id} - Delete horse
delete("/{id}") { delete("/{id}") {
try { try {
val horseId = uuidFrom(call.parameters["id"]!!) val horseId = Uuid.parse(call.parameters["id"]!!)
val forceDelete = call.request.queryParameters["force"]?.toBoolean() ?: false val forceDelete = call.request.queryParameters["force"]?.toBoolean() ?: false
val deleteRequest = DeleteHorseUseCase.DeleteHorseRequest(horseId, forceDelete) val deleteRequest = DeleteHorseUseCase.DeleteHorseRequest(horseId, forceDelete)
@@ -354,7 +354,7 @@ class HorseController(
// POST /api/horses/{id}/soft-delete - Soft delete horse (mark as inactive) // POST /api/horses/{id}/soft-delete - Soft delete horse (mark as inactive)
post("/{id}/soft-delete") { post("/{id}/soft-delete") {
try { try {
val horseId = uuidFrom(call.parameters["id"]!!) val horseId = Uuid.parse(call.parameters["id"]!!)
val response = deleteHorseUseCase.softDelete(horseId) val response = deleteHorseUseCase.softDelete(horseId)
if (response.success) { if (response.success) {
@@ -1,3 +1,4 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.masterdata.api.rest package at.mocode.masterdata.api.rest
import at.mocode.core.domain.model.ApiResponse import at.mocode.core.domain.model.ApiResponse
@@ -6,7 +7,7 @@ import at.mocode.masterdata.application.usecase.CreateAltersklasseUseCase
import at.mocode.masterdata.application.usecase.GetAltersklasseUseCase import at.mocode.masterdata.application.usecase.GetAltersklasseUseCase
import at.mocode.masterdata.domain.model.AltersklasseDefinition import at.mocode.masterdata.domain.model.AltersklasseDefinition
import at.mocode.core.utils.validation.ApiValidationUtils import at.mocode.core.utils.validation.ApiValidationUtils
import com.benasher44.uuid.uuidFrom import kotlin.uuid.Uuid
import io.ktor.http.* import io.ktor.http.*
import io.ktor.server.request.* import io.ktor.server.request.*
import io.ktor.server.response.* import io.ktor.server.response.*
@@ -119,7 +120,7 @@ class AltersklasseController(
// GET /api/masterdata/altersklassen/{id} - Get age class by ID // GET /api/masterdata/altersklassen/{id} - Get age class by ID
get("/{id}") { get("/{id}") {
try { try {
val altersklasseId = call.parameters["id"]?.let { uuidFrom(it) } val altersklasseId = call.parameters["id"]?.let { Uuid.parse(it) }
?: return@get call.respond(HttpStatusCode.BadRequest, ApiResponse.error<AltersklasseDto>("Invalid age class ID")) ?: return@get call.respond(HttpStatusCode.BadRequest, ApiResponse.error<AltersklasseDto>("Invalid age class ID"))
val altersklasse = getAltersklasseUseCase.getById(altersklasseId) val altersklasse = getAltersklasseUseCase.getById(altersklasseId)
@@ -285,7 +286,7 @@ class AltersklasseController(
val oetoRegelReferenzId = createDto.oetoRegelReferenzId?.let { val oetoRegelReferenzId = createDto.oetoRegelReferenzId?.let {
try { try {
uuidFrom(it) Uuid.parse(it)
} catch (_: Exception) { } catch (_: Exception) {
return@post call.respond( return@post call.respond(
HttpStatusCode.BadRequest, HttpStatusCode.BadRequest,
@@ -320,7 +321,7 @@ class AltersklasseController(
// PUT /api/masterdata/altersklassen/{id} - Update existing age class // PUT /api/masterdata/altersklassen/{id} - Update existing age class
put("/{id}") { put("/{id}") {
try { try {
val altersklasseId = call.parameters["id"]?.let { uuidFrom(it) } val altersklasseId = call.parameters["id"]?.let { Uuid.parse(it) }
?: return@put call.respond(HttpStatusCode.BadRequest, ApiResponse.error<AltersklasseDto>("Invalid age class ID")) ?: return@put call.respond(HttpStatusCode.BadRequest, ApiResponse.error<AltersklasseDto>("Invalid age class ID"))
val updateDto = call.receive<UpdateAltersklasseDto>() val updateDto = call.receive<UpdateAltersklasseDto>()
@@ -366,7 +367,7 @@ class AltersklasseController(
val oetoRegelReferenzId = updateDto.oetoRegelReferenzId?.let { val oetoRegelReferenzId = updateDto.oetoRegelReferenzId?.let {
try { try {
uuidFrom(it) Uuid.parse(it)
} catch (_: Exception) { } catch (_: Exception) {
return@put call.respond( return@put call.respond(
HttpStatusCode.BadRequest, HttpStatusCode.BadRequest,
@@ -402,7 +403,7 @@ class AltersklasseController(
// DELETE /api/masterdata/altersklassen/{id} - Delete age class // DELETE /api/masterdata/altersklassen/{id} - Delete age class
delete("/{id}") { delete("/{id}") {
try { try {
val altersklasseId = call.parameters["id"]?.let { uuidFrom(it) } val altersklasseId = call.parameters["id"]?.let { Uuid.parse(it) }
?: return@delete call.respond(HttpStatusCode.BadRequest, ApiResponse.error<Unit>("Invalid age class ID")) ?: return@delete call.respond(HttpStatusCode.BadRequest, ApiResponse.error<Unit>("Invalid age class ID"))
val result = createAltersklasseUseCase.deleteAltersklasse(altersklasseId) val result = createAltersklasseUseCase.deleteAltersklasse(altersklasseId)
@@ -419,7 +420,7 @@ class AltersklasseController(
// GET /api/masterdata/altersklassen/eligible/{id} - Check eligibility for age class // GET /api/masterdata/altersklassen/eligible/{id} - Check eligibility for age class
get("/eligible/{id}") { get("/eligible/{id}") {
try { try {
val altersklasseId = call.parameters["id"]?.let { uuidFrom(it) } val altersklasseId = call.parameters["id"]?.let { Uuid.parse(it) }
?: return@get call.respond(HttpStatusCode.BadRequest, ApiResponse.error<Boolean>("Invalid age class ID")) ?: return@get call.respond(HttpStatusCode.BadRequest, ApiResponse.error<Boolean>("Invalid age class ID"))
val ageParam = call.request.queryParameters["age"]?.toIntOrNull() val ageParam = call.request.queryParameters["age"]?.toIntOrNull()