feat(masterdata): introduce Regulation domain with API, persistence, and metrics integration
- Added `RegulationRepository` and its `Exposed` implementation for persistence. - Implemented REST endpoints for regulations (`/rules`) in `RegulationController`, including support for tournament classes, license matrix, guidelines, fees, and configuration retrieval. - Integrated OpenAPI documentation for `/rules` endpoints with Swagger UI in `masterdataApiModule`. - Enabled Micrometer-based metrics for Prometheus in the API layer. - Updated Gradle dependencies to include OpenAPI, Swagger, and Micrometer libraries. - Registered `RegulationRepository` and `RegulationController` in `MasterdataConfiguration`. - Improved database access patterns and reduced repetitive validation logic across domain services. - Added unit and application tests for `RegulationController` to verify API behavior and repository interactions. - Updated the service's `ROADMAP.md` to mark API v1 endpoints and observability as complete. Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
+12
-14
@@ -2,17 +2,17 @@
|
||||
package at.mocode.masterdata.application.usecase
|
||||
|
||||
import at.mocode.core.domain.model.SparteE
|
||||
import at.mocode.core.domain.model.ValidationError
|
||||
import at.mocode.core.domain.model.ValidationResult
|
||||
import at.mocode.masterdata.domain.model.AltersklasseDefinition
|
||||
import at.mocode.masterdata.domain.repository.AltersklasseRepository
|
||||
import at.mocode.core.domain.model.ValidationResult
|
||||
import at.mocode.core.domain.model.ValidationError
|
||||
import kotlin.uuid.Uuid
|
||||
import kotlin.time.Clock
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Use case for creating and updating age class information.
|
||||
*
|
||||
* This use case encapsulates the business logic for age class management
|
||||
* This use case encapsulates the business logic for age class management,
|
||||
* including validation, duplicate checking, and persistence.
|
||||
*/
|
||||
class CreateAltersklasseUseCase(
|
||||
@@ -137,16 +137,14 @@ class CreateAltersklasseUseCase(
|
||||
*/
|
||||
suspend fun updateAltersklasse(request: UpdateAltersklasseRequest): UpdateAltersklasseResponse {
|
||||
// Check if age class exists
|
||||
val existingAltersklasse = altersklasseRepository.findById(request.altersklasseId)
|
||||
if (existingAltersklasse == null) {
|
||||
return UpdateAltersklasseResponse(
|
||||
altersklasse = null,
|
||||
success = false,
|
||||
errors = listOf("Age class with ID ${request.altersklasseId} not found")
|
||||
)
|
||||
}
|
||||
val existingAltersklasse =
|
||||
altersklasseRepository.findById(request.altersklasseId) ?: return UpdateAltersklasseResponse(
|
||||
altersklasse = null,
|
||||
success = false,
|
||||
errors = listOf("Age class with ID ${request.altersklasseId} not found")
|
||||
)
|
||||
|
||||
// Validate the request
|
||||
// Validate the request
|
||||
val validationResult = validateUpdateRequest(request)
|
||||
if (!validationResult.isValid()) {
|
||||
val errors = (validationResult as ValidationResult.Invalid).errors.map { it.message }
|
||||
@@ -273,7 +271,7 @@ class CreateAltersklasseUseCase(
|
||||
* Validates an update age class request.
|
||||
*/
|
||||
private fun validateUpdateRequest(request: UpdateAltersklasseRequest): ValidationResult {
|
||||
// Use the same validation logic as create request
|
||||
// Use the same validation logic as creation request
|
||||
val createRequest = CreateAltersklasseRequest(
|
||||
altersklasseCode = request.altersklasseCode,
|
||||
bezeichnung = request.bezeichnung,
|
||||
|
||||
+20
-23
@@ -1,17 +1,17 @@
|
||||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||
package at.mocode.masterdata.application.usecase
|
||||
|
||||
import at.mocode.core.domain.model.ValidationError
|
||||
import at.mocode.core.domain.model.ValidationResult
|
||||
import at.mocode.masterdata.domain.model.BundeslandDefinition
|
||||
import at.mocode.masterdata.domain.repository.BundeslandRepository
|
||||
import at.mocode.core.domain.model.ValidationResult
|
||||
import at.mocode.core.domain.model.ValidationError
|
||||
import kotlin.uuid.Uuid
|
||||
import kotlin.time.Clock
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Use case for creating and updating federal state information.
|
||||
*
|
||||
* This use case encapsulates the business logic for federal state management
|
||||
* This use case encapsulates the business logic for federal state management,
|
||||
* including validation, duplicate checking, and persistence.
|
||||
*/
|
||||
class CreateBundeslandUseCase(
|
||||
@@ -22,14 +22,14 @@ class CreateBundeslandUseCase(
|
||||
* Request data for creating a new federal state.
|
||||
*/
|
||||
data class CreateBundeslandRequest(
|
||||
val landId: Uuid,
|
||||
val oepsCode: String? = null,
|
||||
val iso3166_2_Code: String? = null,
|
||||
val name: String,
|
||||
val kuerzel: String? = null,
|
||||
val wappenUrl: String? = null,
|
||||
val istAktiv: Boolean = true,
|
||||
val sortierReihenfolge: Int? = null
|
||||
val landId: Uuid,
|
||||
val oepsCode: String? = null,
|
||||
val iso3166_2_Code: String? = null,
|
||||
val name: String,
|
||||
val kuerzel: String? = null,
|
||||
val wappenUrl: String? = null,
|
||||
val istAktiv: Boolean = true,
|
||||
val sortierReihenfolge: Int? = null
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -133,16 +133,13 @@ class CreateBundeslandUseCase(
|
||||
*/
|
||||
suspend fun updateBundesland(request: UpdateBundeslandRequest): UpdateBundeslandResponse {
|
||||
// Check if federal state exists
|
||||
val existingBundesland = bundeslandRepository.findById(request.bundeslandId)
|
||||
if (existingBundesland == null) {
|
||||
return UpdateBundeslandResponse(
|
||||
bundesland = null,
|
||||
success = false,
|
||||
errors = listOf("Federal state with ID ${request.bundeslandId} not found")
|
||||
)
|
||||
}
|
||||
val existingBundesland = bundeslandRepository.findById(request.bundeslandId) ?: return UpdateBundeslandResponse(
|
||||
bundesland = null,
|
||||
success = false,
|
||||
errors = listOf("Federal state with ID ${request.bundeslandId} not found")
|
||||
)
|
||||
|
||||
// Validate the request
|
||||
// Validate the request
|
||||
val validationResult = validateUpdateRequest(request)
|
||||
if (!validationResult.isValid()) {
|
||||
val errors = (validationResult as ValidationResult.Invalid).errors.map { it.message }
|
||||
@@ -209,7 +206,7 @@ class CreateBundeslandUseCase(
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a create federal state request.
|
||||
* Validates create federal state request.
|
||||
*/
|
||||
private fun validateCreateRequest(request: CreateBundeslandRequest): ValidationResult {
|
||||
val errors = mutableListOf<ValidationError>()
|
||||
@@ -264,7 +261,7 @@ class CreateBundeslandUseCase(
|
||||
* Validates an update federal state request.
|
||||
*/
|
||||
private fun validateUpdateRequest(request: UpdateBundeslandRequest): ValidationResult {
|
||||
// Use the same validation logic as create request
|
||||
// Use the same validation logic as creation request
|
||||
val createRequest = CreateBundeslandRequest(
|
||||
landId = request.landId,
|
||||
oepsCode = request.oepsCode,
|
||||
|
||||
+11
-14
@@ -1,17 +1,17 @@
|
||||
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
|
||||
package at.mocode.masterdata.application.usecase
|
||||
|
||||
import at.mocode.core.domain.model.ValidationError
|
||||
import at.mocode.core.domain.model.ValidationResult
|
||||
import at.mocode.masterdata.domain.model.LandDefinition
|
||||
import at.mocode.masterdata.domain.repository.LandRepository
|
||||
import at.mocode.core.domain.model.ValidationResult
|
||||
import at.mocode.core.domain.model.ValidationError
|
||||
import kotlin.uuid.Uuid
|
||||
import kotlin.time.Clock
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Use case for creating and updating country information.
|
||||
*
|
||||
* This use case encapsulates the business logic for country management
|
||||
* This use case encapsulates the business logic for country management,
|
||||
* including validation, duplicate checking, and persistence.
|
||||
*/
|
||||
class CreateCountryUseCase(
|
||||
@@ -139,16 +139,13 @@ class CreateCountryUseCase(
|
||||
*/
|
||||
suspend fun updateCountry(request: UpdateCountryRequest): UpdateCountryResponse {
|
||||
// Check if country exists
|
||||
val existingCountry = landRepository.findById(request.landId)
|
||||
if (existingCountry == null) {
|
||||
return UpdateCountryResponse(
|
||||
country = null,
|
||||
success = false,
|
||||
errors = listOf("Country with ID ${request.landId} not found")
|
||||
)
|
||||
}
|
||||
val existingCountry = landRepository.findById(request.landId) ?: return UpdateCountryResponse(
|
||||
country = null,
|
||||
success = false,
|
||||
errors = listOf("Country with ID ${request.landId} not found")
|
||||
)
|
||||
|
||||
// Validate the request
|
||||
// Validate the request
|
||||
val validationResult = validateUpdateRequest(request)
|
||||
if (!validationResult.isValid()) {
|
||||
val errors = (validationResult as ValidationResult.Invalid).errors.map { it.message }
|
||||
@@ -271,7 +268,7 @@ class CreateCountryUseCase(
|
||||
* Validates an update country request.
|
||||
*/
|
||||
private fun validateUpdateRequest(request: UpdateCountryRequest): ValidationResult {
|
||||
// Use the same validation logic as create request
|
||||
// Use the same validation logic as creation request
|
||||
val createRequest = CreateCountryRequest(
|
||||
isoAlpha2Code = request.isoAlpha2Code,
|
||||
isoAlpha3Code = request.isoAlpha3Code,
|
||||
|
||||
+12
-15
@@ -2,17 +2,17 @@
|
||||
package at.mocode.masterdata.application.usecase
|
||||
|
||||
import at.mocode.core.domain.model.PlatzTypE
|
||||
import at.mocode.core.domain.model.ValidationError
|
||||
import at.mocode.core.domain.model.ValidationResult
|
||||
import at.mocode.masterdata.domain.model.Platz
|
||||
import at.mocode.masterdata.domain.repository.PlatzRepository
|
||||
import at.mocode.core.domain.model.ValidationResult
|
||||
import at.mocode.core.domain.model.ValidationError
|
||||
import kotlin.uuid.Uuid
|
||||
import kotlin.time.Clock
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
/**
|
||||
* Use case for creating and updating venue/arena information.
|
||||
*
|
||||
* This use case encapsulates the business logic for venue management
|
||||
* This use case encapsulates the business logic for venue management,
|
||||
* including validation, duplicate checking, and persistence.
|
||||
*/
|
||||
class CreatePlatzUseCase(
|
||||
@@ -131,16 +131,13 @@ class CreatePlatzUseCase(
|
||||
*/
|
||||
suspend fun updatePlatz(request: UpdatePlatzRequest): UpdatePlatzResponse {
|
||||
// Check if venue exists
|
||||
val existingPlatz = platzRepository.findById(request.platzId)
|
||||
if (existingPlatz == null) {
|
||||
return UpdatePlatzResponse(
|
||||
platz = null,
|
||||
success = false,
|
||||
errors = listOf("Venue with ID ${request.platzId} not found")
|
||||
)
|
||||
}
|
||||
val existingPlatz = platzRepository.findById(request.platzId) ?: return UpdatePlatzResponse(
|
||||
platz = null,
|
||||
success = false,
|
||||
errors = listOf("Venue with ID ${request.platzId} not found")
|
||||
)
|
||||
|
||||
// Validate the request
|
||||
// Validate the request
|
||||
val validationResult = validateUpdateRequest(request)
|
||||
if (!validationResult.isValid()) {
|
||||
val errors = (validationResult as ValidationResult.Invalid).errors.map { it.message }
|
||||
@@ -251,7 +248,7 @@ class CreatePlatzUseCase(
|
||||
* Validates an update venue request.
|
||||
*/
|
||||
private fun validateUpdateRequest(request: UpdatePlatzRequest): ValidationResult {
|
||||
// Use the same validation logic as create request
|
||||
// Use the same validation logic as creation request
|
||||
val createRequest = CreatePlatzRequest(
|
||||
turnierId = request.turnierId,
|
||||
name = request.name,
|
||||
@@ -384,7 +381,7 @@ class CreatePlatzUseCase(
|
||||
* This method performs comprehensive checks for tournament venue setup.
|
||||
*
|
||||
* @param turnierId The tournament ID
|
||||
* @param requiredVenueTypes Map of venue type to minimum count required
|
||||
* @param requiredVenueTypes Map of a venue type to minimum count required
|
||||
* @return ValidationResult indicating if the tournament has adequate venue setup
|
||||
*/
|
||||
suspend fun validateTournamentVenueSetup(
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ class GetAltersklasseUseCase(
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if a person with given age and gender can participate in an age class.
|
||||
* Validates if a person with a given age and gender can participate in an age class.
|
||||
*
|
||||
* @param altersklasseId The age class ID
|
||||
* @param age The person's age
|
||||
|
||||
+2
-2
@@ -182,7 +182,7 @@ class GetPlatzUseCase(
|
||||
*
|
||||
* @param turnierId The tournament ID
|
||||
* @param activeOnly Whether to include only active venues (default: true)
|
||||
* @return Map of venue type to list of venues
|
||||
* @return Map of a venue type to a list of venues
|
||||
*/
|
||||
suspend fun getGroupedByTypeForTournament(turnierId: Uuid, activeOnly: Boolean = true): Map<PlatzTypE, List<Platz>> {
|
||||
val venues = platzRepository.findByTournament(turnierId, activeOnly, true)
|
||||
@@ -243,7 +243,7 @@ class GetPlatzUseCase(
|
||||
* @param requiredType Optional required venue type
|
||||
* @param requiredDimensions Optional required dimensions
|
||||
* @param requiredGroundType Optional required ground type
|
||||
* @return Pair of (isValid, reasons) where reasons contains any validation issues
|
||||
* @return Pair of (isValid, reasons) where reasons contain any validation issues
|
||||
*/
|
||||
suspend fun validateVenueSuitability(
|
||||
platzId: Uuid,
|
||||
|
||||
Reference in New Issue
Block a user