From 4c382e64a51dbe9bde4a2530b98cf5e88c21dc16 Mon Sep 17 00:00:00 2001 From: stefan Date: Fri, 25 Jul 2025 13:14:44 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20Migrationsplan=20f=C3=BCr=20Projekt-Res?= =?UTF-8?q?trukturierung=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Detaillierter Plan zur Migration von alter zu neuer Modulstruktur - Umfasst Überführung von shared-kernel zu core-Modulen - Definiert Migration von Fachdomänen zu bounded contexts: * master-data → masterdata-Module * member-management → members-Module * horse-registry → horses-Module * event-management → events-Module - Beschreibt Verlagerung von api-gateway zu infrastructure/gateway - Strukturiert nach Domain-driven Design Prinzipien - Berücksichtigt Clean Architecture Layering (domain, application, infrastructure, api) --- build.gradle.kts | 4 +++- .../mocode/core/domain/event/DomainEvent.kt | 2 -- .../redis/RedisEventStoreIntegrationTest.kt | 4 +--- .../eventstore/redis/RedisEventStoreTest.kt | 8 +------ .../eventstore/redis/RedisIntegrationTest.kt | 3 +-- .../api/rest/AltersklasseController.kt | 12 +++++------ .../api/rest/BundeslandController.kt | 6 +++--- .../masterdata/api/rest/PlatzController.kt | 16 +++++++------- .../persistence/LandRepositoryImpl.kt | 3 +-- .../members/api/rest/MemberController.kt | 21 ++++++------------- .../MemberServiceIntegrationTest.kt | 11 +++++----- 11 files changed, 35 insertions(+), 55 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f844d4ee..67bd46f9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import java.util.Locale + plugins { kotlin("jvm") version "2.1.21" apply false kotlin("plugin.spring") version "2.1.21" apply false @@ -113,7 +115,7 @@ tasks.register("generateOpenApiDocs") { { "openapi": "3.0.3", "info": { - "title": "${moduleName.capitalize()} API", + "title": "${moduleName.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }} API", "description": "REST API for ${moduleName} management", "version": "1.0.0", "contact": { diff --git a/core/core-domain/src/main/kotlin/at/mocode/core/domain/event/DomainEvent.kt b/core/core-domain/src/main/kotlin/at/mocode/core/domain/event/DomainEvent.kt index 2eb90daa..61cf5157 100644 --- a/core/core-domain/src/main/kotlin/at/mocode/core/domain/event/DomainEvent.kt +++ b/core/core-domain/src/main/kotlin/at/mocode/core/domain/event/DomainEvent.kt @@ -2,8 +2,6 @@ package at.mocode.core.domain.event import com.benasher44.uuid.Uuid import com.benasher44.uuid.uuid4 -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant /** * Interface for all domain events in the system. diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreIntegrationTest.kt b/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreIntegrationTest.kt index b297128a..5808e8be 100644 --- a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreIntegrationTest.kt +++ b/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreIntegrationTest.kt @@ -4,7 +4,6 @@ import at.mocode.core.domain.event.BaseDomainEvent import at.mocode.core.domain.event.DomainEvent import at.mocode.infrastructure.eventstore.api.EventSerializer import at.mocode.infrastructure.eventstore.api.EventStore -import at.mocode.infrastructure.eventstore.api.Subscription import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -15,9 +14,8 @@ import org.testcontainers.containers.GenericContainer import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers import org.testcontainers.utility.DockerImageName -import java.time.Duration import java.time.Instant -import java.util.UUID +import java.util.* import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import kotlin.test.assertEquals diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreTest.kt b/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreTest.kt index 9767602b..78c8b806 100644 --- a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreTest.kt +++ b/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreTest.kt @@ -1,10 +1,8 @@ package at.mocode.infrastructure.eventstore.redis import at.mocode.core.domain.event.BaseDomainEvent -import at.mocode.core.domain.event.DomainEvent import at.mocode.infrastructure.eventstore.api.ConcurrencyException import at.mocode.infrastructure.eventstore.api.EventSerializer -import at.mocode.infrastructure.eventstore.api.Subscription import io.mockk.every import io.mockk.mockk import org.junit.jupiter.api.AfterEach @@ -19,12 +17,8 @@ import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers import org.testcontainers.utility.DockerImageName import java.time.Instant -import java.util.UUID -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit +import java.util.* import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue @Testcontainers class RedisEventStoreTest { diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisIntegrationTest.kt b/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisIntegrationTest.kt index 823a9f8f..06474233 100644 --- a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisIntegrationTest.kt +++ b/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisIntegrationTest.kt @@ -4,7 +4,6 @@ import at.mocode.core.domain.event.BaseDomainEvent import at.mocode.core.domain.event.DomainEvent import at.mocode.infrastructure.eventstore.api.EventSerializer import at.mocode.infrastructure.eventstore.api.EventStore -import at.mocode.infrastructure.eventstore.api.Subscription import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -16,7 +15,7 @@ import org.testcontainers.junit.jupiter.Container import org.testcontainers.junit.jupiter.Testcontainers import org.testcontainers.utility.DockerImageName import java.time.Instant -import java.util.UUID +import java.util.* import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import kotlin.test.assertEquals diff --git a/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/AltersklasseController.kt b/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/AltersklasseController.kt index ecbe1b1c..8e66a906 100644 --- a/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/AltersklasseController.kt +++ b/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/AltersklasseController.kt @@ -88,7 +88,7 @@ class AltersklasseController( val sparteFilter = sparteFilterParam?.let { try { SparteE.valueOf(it.uppercase()) - } catch (e: Exception) { + } catch (_: Exception) { return@get call.respond( HttpStatusCode.BadRequest, ApiResponse.error>("Invalid sparte parameter: $it") @@ -224,7 +224,7 @@ class AltersklasseController( val sparte = try { SparteE.valueOf(sparteParam.uppercase()) - } catch (e: Exception) { + } catch (_: Exception) { return@get call.respond(HttpStatusCode.BadRequest, ApiResponse.error>("Invalid sport type: $sparteParam")) } @@ -264,7 +264,7 @@ class AltersklasseController( val sparteFilter = createDto.sparteFilter?.let { try { SparteE.valueOf(it.uppercase()) - } catch (e: Exception) { + } catch (_: Exception) { return@post call.respond( HttpStatusCode.BadRequest, ApiResponse.error("Invalid sparte filter: $it") @@ -286,7 +286,7 @@ class AltersklasseController( val oetoRegelReferenzId = createDto.oetoRegelReferenzId?.let { try { uuidFrom(it) - } catch (e: Exception) { + } catch (_: Exception) { return@post call.respond( HttpStatusCode.BadRequest, ApiResponse.error("Invalid OETO regel referenz ID format") @@ -345,7 +345,7 @@ class AltersklasseController( val sparteFilter = updateDto.sparteFilter?.let { try { SparteE.valueOf(it.uppercase()) - } catch (e: Exception) { + } catch (_: Exception) { return@put call.respond( HttpStatusCode.BadRequest, ApiResponse.error("Invalid sparte filter: $it") @@ -367,7 +367,7 @@ class AltersklasseController( val oetoRegelReferenzId = updateDto.oetoRegelReferenzId?.let { try { uuidFrom(it) - } catch (e: Exception) { + } catch (_: Exception) { return@put call.respond( HttpStatusCode.BadRequest, ApiResponse.error("Invalid OETO regel referenz ID format") diff --git a/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/BundeslandController.kt b/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/BundeslandController.kt index 872cbd42..45155f6e 100644 --- a/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/BundeslandController.kt +++ b/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/BundeslandController.kt @@ -130,7 +130,7 @@ class BundeslandController( val landId = try { uuidFrom(landIdParam) - } catch (e: Exception) { + } catch (_: Exception) { return@get call.respond(HttpStatusCode.BadRequest, ApiResponse.error("Invalid country ID format")) } @@ -235,7 +235,7 @@ class BundeslandController( try { uuidFrom(createDto.landId) - } catch (e: Exception) { + } catch (_: Exception) { call.respond( HttpStatusCode.BadRequest, ApiResponse.error("Invalid country ID format") @@ -284,7 +284,7 @@ class BundeslandController( try { uuidFrom(updateDto.landId) - } catch (e: Exception) { + } catch (_: Exception) { call.respond( HttpStatusCode.BadRequest, ApiResponse.error("Invalid country ID format") diff --git a/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/PlatzController.kt b/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/PlatzController.kt index b1ee312e..0321f227 100644 --- a/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/PlatzController.kt +++ b/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/PlatzController.kt @@ -153,7 +153,7 @@ class PlatzController( val typ = try { PlatzTypE.valueOf(typParam.uppercase()) - } catch (e: Exception) { + } catch (_: Exception) { return@get call.respond(HttpStatusCode.BadRequest, ApiResponse.error>("Invalid venue type: $typParam")) } @@ -223,7 +223,7 @@ class PlatzController( val requiredType = try { PlatzTypE.valueOf(typParam.uppercase()) - } catch (e: Exception) { + } catch (_: Exception) { return@get call.respond(HttpStatusCode.BadRequest, ApiResponse.error>("Invalid venue type: $typParam")) } @@ -255,7 +255,7 @@ class PlatzController( val turnierId = try { uuidFrom(createDto.turnierId) - } catch (e: Exception) { + } catch (_: Exception) { return@post call.respond( HttpStatusCode.BadRequest, ApiResponse.error("Invalid tournament ID format") @@ -264,7 +264,7 @@ class PlatzController( val typ = try { PlatzTypE.valueOf(createDto.typ.uppercase()) - } catch (e: Exception) { + } catch (_: Exception) { return@post call.respond( HttpStatusCode.BadRequest, ApiResponse.error("Invalid venue type: ${createDto.typ}") @@ -311,7 +311,7 @@ class PlatzController( val turnierId = try { uuidFrom(updateDto.turnierId) - } catch (e: Exception) { + } catch (_: Exception) { return@put call.respond( HttpStatusCode.BadRequest, ApiResponse.error("Invalid tournament ID format") @@ -320,7 +320,7 @@ class PlatzController( val typ = try { PlatzTypE.valueOf(updateDto.typ.uppercase()) - } catch (e: Exception) { + } catch (_: Exception) { return@put call.respond( HttpStatusCode.BadRequest, ApiResponse.error("Invalid venue type: ${updateDto.typ}") @@ -387,7 +387,7 @@ class PlatzController( val typ = try { PlatzTypE.valueOf(typParam.uppercase()) - } catch (e: Exception) { + } catch (_: Exception) { return@get call.respond(HttpStatusCode.BadRequest, ApiResponse.error("Invalid venue type: $typParam")) } @@ -433,7 +433,7 @@ class PlatzController( val requiredType = requiredTypeParam?.let { try { PlatzTypE.valueOf(it.uppercase()) - } catch (e: Exception) { + } catch (_: Exception) { return@get call.respond(HttpStatusCode.BadRequest, ApiResponse.error>("Invalid required type: $it")) } } diff --git a/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandRepositoryImpl.kt b/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandRepositoryImpl.kt index 94231fac..6a5b0336 100644 --- a/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandRepositoryImpl.kt +++ b/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandRepositoryImpl.kt @@ -1,9 +1,8 @@ package at.mocode.masterdata.infrastructure.persistence +import at.mocode.core.utils.database.DatabaseFactory import at.mocode.masterdata.domain.model.LandDefinition import at.mocode.masterdata.domain.repository.LandRepository -import at.mocode.masterdata.infrastructure.persistence.LandTable -import at.mocode.core.utils.database.DatabaseFactory import com.benasher44.uuid.Uuid import kotlinx.datetime.Clock import kotlinx.datetime.TimeZone diff --git a/members/members-api/src/main/kotlin/at/mocode/members/api/rest/MemberController.kt b/members/members-api/src/main/kotlin/at/mocode/members/api/rest/MemberController.kt index 77ae8cba..1023ffd6 100644 --- a/members/members-api/src/main/kotlin/at/mocode/members/api/rest/MemberController.kt +++ b/members/members-api/src/main/kotlin/at/mocode/members/api/rest/MemberController.kt @@ -1,30 +1,21 @@ package at.mocode.members.api.rest import at.mocode.core.domain.model.ApiResponse -import at.mocode.members.application.usecase.CreateMemberUseCase -import at.mocode.members.application.usecase.DeleteMemberUseCase -import at.mocode.members.application.usecase.FindExpiringMembershipsUseCase -import at.mocode.members.application.usecase.FindMembersByDateRangeUseCase -import at.mocode.members.application.usecase.GetMemberUseCase -import at.mocode.members.application.usecase.UpdateMemberUseCase -import at.mocode.members.application.usecase.ValidateMemberDataUseCase -import at.mocode.members.domain.repository.MemberRepository import at.mocode.infrastructure.messaging.client.EventPublisher -import com.benasher44.uuid.Uuid +import at.mocode.members.application.usecase.* +import at.mocode.members.domain.repository.MemberRepository import com.benasher44.uuid.uuidFrom +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.responses.ApiResponses +import io.swagger.v3.oas.annotations.tags.Tag import kotlinx.coroutines.runBlocking import kotlinx.datetime.LocalDate import org.springframework.beans.factory.annotation.Qualifier import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.responses.ApiResponse as SwaggerApiResponse -import io.swagger.v3.oas.annotations.responses.ApiResponses -import io.swagger.v3.oas.annotations.tags.Tag -import io.swagger.v3.oas.annotations.media.Content -import io.swagger.v3.oas.annotations.media.Schema /** * Simple no-op EventPublisher implementation for the controller. diff --git a/members/members-service/src/test/kotlin/at/mocode/members/service/integration/MemberServiceIntegrationTest.kt b/members/members-service/src/test/kotlin/at/mocode/members/service/integration/MemberServiceIntegrationTest.kt index d8e15ef7..7e1e460d 100644 --- a/members/members-service/src/test/kotlin/at/mocode/members/service/integration/MemberServiceIntegrationTest.kt +++ b/members/members-service/src/test/kotlin/at/mocode/members/service/integration/MemberServiceIntegrationTest.kt @@ -1,21 +1,20 @@ package at.mocode.members.service.integration +import at.mocode.infrastructure.messaging.client.EventPublisher import at.mocode.members.api.rest.MemberController import at.mocode.members.domain.model.Member import at.mocode.members.domain.repository.MemberRepository -import at.mocode.members.infrastructure.persistence.MemberRepositoryImpl -import at.mocode.infrastructure.messaging.client.EventPublisher -import kotlinx.datetime.LocalDate import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Test +import kotlinx.datetime.LocalDate import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.test.context.ActiveProfiles import org.springframework.test.context.TestPropertySource -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Qualifier import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue