Refactor license matrix and tokenizer logic: rename LicenseTable to LizenzTable, replace LicenseMatrixService with LizenzMatrixService, enhance tokenizer with normalized and fallback token handling, improve ZNS import for license extraction, and update related documentation.
Desktop CI — Headless Tests & Build / Compose Desktop — Tests (headless) & Build (push) Waiting to run
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Waiting to run
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Waiting to run
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Waiting to run
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Waiting to run

This commit is contained in:
2026-04-06 23:51:56 +02:00
parent b7fa2d26a9
commit 7bf89c58d3
25 changed files with 612 additions and 138 deletions
@@ -59,7 +59,7 @@ class MasterdataDatabaseConfiguration(
TurnierKlassenTable,
TurnierSpartenTable,
TurnierKategorienTable,
LicenseTable,
LizenzTable,
RichtverfahrenTable,
GebuehrTable,
RegulationConfigTable
@@ -112,7 +112,7 @@ class MasterdataTestDatabaseConfiguration {
TurnierKlassenTable,
TurnierSpartenTable,
TurnierKategorienTable,
LicenseTable,
LizenzTable,
RichtverfahrenTable,
GebuehrTable,
RegulationConfigTable
@@ -0,0 +1,79 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.masterdata.service.config
import at.mocode.masterdata.infrastructure.persistence.LizenzTable
import jakarta.annotation.PostConstruct
import org.jetbrains.exposed.v1.core.*
import org.jetbrains.exposed.v1.jdbc.insert
import org.jetbrains.exposed.v1.jdbc.selectAll
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.update
import org.slf4j.LoggerFactory
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.DependsOn
import org.springframework.context.annotation.Profile
import kotlin.uuid.Uuid
/**
* Seeder für Reiterlizenzen (license_matrix) gemäß ÖTO 2026.
*
* Ziel: Sicherstellen, dass bei Service-Start alle benötigten Lizenzeinträge
* für Dressur und Springen vorhanden sind auch wenn die DB leer ist oder
* frühere Migrationen/Seeds nicht gelaufen sind.
*
* Idempotent: pro (sparte, lizenz_klasse) exakt ein Datensatz; bei Änderungen
* der max_turnierklasse_code wird dieser upgedatet.
*/
@Configuration
@Profile("!test")
@DependsOn("masterdataDatabaseConfiguration")
class ReiterlizenzenSeeder {
private val log = LoggerFactory.getLogger(ReiterlizenzenSeeder::class.java)
@PostConstruct
fun seed() {
log.info("Starte Seeding der Reiterlizenzen (license_matrix)...")
transaction {
// Springen: LIZENZFREI→E, R1→L, R2→M, R3→S, R4→S
upsert("SPRINGEN", "LIZENZFREI", "E")
upsert("SPRINGEN", "R1", "L")
upsert("SPRINGEN", "R2", "M")
upsert("SPRINGEN", "R3", "S")
upsert("SPRINGEN", "R4", "S")
// Dressur: LIZENZFREI→E, RD1→L, RD2→M, RD3→S
upsert("DRESSUR", "LIZENZFREI", "E")
upsert("DRESSUR", "RD1", "L")
upsert("DRESSUR", "RD2", "M")
upsert("DRESSUR", "RD3", "S")
}
log.info("Seeding der Reiterlizenzen abgeschlossen.")
}
private fun upsert(sparte: String, lizenzKlasse: String, maxTurnierklasseCode: String) {
val existing = LizenzTable.selectAll()
.where { (LizenzTable.sparte eq sparte) and (LizenzTable.lizenzKlasse eq lizenzKlasse) }
.singleOrNull()
if (existing == null) {
LizenzTable.insert {
it[id] = Uuid.random()
it[LizenzTable.sparte] = sparte
it[LizenzTable.lizenzKlasse] = lizenzKlasse
it[LizenzTable.maxTurnierklasseCode] = maxTurnierklasseCode
it[istAktiv] = true
}
log.debug("Lizenz-Matrix angelegt: {} / {} -> {}", sparte, lizenzKlasse, maxTurnierklasseCode)
} else {
val currentMax = existing[LizenzTable.maxTurnierklasseCode]
val currentActive = existing[LizenzTable.istAktiv]
if (currentMax != maxTurnierklasseCode || !currentActive) {
LizenzTable.update({ (LizenzTable.sparte eq sparte) and (LizenzTable.lizenzKlasse eq lizenzKlasse) }) {
it[LizenzTable.maxTurnierklasseCode] = maxTurnierklasseCode
it[LizenzTable.istAktiv] = true
}
log.debug("Lizenz-Matrix aktualisiert: {} / {} -> {}", sparte, lizenzKlasse, maxTurnierklasseCode)
}
}
}
}
@@ -1,36 +1,79 @@
-- V013__Cleanup_and_Standardize_Masterdata.sql
-- Datum: 6. April 2026
-- 1. Bundesland -> bundeslaender
ALTER TABLE bundesland RENAME TO bundeslaender;
ALTER TABLE bundeslaender RENAME COLUMN id TO bundesland_id;
ALTER INDEX IF EXISTS pk_bundesland RENAME TO pk_bundeslaender;
ALTER INDEX IF EXISTS idx_bundesland_oeps RENAME TO idx_bundeslaender_oeps;
ALTER INDEX IF EXISTS idx_bundesland_iso RENAME TO idx_bundeslaender_iso;
ALTER INDEX IF EXISTS ux_bundesland_land_kuerzel RENAME TO ux_bundeslaender_land_kuerzel;
ALTER INDEX IF EXISTS bundesland_bundesland_nr_unique RENAME TO bundeslaender_bundesland_nr_unique;
-- 1. Bundesland -> bundeslaender (idempotent)
DO $$
BEGIN
IF to_regclass('public.bundesland') IS NOT NULL AND to_regclass('public.bundeslaender') IS NULL THEN
ALTER TABLE bundesland RENAME TO bundeslaender;
END IF;
-- 2. qualifikation_master -> funktionaers_qualifikationen
ALTER TABLE qualifikation_master RENAME TO funktionaers_qualifikationen;
-- Spaltenumbenennung nur, wenn noch "id" existiert
IF to_regclass('public.bundeslaender') IS NOT NULL THEN
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'bundeslaender' AND column_name = 'id'
) THEN
ALTER TABLE bundeslaender RENAME COLUMN id TO bundesland_id;
END IF;
END IF;
-- Optionale historische Index-Umbenennungen (nur wenn vorhanden)
IF EXISTS (SELECT 1 FROM pg_class WHERE relname = 'pk_bundesland') THEN
ALTER INDEX pk_bundesland RENAME TO pk_bundeslaender;
END IF;
IF EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_bundesland_oeps') THEN
ALTER INDEX idx_bundesland_oeps RENAME TO idx_bundeslaender_oeps;
END IF;
IF EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_bundesland_iso') THEN
ALTER INDEX idx_bundesland_iso RENAME TO idx_bundeslaender_iso;
END IF;
IF EXISTS (SELECT 1 FROM pg_class WHERE relname = 'ux_bundesland_land_kuerzel') THEN
ALTER INDEX ux_bundesland_land_kuerzel RENAME TO ux_bundeslaender_land_kuerzel;
END IF;
IF EXISTS (SELECT 1 FROM pg_class WHERE relname = 'bundesland_bundesland_nr_unique') THEN
ALTER INDEX bundesland_bundesland_nr_unique RENAME TO bundeslaender_bundesland_nr_unique;
END IF;
END $$;
-- 2. qualifikation_master -> funktionaers_qualifikationen (idempotent)
DO $$
BEGIN
IF to_regclass('public.qualifikation_master') IS NOT NULL AND to_regclass('public.funktionaers_qualifikationen') IS NULL THEN
ALTER TABLE qualifikation_master RENAME TO funktionaers_qualifikationen;
END IF;
END $$;
-- Die Join-Tabelle funktionaer_qualifikation bleibt als solche bestehen,
-- referenziert aber nun funktionaers_qualifikationen.
-- (Der Name der Join-Tabelle ist bereits fast korrekt, wir lassen sie vorerst so,
-- da sie die Verknüpfung zw. Funktionär und Qualifikation darstellt.)
-- Update: Der User möchte "funktionaers_qualifikationen" als Name für die Qualifikationen.
-- 3. reiter_lizenz -> reit_lizenzen
ALTER TABLE reiter_lizenz RENAME TO reit_lizenzen;
-- 3. reiter_lizenz -> reit_lizenzen (idempotent)
DO $$
BEGIN
IF to_regclass('public.reiter_lizenz') IS NOT NULL AND to_regclass('public.reit_lizenzen') IS NULL THEN
ALTER TABLE reiter_lizenz RENAME TO reit_lizenzen;
END IF;
END $$;
ALTER INDEX IF EXISTS pk_reiter_lizenz RENAME TO pk_reit_lizenzen;
-- 4. reiter_sparte entfernen
DROP TABLE IF EXISTS reiter_sparte;
-- 5. turnierklasse -> turnier_klassen
ALTER TABLE turnierklasse RENAME TO turnier_klassen;
-- 5. turnierklasse -> turnier_klassen (idempotent)
-- Hinweis: In der aktuellen Codebasis verwendet Exposed `bewerbs_klassen` als technische Tabelle
-- für Turnier-/Bewerbsklassen. Daher nur umbenennen, wenn die Alt-Tabelle tatsächlich existiert.
DO $$
BEGIN
IF to_regclass('public.turnierklasse') IS NOT NULL AND to_regclass('public.turnier_klassen') IS NULL THEN
ALTER TABLE turnierklasse RENAME TO turnier_klassen;
END IF;
END $$;
ALTER INDEX IF EXISTS pk_turnierklasse RENAME TO pk_turnier_klassen;
ALTER INDEX IF EXISTS idx_turnierklasse_sparte_code RENAME TO idx_turnier_klassen_sparte_code;
-- 6. turnier_sparten erstellen
CREATE TABLE IF NOT EXISTS turnier_sparten (
sparte_id UUID PRIMARY KEY,
code VARCHAR(10) UNIQUE NOT NULL, -- z.B. D, S, V, F, R, C
@@ -40,6 +83,5 @@ CREATE TABLE IF NOT EXISTS turnier_sparten (
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 7. Constraints aktualisieren (falls nötig)
-- Da wir nur Tabellen umbenannt haben, bleiben die Foreign Keys in PostgreSQL erhalten
-- und zeigen automatisch auf die neuen Tabellennamen.