feat(horses-service): remove legacy configuration and repository classes
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Successful in 7m12s
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Successful in 6m42s
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Successful in 6m28s
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Successful in 1m51s

- Deleted outdated `ApplicationConfiguration` and `HorseRepositoryImpl` classes.
- Migrated to streamlined modular Gradle configuration in `build.gradle.kts`.
- Updated domain models and dependencies to use multiplatform and serialization plugins.
- Added modular setup for `horses` namespace in `settings.gradle.kts`.
- Reorganized database configuration with minimal JDBC bindings for development.

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-03-23 13:47:04 +01:00
parent 7b35831d8c
commit c53daa926a
44 changed files with 75781 additions and 530 deletions
@@ -0,0 +1,18 @@
package at.mocode.persons.service
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.ComponentScan
@SpringBootApplication
@ComponentScan(
basePackages = [
"at.mocode.persons.service",
"at.mocode.persons.infrastructure"
]
)
class PersonsServiceApplication
fun main(args: Array<String>) {
runApplication<PersonsServiceApplication>(*args)
}
@@ -0,0 +1,31 @@
package at.mocode.persons.service.config
import at.mocode.persons.infrastructure.persistence.ZnsPersonTable
import jakarta.annotation.PostConstruct
import org.jetbrains.exposed.v1.jdbc.Database
import org.jetbrains.exposed.v1.jdbc.SchemaUtils
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Profile
@Configuration
@Profile("dev")
class PersonsDatabaseConfiguration(
@Value("\${spring.datasource.url}") private val jdbcUrl: String,
@Value("\${spring.datasource.username}") private val username: String,
@Value("\${spring.datasource.password}") private val password: String
) {
private val log = LoggerFactory.getLogger(PersonsDatabaseConfiguration::class.java)
@PostConstruct
fun initializeDatabase() {
log.info("Initialisiere Datenbank-Schema für Persons-Service...")
Database.connect(jdbcUrl, user = username, password = password)
transaction {
SchemaUtils.createMissingTablesAndColumns(ZnsPersonTable)
log.info("Datenbank-Schema erfolgreich initialisiert")
}
}
}
@@ -0,0 +1,136 @@
package at.mocode.persons.service.dev
import at.mocode.persons.infrastructure.persistence.ZnsPersonTable
import org.jetbrains.exposed.v1.jdbc.SchemaUtils
import org.jetbrains.exposed.v1.jdbc.batchInsert
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.CommandLineRunner
import org.springframework.context.annotation.Profile
import org.springframework.stereotype.Component
import java.io.File
import kotlin.time.Clock
/**
* Dev-only Seeder: Importiert LIZENZ01.dat (ZNS) → zns_persons.
* Aktivierung: Umgebungsvariable ZNS_DATA_DIR setzen + Profil "dev".
*/
@Component
@Profile("dev")
class ZnsPersonSeeder(
@Value("\${zns.data.dir:#{null}}") private val znsDataDir: String?
) : CommandLineRunner {
private val log = LoggerFactory.getLogger(ZnsPersonSeeder::class.java)
override fun run(vararg args: String) {
if (znsDataDir == null) {
log.info("ZNS_DATA_DIR nicht gesetzt ZnsPersonSeeder wird übersprungen.")
return
}
val dir = File(znsDataDir)
if (!dir.exists() || !dir.isDirectory) {
log.warn("ZNS_DATA_DIR '{}' existiert nicht oder ist kein Verzeichnis.", znsDataDir)
return
}
log.info("Starte ZNS-Personen-Import aus: {}", dir.absolutePath)
transaction {
SchemaUtils.createMissingTablesAndColumns(ZnsPersonTable)
}
seedPersons(dir)
log.info("ZNS-Personen-Import abgeschlossen.")
}
// -------------------------------------------------------------------------
// LIZENZ01.dat → zns_persons
// Format (220 Zeichen):
// [0-5] LizenzNr
// [6-55] Nachname
// [56-80] Vorname
// [81-83] VereinsNr
// [84-133] VereinsName
// [134-136] Nation
// [137-143] LizenzKlasse (z.B. "R1", "R2", "RD2")
// [144-156] MitgliedsNr
// [157-165] Telefon (nicht gespeichert)
// [166-169] Jahr
// [170] Geschlecht (M/W)
// [171-178] Geburtsdatum (YYYYMMDD)
// -------------------------------------------------------------------------
private fun seedPersons(dir: File) {
val file = File(dir, "LIZENZ01.dat")
if (!file.exists()) {
log.warn("LIZENZ01.dat nicht gefunden Personen werden übersprungen.")
return
}
data class PersonRow(
val lizenzNr: String,
val nachname: String,
val vorname: String,
val vereinsNr: String?,
val vereinsName: String?,
val nation: String?,
val lizenzKlasse: String?,
val mitgliedsNr: String?,
val geschlecht: String?,
val geburtsdatum: java.time.LocalDate?
)
val rows = file.readLines(Charsets.ISO_8859_1)
.filter { it.length >= 6 }
.mapNotNull { line ->
val lizenzNr = line.substring(0, 6).trim()
if (lizenzNr.isBlank()) return@mapNotNull null
val nachname = line.safeSubstring(6, 56).trim()
val vorname = line.safeSubstring(56, 81).trim()
val vereinsNr = line.safeSubstring(81, 84).trim().takeIf { it.isNotBlank() }
val vereinsName = line.safeSubstring(84, 134).trim().takeIf { it.isNotBlank() }
val nation = line.safeSubstring(134, 137).trim().takeIf { it.isNotBlank() }
val lizenzKlasse = line.safeSubstring(137, 144).trim().takeIf { it.isNotBlank() }
val mitgliedsNr = line.safeSubstring(144, 157).trim().takeIf { it.isNotBlank() }
val geschlecht = line.safeSubstring(170, 171).trim().takeIf { it.isNotBlank() }
val gebDatStr = line.safeSubstring(171, 179).trim()
val gebDat = parseDate(gebDatStr)
PersonRow(
lizenzNr, nachname, vorname, vereinsNr, vereinsName,
nation, lizenzKlasse, mitgliedsNr, geschlecht, gebDat
)
}
val now = Clock.System.now()
transaction {
ZnsPersonTable.batchInsert(rows, ignore = true) { row ->
this[ZnsPersonTable.lizenzNummer] = row.lizenzNr
this[ZnsPersonTable.nachname] = row.nachname
this[ZnsPersonTable.vorname] = row.vorname
this[ZnsPersonTable.vereinsNummer] = row.vereinsNr
this[ZnsPersonTable.vereinsName] = row.vereinsName
this[ZnsPersonTable.nation] = row.nation
this[ZnsPersonTable.lizenzKlasse] = row.lizenzKlasse
this[ZnsPersonTable.mitgliedsNummer] = row.mitgliedsNr
this[ZnsPersonTable.geschlecht] = row.geschlecht
this[ZnsPersonTable.geburtsdatum] = row.geburtsdatum?.let {
kotlinx.datetime.LocalDate(it.year, it.monthValue, it.dayOfMonth)
}
this[ZnsPersonTable.createdAt] = now
}
}
log.info("Personen importiert: {} Datensätze", rows.size)
}
private fun String.safeSubstring(start: Int, end: Int): String =
if (this.length >= end) this.substring(start, end) else if (this.length > start) this.substring(start) else ""
private fun parseDate(s: String): java.time.LocalDate? {
if (s.length < 8 || s.all { it == '0' }) return null
return try {
java.time.LocalDate.of(s.substring(0, 4).toInt(), s.substring(4, 6).toInt(), s.substring(6, 8).toInt())
} catch (_: Exception) {
null
}
}
}