fix(tests): resolve EntriesIsolationIntegrationTest failures with test-specific DB config

- Added `TestExposedConfiguration` to connect Exposed with Spring `DataSource` in the `test` profile.
- Downgraded `springdoc` version from `3.0.0` to `2.8.9` for Spring Boot 3.x compatibility.
- Applied `@ActiveProfiles("test")` to `EntriesIsolationIntegrationTest`.
- Updated roadmap documentation to reflect bugfix and test success.

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-04-03 10:52:37 +02:00
parent f4844eb428
commit 1f9f528554
14 changed files with 667 additions and 36 deletions
@@ -0,0 +1,132 @@
package at.mocode.frontend.features.reiter.presentation
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import at.mocode.frontend.core.designsystem.components.MsValidationWrapper
import at.mocode.frontend.core.designsystem.components.ValidationMessage
import at.mocode.frontend.core.designsystem.components.ValidationSeverity
import at.mocode.frontend.core.domain.validation.ValidationResult
/**
* Edit-Dialog für Reiter-Profil mit Live-Validierung (OEPS-Nummer, FEI-ID, Lizenzklasse).
* Validierungsregeln: OetoValidators (ÖTO 2026 / FEI General Regulations 2026).
*/
@Composable
fun ReiterProfilEditDialog(
state: ReiterProfilState,
onIntent: (ReiterProfilIntent) -> Unit,
onDismiss: () -> Unit,
) {
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("Reiter bearbeiten") },
text = {
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
// Vorname
OutlinedTextField(
value = state.vorname,
onValueChange = { onIntent(ReiterProfilIntent.EditVorname(it)) },
label = { Text("Vorname") },
singleLine = true,
modifier = Modifier.fillMaxWidth(),
)
// Nachname
OutlinedTextField(
value = state.nachname,
onValueChange = { onIntent(ReiterProfilIntent.EditNachname(it)) },
label = { Text("Nachname") },
singleLine = true,
modifier = Modifier.fillMaxWidth(),
)
// OEPS-Nummer mit Live-Validierung
MsValidationWrapper(
messages = state.oepsNummerValidation.toMessages(),
modifier = Modifier.fillMaxWidth(),
) {
OutlinedTextField(
value = state.oepsNummer,
onValueChange = { onIntent(ReiterProfilIntent.EditOeps(it)) },
label = { Text("OEPS-Mitgliedsnummer") },
placeholder = { Text("z. B. 1234567 oder OEPS-1234567") },
singleLine = true,
isError = state.oepsNummerValidation is ValidationResult.Error,
modifier = Modifier.fillMaxWidth(),
)
}
// FEI-ID mit Live-Validierung
MsValidationWrapper(
messages = state.feiIdValidation.toMessages(),
modifier = Modifier.fillMaxWidth(),
) {
OutlinedTextField(
value = state.feiId,
onValueChange = { onIntent(ReiterProfilIntent.EditFeiId(it)) },
label = { Text("FEI-ID") },
placeholder = { Text("z. B. 10011469") },
singleLine = true,
isError = state.feiIdValidation is ValidationResult.Error,
modifier = Modifier.fillMaxWidth(),
)
}
// Lizenzklasse mit Live-Validierung
MsValidationWrapper(
messages = state.lizenzKlasseValidation.toMessages(),
modifier = Modifier.fillMaxWidth(),
) {
OutlinedTextField(
value = state.lizenzKlasse,
onValueChange = { onIntent(ReiterProfilIntent.EditLizenz(it)) },
label = { Text("Lizenzklasse") },
placeholder = { Text("z. B. R1, R2, RD1, LZF") },
singleLine = true,
isError = state.lizenzKlasseValidation is ValidationResult.Error,
modifier = Modifier.fillMaxWidth(),
)
}
// Verein
OutlinedTextField(
value = state.verein,
onValueChange = { onIntent(ReiterProfilIntent.EditVerein(it)) },
label = { Text("Verein") },
singleLine = true,
modifier = Modifier.fillMaxWidth(),
)
}
},
confirmButton = {
Button(
onClick = { onIntent(ReiterProfilIntent.Save) },
enabled = state.isValid,
) {
Text("Speichern")
}
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text("Abbrechen")
}
},
)
}
// ── Hilfs-Extension ──────────────────────────────────────────────────────────
/**
* Konvertiert ein [ValidationResult] in eine Liste von [ValidationMessage] für [MsValidationWrapper].
*/
fun ValidationResult.toMessages(): List<ValidationMessage> = when (this) {
is ValidationResult.Ok -> emptyList()
is ValidationResult.Error -> listOf(ValidationMessage(short, ValidationSeverity.ERROR))
is ValidationResult.Warning -> listOf(ValidationMessage(message, ValidationSeverity.WARNING))
}