(fix) Datenbank-Setup Umbau zu SCS

This commit is contained in:
stefan
2025-07-19 13:33:07 +02:00
parent 3c0cf9ce43
commit edf19188b8
13 changed files with 769 additions and 0 deletions
@@ -0,0 +1,38 @@
package at.mocode.gateway
import at.mocode.gateway.config.MigrationSetup
import at.mocode.shared.database.DatabaseConfig
import at.mocode.shared.database.DatabaseFactory
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.routing.*
import io.ktor.server.response.*
fun main() {
// Datenbank initialisieren
val databaseConfig = DatabaseConfig.fromEnv()
DatabaseFactory.init(databaseConfig)
// Migrationen ausführen
MigrationSetup.runMigrations()
// Server starten
embeddedServer(Netty, port = System.getenv("API_PORT")?.toIntOrNull() ?: 8081) {
configureApplication()
}.start(wait = true)
}
fun Application.configureApplication() {
install(ContentNegotiation) {
json()
}
routing {
get("/health") {
call.respond(mapOf("status" to "OK"))
}
}
}
@@ -0,0 +1,32 @@
package at.mocode.gateway.config
import at.mocode.gateway.migrations.*
import at.mocode.shared.database.DatabaseMigrator
/**
* Konfiguriert und führt alle Datenbankmigrationen aus.
*/
object MigrationSetup {
/**
* Registriert alle Migrationen und führt sie aus.
*/
fun runMigrations() {
// Migrationen registrieren
DatabaseMigrator.registerAll(
// Master Data Migrationen
MasterDataTablesCreation(),
// Member Management Migrationen
MemberManagementTablesCreation(),
// Horse Registry Migrationen
HorseRegistryTablesCreation(),
// Event Management Migrationen
EventManagementTablesCreation()
)
// Migrationen ausführen
DatabaseMigrator.migrate()
}
}
@@ -0,0 +1,56 @@
package at.mocode.gateway.migrations
import at.mocode.shared.database.Migration
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.kotlin.datetime.date
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
import org.jetbrains.exposed.sql.kotlin.datetime.CurrentTimestamp
/**
* Migration zur Erstellung der Veranstaltungsmanagement-Tabellen.
*/
class EventManagementTablesCreation : Migration(4, "Create event management tables") {
override fun up() {
// Veranstaltung-Tabelle
SchemaUtils.create(VeranstaltungTable)
// Veranstaltung_Sportart-Tabelle
SchemaUtils.create(VeranstaltungSportartTable)
}
}
// Definition der Tabellen
object VeranstaltungTable : Table("veranstaltung") {
val id = uuid("id").autoGenerate()
val name = varchar("name", 100)
val beschreibung = text("beschreibung").nullable()
val startDatum = date("start_datum")
val endDatum = date("end_datum")
val anmeldeschluss = date("anmeldeschluss").nullable()
val ort = varchar("ort", 100)
val landCode = varchar("land_code", 2).references(LandTable.code)
val bundeslandCode = varchar("bundesland_code", 5).nullable()
val maxTeilnehmer = integer("max_teilnehmer").nullable()
val istAktiv = bool("ist_aktiv").default(true)
val istOeffentlich = bool("ist_oeffentlich").default(true)
val erstelltAm = timestamp("erstellt_am").defaultExpression(CurrentTimestamp)
val geaendertAm = timestamp("geaendert_am").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
foreignKey(
bundeslandCode to LandTable.code,
landCode to BundeslandTable.landCode
)
// Ende muss nach Start sein
check("datum_check") { endDatum greaterEq startDatum }
}
}
object VeranstaltungSportartTable : Table("veranstaltung_sportart") {
val veranstaltungId = uuid("veranstaltung_id").references(VeranstaltungTable.id)
val sportartCode = varchar("sportart_code", 5).references(SportartTable.code)
override val primaryKey = PrimaryKey(veranstaltungId, sportartCode)
}
@@ -0,0 +1,51 @@
package at.mocode.gateway.migrations
import at.mocode.shared.database.Migration
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
import org.jetbrains.exposed.sql.kotlin.datetime.CurrentTimestamp
/**
* Migration zur Erstellung der Pferderegister-Tabellen.
*/
class HorseRegistryTablesCreation : Migration(3, "Create horse registry tables") {
override fun up() {
// Pferd-Tabelle
SchemaUtils.create(PferdTable)
// Pferdebesitzer-Tabelle
SchemaUtils.create(PferdebesitzerTable)
}
}
// Definition der Tabellen
object PferdTable : Table("pferd") {
val id = uuid("id").autoGenerate()
val name = varchar("name", 100)
val lebensnummer = varchar("lebensnummer", 30).uniqueIndex()
val rasse = varchar("rasse", 50)
val farbe = varchar("farbe", 50)
val geburtsjahr = integer("geburtsjahr").nullable()
val geschlecht = varchar("geschlecht", 1) // 'S' = Stute, 'W' = Wallach, 'H' = Hengst
val aktiv = bool("aktiv").default(true)
val erstelltAm = timestamp("erstellt_am").defaultExpression(CurrentTimestamp)
val geaendertAm = timestamp("geaendert_am").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
// Geschlecht muss S, W oder H sein
check("geschlecht_check") { geschlecht.inList(listOf("S", "W", "H")) }
}
}
object PferdebesitzerTable : Table("pferdebesitzer") {
val pferdId = uuid("pferd_id").references(PferdTable.id)
val personId = uuid("person_id").references(PersonTable.id)
val hauptbesitzer = bool("hauptbesitzer").default(false)
val aktiv = bool("aktiv").default(true)
val erstelltAm = timestamp("erstellt_am").defaultExpression(CurrentTimestamp)
val geaendertAm = timestamp("geaendert_am").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(pferdId, personId)
}
@@ -0,0 +1,115 @@
package at.mocode.gateway.migrations
import at.mocode.shared.database.Migration
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.kotlin.datetime.datetime
/**
* Migration zur Erstellung der Stammdaten-Tabellen.
*/
class MasterDataTablesCreation : Migration(1, "Create master data tables") {
override fun up() {
// Land-Tabelle
SchemaUtils.create(LandTable)
// Bundesland-Tabelle
SchemaUtils.create(BundeslandTable)
// Altersklasse-Tabelle
SchemaUtils.create(AltersklasseTable)
// Sportart-Tabelle
SchemaUtils.create(SportartTable)
// Anfangsdaten einfügen
insertInitialData()
}
private fun insertInitialData() {
// Länder einfügen
LandTable.batchInsert(listOf(
mapOf("code" to "AT", "name" to "Österreich", "active" to true),
mapOf("code" to "DE", "name" to "Deutschland", "active" to true),
mapOf("code" to "CH", "name" to "Schweiz", "active" to true)
)) { data ->
this[LandTable.code] = data["code"] as String
this[LandTable.name] = data["name"] as String
this[LandTable.active] = data["active"] as Boolean
}
// Bundesländer einfügen (Österreich)
BundeslandTable.batchInsert(listOf(
mapOf("landCode" to "AT", "code" to "W", "name" to "Wien"),
mapOf("landCode" to "AT", "code" to "", "name" to "Niederösterreich"),
mapOf("landCode" to "AT", "code" to "", "name" to "Oberösterreich"),
mapOf("landCode" to "AT", "code" to "S", "name" to "Salzburg"),
mapOf("landCode" to "AT", "code" to "T", "name" to "Tirol"),
mapOf("landCode" to "AT", "code" to "V", "name" to "Vorarlberg"),
mapOf("landCode" to "AT", "code" to "ST", "name" to "Steiermark"),
mapOf("landCode" to "AT", "code" to "K", "name" to "Kärnten"),
mapOf("landCode" to "AT", "code" to "B", "name" to "Burgenland")
)) { data ->
this[BundeslandTable.landCode] = data["landCode"] as String
this[BundeslandTable.code] = data["code"] as String
this[BundeslandTable.name] = data["name"] as String
}
// Altersklassen einfügen
AltersklasseTable.batchInsert(listOf(
mapOf("code" to "U12", "name" to "Unter 12", "minAlter" to 0, "maxAlter" to 12),
mapOf("code" to "U16", "name" to "Unter 16", "minAlter" to 13, "maxAlter" to 16),
mapOf("code" to "U21", "name" to "Unter 21", "minAlter" to 17, "maxAlter" to 21),
mapOf("code" to "ALLG", "name" to "Allgemeine Klasse", "minAlter" to 22, "maxAlter" to 99)
)) { data ->
this[AltersklasseTable.code] = data["code"] as String
this[AltersklasseTable.name] = data["name"] as String
this[AltersklasseTable.minAlter] = data["minAlter"] as Int
this[AltersklasseTable.maxAlter] = data["maxAlter"] as Int
}
// Sportarten einfügen
SportartTable.batchInsert(listOf(
mapOf("code" to "DR", "name" to "Dressur"),
mapOf("code" to "SP", "name" to "Springen"),
mapOf("code" to "VS", "name" to "Vielseitigkeit"),
mapOf("code" to "WR", "name" to "Western Reiten"),
mapOf("code" to "VT", "name" to "Voltigieren")
)) { data ->
this[SportartTable.code] = data["code"] as String
this[SportartTable.name] = data["name"] as String
}
}
}
// Definition der Tabellen
object LandTable : Table("land") {
val code = varchar("code", 2)
val name = varchar("name", 50)
val active = bool("active").default(true)
override val primaryKey = PrimaryKey(code)
}
object BundeslandTable : Table("bundesland") {
val landCode = varchar("land_code", 2).references(LandTable.code)
val code = varchar("code", 5)
val name = varchar("name", 50)
override val primaryKey = PrimaryKey(landCode, code)
}
object AltersklasseTable : Table("altersklasse") {
val code = varchar("code", 10)
val name = varchar("name", 50)
val minAlter = integer("min_alter")
val maxAlter = integer("max_alter")
override val primaryKey = PrimaryKey(code)
}
object SportartTable : Table("sportart") {
val code = varchar("code", 5)
val name = varchar("name", 50)
override val primaryKey = PrimaryKey(code)
}
@@ -0,0 +1,99 @@
package at.mocode.gateway.migrations
import at.mocode.shared.database.Migration
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.kotlin.datetime.date
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
import org.jetbrains.exposed.sql.kotlin.datetime.CurrentTimestamp
/**
* Migration zur Erstellung der Mitgliederverwaltung-Tabellen.
*/
class MemberManagementTablesCreation : Migration(2, "Create member management tables") {
override fun up() {
// Person-Tabelle
SchemaUtils.create(PersonTable)
// Verein-Tabelle
SchemaUtils.create(VereinTable)
// Mitgliedschaft-Tabelle
SchemaUtils.create(MitgliedschaftTable)
// Adresse-Tabelle
SchemaUtils.create(AdresseTable)
}
}
// Definition der Tabellen
object PersonTable : Table("person") {
val id = uuid("id").autoGenerate()
val vorname = varchar("vorname", 50)
val nachname = varchar("nachname", 50)
val email = varchar("email", 100).uniqueIndex()
val telefon = varchar("telefon", 20).nullable()
val geburtsdatum = date("geburtsdatum").nullable()
val aktiv = bool("aktiv").default(true)
val erstelltAm = timestamp("erstellt_am").defaultExpression(CurrentTimestamp)
val geaendertAm = timestamp("geaendert_am").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
}
object VereinTable : Table("verein") {
val id = uuid("id").autoGenerate()
val name = varchar("name", 100)
val vereinsNummer = varchar("vereins_nummer", 20).uniqueIndex()
val landCode = varchar("land_code", 2).references(LandTable.code)
val bundeslandCode = varchar("bundesland_code", 5).nullable()
val aktiv = bool("aktiv").default(true)
val erstelltAm = timestamp("erstellt_am").defaultExpression(CurrentTimestamp)
val geaendertAm = timestamp("geaendert_am").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
foreignKey(
bundeslandCode to LandTable.code,
landCode to BundeslandTable.landCode
)
}
}
object MitgliedschaftTable : Table("mitgliedschaft") {
val personId = uuid("person_id").references(PersonTable.id)
val vereinId = uuid("verein_id").references(VereinTable.id)
val aktiv = bool("aktiv").default(true)
val erstelltAm = timestamp("erstellt_am").defaultExpression(CurrentTimestamp)
val geaendertAm = timestamp("geaendert_am").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(personId, vereinId)
}
object AdresseTable : Table("adresse") {
val id = uuid("id").autoGenerate()
val personId = uuid("person_id").references(PersonTable.id).nullable()
val vereinId = uuid("verein_id").references(VereinTable.id).nullable()
val strasse = varchar("strasse", 100)
val hausnummer = varchar("hausnummer", 10)
val plz = varchar("plz", 10)
val ort = varchar("ort", 100)
val landCode = varchar("land_code", 2).references(LandTable.code)
val bundeslandCode = varchar("bundesland_code", 5).nullable()
val aktiv = bool("aktiv").default(true)
val erstelltAm = timestamp("erstellt_am").defaultExpression(CurrentTimestamp)
val geaendertAm = timestamp("geaendert_am").defaultExpression(CurrentTimestamp)
override val primaryKey = PrimaryKey(id)
init {
foreignKey(
bundeslandCode to LandTable.code,
landCode to BundeslandTable.landCode
)
check("address_owner_check") {
(personId.isNotNull() and vereinId.isNull()) or
(personId.isNull() and vereinId.isNotNull())
}
}
}