22 Commits

Author SHA1 Message Date
stefan a74b0bb815 build: Update Gradle Wrapper to v9.6.0
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-06-23 14:06:41 +02:00
stefan 40cf1e5d22 feat: füge neue Dokumentationen zu Richterqualifikationen (Dressur & Springen) sowie Systemmigration (Java 25, Kotlin 2.4.0, Gradle 9, Spring Boot 4) hinzu
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-06-21 21:06:11 +02:00
stefan ce63303b2c docs: massive restructuring of documentation, development guides and agent playbooks 2026-06-15 12:54:38 +02:00
stefan e4988b4397 docs: add tournament files for Ebbs Tirol 2026 2026-06-15 12:53:29 +02:00
stefan 8816e8d297 air work test 2026-06-15 12:26:22 +02:00
stefan 98d0bf0c7b docs: Turnier-Dokumente für 2026 hinzugefügt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-28 13:25:59 +02:00
stefan 0a90b57c2a docs: Ergänzung der Simka Core Server Dokumentation
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-22 13:13:24 +02:00
stefan 0ab62a2752 docs: README-Testbeschreibung aktualisiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-22 11:36:34 +02:00
stefan 6070709bf2 docs: README-Testbeschreibung aktualisiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-22 11:34:17 +02:00
stefan 763c2a9157 Test 2. Versuch zu committen
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-20 10:10:30 +00:00
StefanMo 4f715d10bb refactor: extrahiere ReiterLizenz in core-domain, aktualisiere Abhängigkeiten und behebe Windows-SQLite-Temp-Verzeichnisproblem 2026-05-12 23:33:48 +02:00
stefan 0b830eb675 feat: integriere VeranstaltungRepository und syncModule in Desktop-App
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-12 19:29:51 +02:00
stefan 4c37ecb952 refactor(build): redundante Variable im Gradle-Skript entfernt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-12 15:27:02 +02:00
stefan c25ef17a4a refactor(build): Typen in Gradle-Skript explizit hinzugefügt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-12 15:23:52 +02:00
stefan e5e3b4cfec refactor(build): Plugin-Anwendung in Gradle-Konfiguration vereinfacht
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-12 15:17:47 +02:00
stefan 7d064853e5 feat: optimiere Gradle-Konfiguration für bessere Build-Performance (JVM, Worker, Cache) und dokumentiere Änderungen
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-11 21:39:46 +02:00
stefan 387180c12c chore: entferne index.html
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-11 20:44:35 +02:00
stefan 49393d3eac feat: verbessere Build-Performance durch Standard-Deaktivierung von WASM und aktualisiere Dokumentation
Signed-off-by: StefanMoCoAt <stefan.mo.co@gmail.com>
2026-05-11 20:44:24 +02:00
stefan e389fe9bce feat(desktop, network): Chat-Funktion hinzugefügt und P2P-Sync verbessert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-11 13:57:53 +02:00
stefan 1a4753cd73 refactor(frontend): HTML-Styles aufgeräumt und Konsistenz verbessert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-09 17:23:17 +02:00
stefan ece3f8bf78 feat(frontend): Grundlegendes HTML-Template für Website hinzugefügt
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-09 17:09:51 +02:00
stefan 8d176ce955 refactor(gradle, desktop): Build-Konfiguration bereinigt, Ports optimiert und UI-Logik konsolidiert
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
2026-05-09 14:27:22 +02:00
746 changed files with 1798 additions and 936 deletions
+41
View File
@@ -0,0 +1,41 @@
## 🚀 Identität & Arbeitsmodus (Chamäleon-Modus)
Du bist ein hochqualifizierter KI-Assistent für das Softwareprojekt "Meldestelle" von Stefan.
Ich weise dir in meinen Prompts Aufgaben zu. Nimm sofort die entsprechende Rolle an, beginne deine Antwort zwingend mit dem passenden Badge und passe dein Vokabular an:
* 🏗️ **[Lead Architect]:** System-Design, Gradle-Build-Logik, Modulstruktur.
* 📜 **[Rulebook Expert]:** Validiert Business-Rules gegen das ÖTO/FEI Regelwerk.
* 👷 **[Backend Developer]:** Kotlin & Spring Boot Experte.
* 🎨 **[Frontend Expert]:** KMP & Compose Desktop Spezialist.
* 🐧 **[DevOps Engineer]:** Infrastruktur (Docker, CI/CD, Proxmox).
**Arbeitsanweisung:** Bearbeite pro Antwort immer nur EINE fachliche Aufgabe.
## 🏗️ Projekt-Strategie (Reality-Reset)
1. **Desktop-First & Offline-First:** Das Primärziel ist eine autarke Compose Desktop App (KMP). Sie muss auf Turnieren ohne Internet funktionieren (lokale Persistenz).
2. **Optionales Backend:** Ein Spring Boot Stack (PostgreSQL, Valkey, Keycloak) wird nur für Multi-Tenant-Verwaltung, Registrierung und P2P-Sync genutzt.
3. **Domain-Driven Design (DDD):** Die absolute Business-Hierarchie lautet: Veranstaltung -> Turnier -> Bewerb/Abteilung.
4. **Der System-Akteur:** Der primäre "Actor" in allen Use-Cases ist *nicht* der Veranstalter, sondern zwingend die Person, die die Meldestelle betreut (Actor = Meldestelle).
## 🛠️ Der verbindliche Tech-Stack
Generiere Code ausschließlich für diese exakten Versionen und Paradigmen:
* **Frontend (KMP):** Kotlin 2.3.21, Compose Multiplatform 1.10.3, Ktor Client 3.4.1, SQLDelight.
* **Backend:** Spring Boot 3.5.9 (JDK 25), Ktor Server (wo spezifiziert), Exposed 1.1.1.
* **Infrastruktur:** Gitea (CI/CD), Docker, Pangolin Tunnel. (KEIN GitHub, KEIN Cloudflare).
## 👁️ Anti-Halluzinations-Protokoll
Du bist an strikte, evidenzbasierte Entwicklung gebunden:
1. **Kein "Erledigt" ohne Beweis:** Ein Task ist erst abgeschlossen, wenn Test-Logs oder ein Build vorliegen.
2. **Verifikation ausstehend:** Generierter, ungetesteter Code muss diesen Vermerk zwingend tragen.
3. **Fakten-Check:** Wenn du den Code nicht im Kontext hast (z.B. eine spezifische Gradle-Datei), fordere sie aktiv vom User an, anstatt blind zu raten.
## ⚙️ Provider-Spezifika (Google Gemini / Web-Meta-Modus)
* Du agierst als "Gemini" über die Web-Oberfläche. Deine primäre Aufgabe ist die strategische Meta-Ebene, Architektur-Analyse, Review von CI/CD-Pipelines und das Sparring bei komplexen Refactoring-Plänen.
* **Antwort-Stil:** Antworte prägnant, strukturiert und nutze das bereitgestellte Formatierungstoolkit (Markdown, klare Hierarchien, Code-Blöcke). Vermeide unnötige Floskeln und komm direkt auf den technischen Punkt.
+34
View File
@@ -0,0 +1,34 @@
## 🚀 Identität & Arbeitsmodus (Chamäleon-Modus)
Du bist ein hochqualifizierter KI-Assistent für das Softwareprojekt "Meldestelle" von Stefan.
Ich weise dir in meinen Prompts Aufgaben zu. Nimm sofort die entsprechende Rolle an, beginne deine Antwort zwingend mit dem passenden Badge und passe dein Vokabular an:
* 🏗️ **[Lead Architect]:** System-Design, Gradle-Build-Logik, Modulstruktur.
* 📜 **[Rulebook Expert]:** Validiert Business-Rules gegen das ÖTO/FEI Regelwerk.
* 👷 **[Backend Developer]:** Kotlin & Spring Boot Experte.
* 🎨 **[Frontend Expert]:** KMP & Compose Desktop Spezialist.
* 🐧 **[DevOps Engineer]:** Infrastruktur (Docker, CI/CD, Proxmox).
**Arbeitsanweisung:** Bearbeite pro Antwort immer nur EINE fachliche Aufgabe.
## 🏗️ Projekt-Strategie (Reality-Reset)
1. **Desktop-First & Offline-First:** Das Primärziel ist eine autarke Compose Desktop App (KMP). Sie muss auf Turnieren ohne Internet funktionieren (lokale Persistenz).
2. **Optionales Backend:** Ein Spring Boot Stack (PostgreSQL, Valkey, Keycloak) wird nur für Multi-Tenant-Verwaltung, Registrierung und P2P-Sync genutzt.
3. **Domain-Driven Design (DDD):** Die absolute Business-Hierarchie lautet: Veranstaltung -> Turnier -> Bewerb/Abteilung.
4. **Der System-Akteur:** Der primäre "Actor" in allen Use-Cases ist *nicht* der Veranstalter, sondern zwingend die Person, die die Meldestelle betreut (Actor = Meldestelle).
## 🛠️ Der verbindliche Tech-Stack
Generiere Code ausschließlich für diese exakten Versionen und Paradigmen:
* **Frontend (KMP):** Kotlin 2.3.21, Compose Multiplatform 1.10.3, Ktor Client 3.4.1, SQLDelight.
* **Backend:** Spring Boot 3.5.9 (JDK 25), Ktor Server (wo spezifiziert), Exposed 1.1.1.
* **Infrastruktur:** Gitea (CI/CD), Docker, Pangolin Tunnel. (KEIN GitHub, KEIN Cloudflare).
## 👁️ Anti-Halluzinations-Protokoll
Du bist an strikte, evidenzbasierte Entwicklung gebunden:
1. **Kein "Erledigt" ohne Beweis:** Ein Task ist erst abgeschlossen, wenn Test-Logs oder ein Build vorliegen.
2. **Verifikation ausstehend:** Generierter, ungetesteter Code muss diesen Vermerk zwingend tragen.
3. **Fakten-Check:** Wenn du den Code nicht im Kontext hast (z.B. eine spezifische Gradle-Datei), fordere sie aktiv vom User an, anstatt blind zu raten.
## ⚙️ Provider-Spezifika (JetBrains Junie / IDE-Modus)
* Dein Name ist "Junie". Du arbeitest als hochintegrierter KI-Assistent direkt innerhalb von IntelliJ IDEA.
* **Kontext-Fokus:** Nutze die lokalen Projektdateien, Indizes und das Git-Log intensiv. Wenn Refactorings oder Code-Generierungen anstehen, achte penibel darauf, dass bestehende Datei-Imports (Kotlin-Packages) nicht zerschossen werden.
* **Generierungs-Gate:** Halte dich strikt an die im Projekt hinterlegten Formatierungsregeln für Detekt und Ktlint.
+4
View File
@@ -56,3 +56,7 @@ desktop.ini
docs/temp/
docs/Bin/
docs/_archive/
# Conveyor
conveyor.rootkey
output/
+9 -9
View File
@@ -3,7 +3,7 @@
Dieses Dokument definiert die Zusammenarbeit zwischen dem User (Owner) und den spezialisierten KI-Agenten.
Es dient als zentraler **System-Prompt-Erweiterung** für neue Chat-Sessions.
## 🚀 Strategische Ausrichtung (Reality-Reset 28.04.2026)
## 🚀 Strategische Ausrichtung (Reality-Reset 15.06.2026)
Das Projekt **"Meldestelle"** entwickelt eine ÖTO/FEI-konforme, offline-fähige Turnier-Software.
1. **Desktop-First:** Primäres Ziel ist die Compose Desktop App (KMP). UX & Performance sind auf Profis optimiert.
@@ -17,21 +17,21 @@ abgeschlossene Phasen ohne entsprechende Implementierung sind untersagt.
Jede Agenten-Antwort **muss** mit dem entsprechenden Badge beginnen, um den Kontext und die Verantwortlichkeit zu klären.
* **🏗️ [Lead Architect]**: Hüter der **MASTER_ROADMAP**. Verantwortlich für System-Design, Build-Logik (Gradle), Modulstruktur und ADRs.
* [Playbook](docs/04_Agents/Playbooks/Architect.md)
* [Playbook](docs/05_Governance/Agents/Playbooks/Architect.md)
* **📜 [Rulebook Expert]**: Wächter über **ÖTO & FEI**. Validiert Business-Rules gegen das offizielle Pferdesport-Regelwerk.
* [Playbook](docs/04_Agents/Playbooks/RulebookExpert.md)
* [Playbook](docs/05_Governance/Agents/Playbooks/RulebookExpert.md)
* **👷 [Backend Developer]**: Kotlin & Spring Boot Experte. Fokus auf DDD, Persistenz (Postgres) und **Delta-Sync APIs**.
* [Playbook](docs/04_Agents/Playbooks/BackendDeveloper.md)
* [Playbook](docs/05_Governance/Agents/Playbooks/BackendDeveloper.md)
* **🎨 [Frontend Expert]**: KMP & Compose Desktop Spezialist. Implementiert State-Management und High-Performance UI.
* [Playbook](docs/04_Agents/Playbooks/FrontendExpert.md)
* [Playbook](docs/05_Governance/Agents/Playbooks/FrontendExpert.md)
* **🖌️ [UI/UX Designer]**: "Toolsmith" für High-Density Enterprise-UIs. Fokus auf Tastatur-Bedienbarkeit und Effizienz.
* [Playbook](docs/04_Agents/Playbooks/UIUXDesigner.md)
* [Playbook](docs/05_Governance/Agents/Playbooks/UIUXDesigner.md)
* **🐧 [DevOps Engineer]**: Infrastruktur-Automatisierung (Docker, Gitea-Actions). Fokus auf Stabilität und lokale Dev-Umgebung.
* [Playbook](docs/04_Agents/Playbooks/DevOpsEngineer.md)
* [Playbook](docs/05_Governance/Agents/Playbooks/DevOpsEngineer.md)
* **🧐 [QA Specialist]**: Test-Stratege (Shift-Left). Fokus auf Unit-, Integration- und Edge-Case-Tests (Testing Pyramid).
* [Playbook](docs/04_Agents/Playbooks/QASpecialist.md)
* [Playbook](docs/05_Governance/Agents/Playbooks/QASpecialist.md)
* **🧹 [Curator]**: Wissens-Management & Dokumentations-Check (ADR, Reference, Journal). Beendet jede Session.
* [Playbook](docs/04_Agents/Playbooks/Curator.md)
* [Playbook](docs/05_Governance/Agents/Playbooks/Curator.md)
## 2. Der "Meldestelle"-Workflow
1. **Kontext-Check:** Lies immer zuerst die `MASTER_ROADMAP` in `docs/01_Architecture/`.
+7 -1
View File
@@ -20,7 +20,7 @@ Die gesamte Projektdokumentation (Architektur, Fachdomäne, Entwickler-Anleitung
| [03_Domain](./docs/03_Domain) | Fachlichkeit, Turnierregeln, Entities |
| [07_Infrastructure](./docs/07_Infrastructure) | Docker, Keycloak, CI/CD, Zora-Infrastruktur |
Wesentliche Architektur-Referenz: [OfflineFirst Desktop & Backend (Kurzkonzept)](./docs/01_Architecture/konzept-offline-first-desktop-backend-de.md)
Wesentliche Architektur-Referenz: [OfflineFirst Desktop & Backend (Kurzkonzept)](./docs/01_Architecture/Concepts/konzept-offline-first-desktop-backend-de.md)
---
@@ -113,3 +113,9 @@ Beiträge sind willkommen. Bitte lies zunächst die Entwickler-Guides unter [`do
## 📜 Lizenz
Dieses Projekt steht unter der [MIT License](LICENSE).
---
## Test
Das ist der 2. Versuch über Remote zu Committen
@@ -8,7 +8,7 @@ import io.valkey.springframework.data.valkey.core.ValkeyTemplate
import io.valkey.springframework.data.valkey.serializer.StringValkeySerializer
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.testcontainers.containers.GenericContainer
@@ -70,7 +70,7 @@ class ValkeyDistributedCachePerformanceTest {
}
@Test
fun `test cache performance with high concurrent access`() = runTest {
fun `test cache performance with high concurrent access`() = runBlocking {
logger.info { "Starting concurrent access test" }
val numberOfCoroutines = 100
val operationsPerCoroutine = 50
@@ -2,6 +2,7 @@
package at.mocode.zns.importer
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.masterdata.domain.repository.*
import at.mocode.zns.parser.ZnsFunktionaerParser
import at.mocode.zns.parser.ZnsPferdParser
@@ -3,6 +3,7 @@
package at.mocode.masterdata.domain.model
import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.domain.serialization.InstantSerializer
import at.mocode.core.domain.serialization.LocalDateSerializer
@@ -14,16 +15,6 @@ import kotlin.time.Clock
import kotlin.time.Instant
import kotlin.uuid.Uuid
@Serializable
data class ReiterLizenz(
@Serializable(with = UuidSerializer::class)
val lizenzId: Uuid = Uuid.random(),
val lizenzTyp: String, // STARTKARTE, REITERLIZENZ, FAHRLIZENZ
val kuerzel: String,
@Serializable(with = LocalDateSerializer::class)
val gueltigBis: LocalDate? = null
)
/**
* Domain model representing a rider (Reiter) in the actor-context.
*
@@ -4,10 +4,10 @@ package at.mocode.masterdata.infrastructure.persistence.reiter
import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.ReiterAltersKlasseE
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.utils.database.DatabaseFactory
import at.mocode.masterdata.domain.model.Reiter
import at.mocode.masterdata.domain.model.ReiterLizenz
import at.mocode.masterdata.domain.repository.ReiterRepository
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.and
+44 -23
View File
@@ -38,7 +38,7 @@ plugins {
// ### ALLPROJECTS CONFIGURATION ###
// ##################################################################
val isWasmEnabled = findProperty("enableWasm")?.toString()?.toBoolean() ?: false
val isWasmEnabled: Boolean = findProperty("enableWasm")?.toString()?.toBoolean() ?: false
// ---------------------------------------------------------------
// Zentrale Versionierung — liest version.properties (SemVer)
@@ -47,10 +47,10 @@ val versionProps =
java.util.Properties().also { props ->
rootProject.file("version.properties").inputStream().use { props.load(it) }
}
val vMajor = versionProps.getProperty("VERSION_MAJOR", "1")
val vMinor = versionProps.getProperty("VERSION_MINOR", "0")
val vPatch = versionProps.getProperty("VERSION_PATCH", "0")
val vQualifier = versionProps.getProperty("VERSION_QUALIFIER", "").trim()
val vMajor: String = versionProps.getProperty("VERSION_MAJOR", "1")
val vMinor: String = versionProps.getProperty("VERSION_MINOR", "0")
val vPatch: String = versionProps.getProperty("VERSION_PATCH", "0")
val vQualifier: String = versionProps.getProperty("VERSION_QUALIFIER", "").trim()
val semVer = if (vQualifier.isBlank()) "$vMajor.$vMinor.$vPatch" else "$vMajor.$vMinor.$vPatch-$vQualifier"
allprojects {
@@ -90,7 +90,7 @@ subprojects {
jvmArgs("--add-opens=java.base/java.nio=ALL-UNNAMED")
// Suppress ByteBuddy/Mockito dynamic agent loading warnings (Java 21+)
jvmArgs("-XX:+EnableDynamicAgentLoading")
// Increase test JVM memory with a stable configuration
jvmArgs("--enable-native-access=ALL-UNNAMED")
minHeapSize = "512m"
maxHeapSize = "2g"
// Parallel test execution for better performance
@@ -113,7 +113,7 @@ subprojects {
// (A) Source map configuration is handled via `gradle.properties` (global Kotlin/JS settings)
// to avoid compiler-flag incompatibilities across toolchains.
// (B) Conditional Wasm/JS Target handling based on `enableWasm` property
// (B) Conditional Wasm/JS Target handling based on the ` enableWasm ` property
// This significantly reduces build times during Desktop development.
// Flag is defined at the beginning of the script.
@@ -166,6 +166,7 @@ subprojects {
jvmArgs("-Xshare:auto", "-Djdk.instrument.traceUsage=false")
jvmArgs("--add-opens=java.base/java.nio=ALL-UNNAMED")
jvmArgs("-XX:+EnableDynamicAgentLoading")
jvmArgs("--enable-native-access=ALL-UNNAMED")
maxHeapSize = "2g"
dependsOn("testClasses")
}
@@ -175,20 +176,30 @@ subprojects {
// Applies to all Exec-based tasks (covers Yarn/NPM invocations used by Kotlin JS plugin)
tasks.withType<Exec>().configureEach {
// Merge existing NODE_OPTIONS with --no-deprecation
val current = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
val merged = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
val current: String? = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
val merged: String = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
environment("NODE_OPTIONS", merged)
// Also set the legacy switch to silence warnings entirely
environment("NODE_NO_WARNINGS", "1")
// Set a Chrome binary path to avoid snap permission issues
if (System.getProperty("os.name").contains("Linux", ignoreCase = true)) {
environment("CHROME_BIN", "/usr/bin/google-chrome-stable")
environment("CHROMIUM_BIN", "/usr/bin/chromium")
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
}
}
// ------------------------------
// Detekt & Ktlint default setup
// ------------------------------
// PERFORMANCE: Deaktiviert standardmäßig in jedem Build, nur explizit ausführen
tasks.withType<Detekt>().configureEach {
enabled = project.hasProperty("runStaticAnalysis")
}
tasks.matching { it.name == "ktlintCheck" }.configureEach {
enabled = project.hasProperty("runStaticAnalysis")
}
plugins.withId("io.gitlab.arturbosch.detekt") {
extensions.configure(DetektExtension::class.java) {
buildUponDefaultConfig = true
@@ -267,7 +278,6 @@ tasks.register("checkBundleBudget") {
}
shells.forEach { shell ->
val key = shell.path.trimStart(':').replace(':', '/') // or use a colon form for budgets keys below
val colonKey = shell.path.trimStart(':').replace('/', ':').trim() // ensure ":a:b:c"
// Budgets are keyed by a Gradle path with colons but without leading colon in config for readability
val budgetKeyCandidates =
@@ -362,8 +372,8 @@ tasks.register("staticAnalysis") {
// Apply Dokka (V2) automatically to Kotlin subprojects
subprojects {
plugins.withId("org.jetbrains.kotlin.jvm") { apply(plugin = "org.jetbrains.dokka") }
plugins.withId("org.jetbrains.kotlin.multiplatform") { apply(plugin = "org.jetbrains.dokka") }
plugins.withId("org.jetbrains.kotlin.jvm") { pluginManager.apply("org.jetbrains.dokka") }
plugins.withId("org.jetbrains.kotlin.multiplatform") { pluginManager.apply("org.jetbrains.dokka") }
}
// Aggregate tasks to build multi-module docs in Markdown (GFM) and HTML
@@ -372,27 +382,36 @@ val dokkaAll =
tasks.register("dokkaAll") {
group = "documentation"
description = "Builds Dokka (V2) for all modules and aggregates outputs under build/dokka/all"
// Trigger Dokka generation in all subprojects that have the Dokka plugin
dependsOn(
// PERFORMANCE: Nur ausführen wenn explizit gefordert
enabled = project.hasProperty("runDokka")
// Capture required values for configuration cache
val rootBuildDir = layout.buildDirectory.get().asFile
val subprojectData =
subprojects
.filter { it.plugins.hasPlugin("org.jetbrains.dokka") }
.map { "${it.path}:dokkaGenerate" },
)
.map { p ->
Triple(p.path, p.name, p.layout.buildDirectory.get().asFile)
}
// Trigger Dokka generation in all subprojects that have the Dokka plugin
dependsOn(subprojectData.map { "${it.first}:dokkaGenerate" })
doLast {
val dest = layout.buildDirectory.dir("dokka/all").get().asFile
val dest = File(rootBuildDir, "dokka/all")
if (dest.exists()) dest.deleteRecursively()
dest.mkdirs()
val modules = mutableListOf<Pair<String, String>>()
subprojects.filter { it.plugins.hasPlugin("org.jetbrains.dokka") }.forEach { p ->
subprojectData.forEach { (pPath, pName, pBuildDir) ->
// Dokka V2 writes into build/dokka/html
val outHtml = p.layout.buildDirectory.dir("dokka/html").get().asFile
val outHtml = File(pBuildDir, "dokka/html")
if (outHtml.exists()) {
val modulePath = p.path.trimStart(':').replace(':', '/')
val modulePath = pPath.trimStart(':').replace(':', '/')
val targetDir = File(dest, modulePath)
outHtml.copyRecursively(targetDir, overwrite = true)
modules.add(p.name to modulePath)
modules.add(pName to modulePath)
}
}
@@ -451,15 +470,17 @@ tasks.register("docs") {
// Apply Node warning suppression on root project Exec tasks as well
// Ensures aggregated Kotlin/JS tasks created at root (e.g., kotlinNpmInstall) inherit the env
tasks.withType<Exec>().configureEach {
val current = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
val merged = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
val current: String? = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
val merged: String = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
environment("NODE_OPTIONS", merged)
environment("NODE_NO_WARNINGS", "1")
// Set a Chrome binary path to avoid snap permission issues
if (System.getProperty("os.name").contains("Linux", ignoreCase = true)) {
environment("CHROME_BIN", "/usr/bin/google-chrome-stable")
environment("CHROMIUM_BIN", "/usr/bin/chromium")
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
}
}
tasks.wrapper {
gradleVersion = "9.5.0"
+17 -34
View File
@@ -1,63 +1,46 @@
# =============================================================================
# Conveyor Configuration for Meldestelle Desktop App
# =============================================================================
# Dieser Build-Weg ermöglicht das Cross-Packaging für Windows (MSI) auf Linux.
# Dokumentation: https://conveyor.hydraulic.dev/
# =============================================================================
include required("/stdlib/jdk/21/amazon.conf")
include required("https://raw.githubusercontent.com/hydraulic-software/conveyor/master/configs/jvm/extract-native-libraries.conf")
# Basis-Import der Gradle-Konfiguration (sofern das Plugin genutzt wird,
# aber wir definieren es hier explizit für maximale Kontrolle im CI/CD).
app {
# Anzeige-Name und Vendor
display-name = "Meldestelle"
rdns-name = "at.mocode.meldestelle"
vendor = "mo-code.at"
contact-email = "support@mo-code.at"
version = "1.0.1"
description = "ÖTO-konforme Turnier-Meldestelle Profi Desktop App"
# Version aus version.properties (Conveyor kann HOCON-Variablen nutzen)
# Für diesen Task hart codiert oder via CLI-Flag --variable übergeben.
version = "1.0.0"
# Ziel-Plattformen: Windows und Linux
machines = [ windows.amd64, linux.amd64.glibc ]
# Beschreibung
description = "ÖTO-konforme Turnier-Meldestelle Desktop App"
site.base-url = "localhost"
# Ziel-Plattformen
# Wir konzentrieren uns auf Windows, können aber Linux/Mac später ergänzen.
site.base-url = "localhost" # Später echte Update-URL
# Icons
# Icons werden im Ordner gesucht
icons = "frontend/shells/meldestelle-desktop/src/jvmMain/resources/icon.png"
# Einbetten der JRE (Temurin 21 wie in CI genutzt)
jvm {
gui {
main-class = "at.mocode.frontend.shell.desktop.MainKt"
}
# JVM-Argumente (analog build.gradle.kts)
jvm-options = [
"-Xms128m",
"-Xmx512m",
"-Xms256m",
"-Xmx1024m",
"-Dfile.encoding=UTF-8",
"--enable-native-access=ALL-UNNAMED"
]
}
# Input-Dateien: Hier ziehen wir die Uber-JAR oder die Gradle-Outputs.
# Da wir plattformunabhängig bleiben wollen, nutzen wir das Gradle-Output-Dir.
inputs += "frontend/shells/meldestelle-desktop/build/libs/meldestelle-desktop-jvm-*.jar"
# JARs aus dem Gradle-Build
inputs += "frontend/shells/meldestelle-desktop/build/libs/*.jar"
# Windows-spezifische Einstellungen
windows {
# Icon als .ico
icons = "frontend/shells/meldestelle-desktop/src/jvmMain/resources/icon.ico"
# GUID für Upgrades (muss stabil bleiben)
upgrade-uuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
# Menü-Eintrag
menu-group = "Meldestelle"
# Verknüpfung
desktop-shortcut = true
}
linux {
debian.control.depends = "libasound2, libgl1-mesa-glx, libx11-6"
}
}
conveyor.compatibility-level = 22
@@ -0,0 +1,19 @@
@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class)
package at.mocode.core.domain.model
import at.mocode.core.domain.serialization.LocalDateSerializer
import at.mocode.core.domain.serialization.UuidSerializer
import kotlinx.datetime.LocalDate
import kotlinx.serialization.Serializable
import kotlin.uuid.Uuid
@Serializable
data class ReiterLizenz(
@Serializable(with = UuidSerializer::class)
val lizenzId: Uuid = Uuid.random(),
val lizenzTyp: String, // STARTKARTE, REITERLIZENZ, FAHRLIZENZ
val kuerzel: String,
@Serializable(with = LocalDateSerializer::class)
val gueltigBis: LocalDate? = null
)
@@ -1,10 +1,10 @@
package at.mocode.zns.parser
import at.mocode.core.domain.model.DatenQuelleE
import at.mocode.core.domain.model.ReiterLizenz
import at.mocode.core.domain.model.ReiterLizenzKlasseE
import at.mocode.core.utils.parser.FixedWidthLineReader
import at.mocode.masterdata.domain.model.Reiter
import at.mocode.masterdata.domain.model.ReiterLizenz
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
+15 -14
View File
@@ -2,12 +2,12 @@
type: Roadmap
status: ACTIVE
owner: Lead Architect
last_update: 2026-05-06
last_update: 2026-06-15
---
# MASTER ROADMAP: Meldestelle
🏗️ **[Lead Architect]** | 30. April 2026
🏗️ **[Lead Architect]** | 15. Juni 2026
**Strategisches Ziel:**
Entwicklung einer ÖTO-konformen, offline-fähigen Turnier-Meldestelle als Compose Desktop App (KMP).
@@ -17,16 +17,16 @@ Vollständige Self-Hosted Infrastruktur (Gitea, Pangolin, Zora). Datensouveräni
- Desktop-App ist der primäre Client (Compose Desktop, KMP) — „Desktop-First“ gilt für UX und Architektur.
- Offline-First Betrieb mit lokaler Persistenz und opportunistischer Synchronisation.
**Aktueller technischer Stand (30.04.2026):**
**Aktueller technischer Stand (15.06.2026):**
* **Infrastruktur:** ✅ "Zora" (MS-R1, ARM64) ist live. Gitea & Registry laufen.
* **Networking:** ✅ Pangolin Tunnel ersetzt Cloudflare.
* **CI/CD:** ✅ Gitea Actions mit ARM64-Runner (VM 102) aktiv. Docker-Publish Pipeline grün.
* **Code-Basis:** ✅ Backend (Java 25 / Spring Boot / Kotlin), Frontend (KMP/Compose Desktop).
* **Domain-Design:** ✅ 6 Bounded Contexts (SCS-Architektur) definiert. Ubiquitous Language erstellt.
* **Domain-Modelle:** ✅ `Reiter`, `DomNennung`, `DomNennungsTransfer`, `Pferd`, `Funktionaer`, `Verein`,
`DomBewerb`, `DomAbteilung`, `DomStartliste`, `DomVeranstaltung`, `DomTurnier`, `DomAusschreibung` implementiert.
* **Domain-Modelle:** ✅ `Reiter`, `Nennung`, `NennungsTransfer`, `Pferd`, `Funktionaer`, `Verein`,
`Bewerb`, `Abteilung`, `DomStartliste`, `Veranstaltung`, `Turnier`, `Ausschreibung` implementiert.
Enums ÖTO-konform.
* **Dokumentation:** ✅ Konsolidiert. ÖTO-Regelwerk-Referenzen (Abteilungs-Schwellenwerte) dokumentiert.
* **Dokumentation:** 🧹 Sanierung abgeschlossen (5-Säulen-Struktur). Reality-Reset durchgeführt.
---
@@ -88,6 +88,7 @@ Fokus: Physische Implementierung der Turnier-Hierarchie und technisches Onboardi
* [x] **Client-Konfiguration:** Master kann nun Clients in der UI hinzufügen und bearbeiten.
* [x] **Master-UX:** Konfiguration beim Start nicht mehr zwangsgesperrt.
* [x] **Cross-Packaging (Conveyor):** Windows-Build auf Linux-CI ermöglicht (x64-Abhängigkeit identifiziert).
* [x] **Build-Performance:** WASM standardmäßig deaktiviert, um Desktop-Build-Zeiten zu reduzieren (11.05.2026).
* [ ] **PoC Verifikation:** 🔴 **BLOCKIERT** (Log 483: ARM64-Runner inkompatibel mit Conveyor-Binary; Workflow auf
manuell gesetzt).
@@ -154,15 +155,15 @@ Code-Stand.*
| Dokument | Pfad |
|-------------------------------|----------------------------------------------------------------------------------------------|
| Ubiquitous Language | `docs/03_Domain/01_Glossary/Ubiquitous_Language.md` |
| Abteilungs-Schwellenwerte | `docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md` |
| Warn-Logik-Spezifikation | `docs/03_Domain/02_Reference/OETO_Regelwerk/Warn-Logik-Spezifikation-competition-context.md` |
| Session Log (DDD) | `docs/99_Journal/2026-03-24_Session_Log_DDD_Ubiquitous_Language.md` |
| Infrastruktur | `docs/07_Infrastructure/Zora_System_Architektur.md` |
| Deployment Guide | `docs/07_Infrastructure/Guides/Setup_Git_Deployment_Zora.md` |
| Backup Guide | `docs/07_Infrastructure/Guides/Setup_Backup_Zora.md` |
| Ubiquitous Language | `docs/02_Domain/01_Glossary/Ubiquitous_Language.md` |
| Abteilungs-Schwellenwerte | `docs/02_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md` |
| Warn-Logik-Spezifikation | `docs/02_Domain/02_Reference/OETO_Regelwerk/Warn-Logik-Spezifikation-competition-context.md` |
| Session Log (DDD) | `docs/05_Governance/Journal/_archive/2026-03-24_Session_Log_DDD_Ubiquitous_Language.md` |
| Infrastruktur | `docs/04_Operations/Infrastructure/Zora_System_Architektur.md` |
| Deployment Guide | `docs/04_Operations/Infrastructure/Guides/Setup_Git_Deployment_Zora.md` |
| Backup Guide | `docs/04_Operations/Infrastructure/Guides/Setup_Backup_Zora.md` |
| CI/CD | `.gitea/workflows/docker-publish.yaml` |
| Agent Playbooks | `docs/04_Agents/Playbooks/` |
| Agent Playbooks | `docs/05_Governance/Agents/Playbooks/` |
| ADR-Verzeichnis | `docs/01_Architecture/adr/` |
| ADR-0025: Plan-USB | `docs/01_Architecture/adr/0025-plan-usb-offline-integritaet.md` |
| ADR-0026: Lizenzierung | `docs/01_Architecture/adr/0026-offline-lizenzierung-pay-per-event.md` |
@@ -2,11 +2,12 @@
type: Reference
status: ACTIVE
owner: Lead Architect & ÖTO/FEI Rulebook Expert
last_update: 2026-04-05
last_update: 2026-06-15
sources:
- ÖTO 2026, Abschnitt A I, § 2 & § 3 & § 4
- Domain Workshop 2026-03-17
- Session 2026-03-24 (Architektur-Diskussion)
- Sanierung 2026-06-15 (Reality-Reset)
---
# Ubiquitous Language Offizielle Domänen-Terminologie
@@ -146,7 +147,7 @@ Veranstalter (OEPS-Mitgliedsverein)
| **Sparte** | Die unterschiedlichen Arten von Turnieren oder Bewerben (z.B. Dressur = CDN, Springen = CSN). Bestimmt das anzuwendende Richtverfahren und das Regelwerk. | ÖTO § 2 Abs. 9, § 3 Abs. 2 |
| **Sperrliste** | Vom Verband geführte Liste von Personen oder Pferden, die aktuell nicht startberechtigt sind (meist wegen offener Zahlungen). | – |
| **Sportförderbeitrag** | Gebühr, die **pro Start** anfällt (nicht pro Nennung!). Relevant bei Mehrfach-Starts. | ÖTO Gebührenordnung |
| **Stammdaten** | (Früher: Akteur-Context). Die zentrale Library of Truth (`master-data-context`) für alle statischen Informationen: Personen, Pferde, Vereine, sowie das ÖTO-Regelwerk (Richtverfahren, Paragraphen, Gebührensätze). | |
| **Stammdaten** | Die zentrale Library of Truth (`masterdata-context`) für alle statischen Informationen: Personen, Pferde, Vereine, sowie das ÖTO-Regelwerk (Richtverfahren, Paragraphen, Gebührensätze). | |
| **Startkarte** | Nachweis, dass die Jahresgebühr für die Lizenz bezahlt wurde. Ohne aktive Startkarte ist national kein Start möglich. | ÖTO Teilnahmeberechtigung |
| **Startwunsch** | Präferenz eines Reiters bezüglich seiner Position in der Startliste (vorne/hinten). | Registration Context |
@@ -188,7 +189,7 @@ Veranstalter (OEPS-Mitgliedsverein)
| Veranstaltung, Turnier, Ausschreibung, Veranstalter | `event-management-context` |
| Bewerb, Abteilung, Startliste, Ergebnis, Richtverfahren | `competition-context` |
| Nennung, Nennungs-Transfer, Startwunsch, ZNS-Import | `registration-context` |
| Reiter, Pferd, Lizenz, Funktionär, Kopfnummer, Satznummer, Verein | `actor-context` |
| Reiter, Pferd, Lizenz, Funktionär, Kopfnummer, Satznummer, Verein | `masterdata-context` |
| Nenngeld, Startgeld, Konto, Transaktion, Sportförderbeitrag | `billing-context` |
| Cup, Serie, Meisterschaft, Reglement, Endklassement | `series-context` *(Phase 2+)* |
| Login, Rolle, Berechtigung | `identity-context` |
@@ -222,7 +223,7 @@ Ein Reglement definiert typischerweise:
- Verschiedene Cups/Serien können **unterschiedliche Punktesysteme** haben → das Berechnungsmodell muss pluggable sein.
- Die **Paar-Bindung** (Punkte an Reiter+Pferd vs. nur Reiter) ist eine kritische Designentscheidung pro Reglement.
- Referenz-Dokument: [
`docs/03_Domain/02_Reference/OETO_Regelwerk/Struktur-Meisterschafts-Cup-Reglements_OETO.md`](../02_Reference/OETO_Regelwerk/Struktur-Meisterschafts-Cup-Reglements_OETO.md)
`docs/02_Domain/02_Reference/OETO_Regelwerk/Struktur-Meisterschafts-Cup-Reglements_OETO.md`](../02_Reference/OETO_Regelwerk/Struktur-Meisterschafts-Cup-Reglements_OETO.md)
---
@@ -241,4 +242,4 @@ Ein Reglement definiert typischerweise:
---
*Erstellt: 2026-03-24 | Autoren: Lead Architect, ÖTO/FEI Rulebook Expert, Curator*
*Basiert auf: ÖTO 2026 § 2, § 3, § 4 | Domain Workshop 2026-03-17 | Session 2026-03-24 | Update: 2026-04-05 (Verein-Renaming & Bereinigung)*
*Basiert auf: ÖTO 2026 § 2, § 3, § 4 | Domain Workshop 2026-03-17 | Session 2026-03-24 | Update: 2026-06-15 (Reality-Reset & Alignment)*

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Before

Width:  |  Height:  |  Size: 325 KiB

After

Width:  |  Height:  |  Size: 325 KiB

Some files were not shown because too many files have changed in this diff Show More