Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a74b0bb815 | |||
| 40cf1e5d22 | |||
| ce63303b2c | |||
| e4988b4397 | |||
| 8816e8d297 | |||
| 98d0bf0c7b | |||
| 0a90b57c2a | |||
| 0ab62a2752 | |||
| 6070709bf2 | |||
| 763c2a9157 | |||
| 4f715d10bb | |||
| 0b830eb675 | |||
| 4c37ecb952 | |||
| c25ef17a4a | |||
| e5e3b4cfec | |||
| 7d064853e5 | |||
| 387180c12c | |||
| 49393d3eac | |||
| e389fe9bce |
Vendored
+41
@@ -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.
|
||||
Vendored
+34
@@ -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.
|
||||
@@ -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/`.
|
||||
|
||||
@@ -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: [Offline‑First Desktop & Backend (Kurzkonzept)](./docs/01_Architecture/konzept-offline-first-desktop-backend-de.md)
|
||||
Wesentliche Architektur-Referenz: [Offline‑First 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
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+1
@@ -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
|
||||
|
||||
+1
-10
@@ -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.
|
||||
*
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+48
-28
@@ -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 {
|
||||
@@ -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.
|
||||
|
||||
@@ -176,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
|
||||
environment("CHROME_BIN", "/usr/bin/google-chrome-stable")
|
||||
environment("CHROMIUM_BIN", "/usr/bin/chromium")
|
||||
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
|
||||
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
|
||||
@@ -268,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 =
|
||||
@@ -363,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
|
||||
@@ -373,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,14 +470,16 @@ 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
|
||||
environment("CHROME_BIN", "/usr/bin/google-chrome-stable")
|
||||
environment("CHROMIUM_BIN", "/usr/bin/chromium")
|
||||
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
|
||||
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 {
|
||||
|
||||
+12
-13
@@ -1,25 +1,20 @@
|
||||
# =============================================================================
|
||||
# Conveyor Configuration for Meldestelle Desktop App
|
||||
# =============================================================================
|
||||
|
||||
include required("/stdlib/jdk/21/openjdk.conf")
|
||||
include required("/stdlib/jdk/21/amazon.conf")
|
||||
include required("https://raw.githubusercontent.com/hydraulic-software/conveyor/master/configs/jvm/extract-native-libraries.conf")
|
||||
|
||||
app {
|
||||
display-name = "Meldestelle"
|
||||
rdns-name = "at.mocode.meldestelle"
|
||||
vendor = "mo-code.at"
|
||||
contact-email = "support@mo-code.at"
|
||||
version = "1.0.0"
|
||||
description = "ÖTO-konforme Turnier-Meldestelle – Desktop App"
|
||||
version = "1.0.1"
|
||||
description = "ÖTO-konforme Turnier-Meldestelle – Profi Desktop App"
|
||||
|
||||
# Ziel-Plattformen: Windows und Linux (AMD/Intel 64-bit)
|
||||
# Ziel-Plattformen: Windows und Linux
|
||||
machines = [ windows.amd64, linux.amd64.glibc ]
|
||||
|
||||
site.base-url = "localhost"
|
||||
|
||||
# Wir geben nur den Ordner an, Conveyor findet die icon.png darin automatisch
|
||||
icons = "frontend/shells/meldestelle-desktop/src/jvmMain/resources"
|
||||
# Icons werden im Ordner gesucht
|
||||
icons = "frontend/shells/meldestelle-desktop/src/jvmMain/resources/icon.png"
|
||||
|
||||
jvm {
|
||||
gui {
|
||||
@@ -27,8 +22,8 @@ app {
|
||||
}
|
||||
|
||||
jvm-options = [
|
||||
"-Xms128m",
|
||||
"-Xmx512m",
|
||||
"-Xms256m",
|
||||
"-Xmx1024m",
|
||||
"-Dfile.encoding=UTF-8",
|
||||
"--enable-native-access=ALL-UNNAMED"
|
||||
]
|
||||
@@ -42,6 +37,10 @@ app {
|
||||
menu-group = "Meldestelle"
|
||||
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
|
||||
|
||||
|
||||
@@ -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` |
|
||||
|
||||
+6
-5
@@ -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 |
@@ -1,98 +0,0 @@
|
||||
# 📦 Guide: Desktop App Packaging (Linux, Windows, macOS)
|
||||
|
||||
Dieses Dokument beschreibt, wie die Meldestelle Desktop App für verschiedene Betriebssysteme paketiert wird. Wir nutzen einen hybriden Ansatz aus **Gradle (Compose-Desktop)** für lokale Linux-Builds und **Conveyor** für das Cross-Packaging (Windows/macOS) von Linux aus.
|
||||
|
||||
---
|
||||
|
||||
## 1. Voraussetzungen
|
||||
|
||||
### Linux (Entwicklungsrechner / Fedora)
|
||||
Um native Pakete bauen zu können, müssen folgende Werkzeuge auf dem System vorhanden sein:
|
||||
|
||||
```bash
|
||||
# Für RPM-Pakete (Fedora)
|
||||
sudo dnf install rpm-build
|
||||
|
||||
# Für DEB-Pakete (Ubuntu/Debian)
|
||||
sudo apt install dpkg-dev fakeroot
|
||||
```
|
||||
|
||||
### Conveyor (Cross-Packaging Tool)
|
||||
Conveyor wird benötigt, um von Linux aus Windows-Installer (.msi) oder macOS-Pakete zu erzeugen.
|
||||
|
||||
**Installation auf Fedora/Linux:**
|
||||
Da automatisierte Skripte manchmal unzuverlässig sind, hier der direkte Weg über das Binär-Paket:
|
||||
|
||||
1. **Tarball herunterladen:**
|
||||
Besuchen Sie [https://downloads.hydraulic.dev/conveyor/download.html](https://downloads.hydraulic.dev/conveyor/download.html) und laden Sie die neueste `linux-amd64.tar.gz` Datei herunter.
|
||||
|
||||
2. **Manuelle Installation:**
|
||||
```bash
|
||||
# Entpacken
|
||||
tar -xvf hydraulic-conveyor-*-linux-amd64.tar.gz
|
||||
# In den Pfad verschieben
|
||||
sudo mv conveyor /usr/local/bin/
|
||||
```
|
||||
|
||||
3. **Verifizieren:**
|
||||
```bash
|
||||
conveyor --version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Lokale Linux-Builds (Gradle)
|
||||
|
||||
Die schnellste Methode, um während der Entwicklung ein installierbares Paket für das eigene System zu erstellen.
|
||||
|
||||
### RPM-Paket (Fedora)
|
||||
```bash
|
||||
./gradlew :frontend:shells:meldestelle-desktop:packageRpm
|
||||
```
|
||||
*Ausgabe: `frontend/shells:meldestelle-desktop/build/compose/binaries/main/rpm/`*
|
||||
|
||||
### DEB-Paket (Ubuntu/Debian)
|
||||
```bash
|
||||
./gradlew :frontend:shells:meldestelle-desktop:packageDeb
|
||||
```
|
||||
*Ausgabe: `frontend/shells:meldestelle-desktop/build/compose/binaries/main/deb/`*
|
||||
|
||||
### Portable Version (Ohne Installation)
|
||||
```bash
|
||||
./gradlew :frontend:shells:meldestelle-desktop:createDistributable
|
||||
```
|
||||
*Ausgabe: `frontend/shells:meldestelle-desktop/build/compose/binaries/main/app/`*
|
||||
|
||||
---
|
||||
|
||||
## 3. Cross-Packaging mit Conveyor
|
||||
|
||||
Conveyor nutzt die kompilierte JAR-Datei und schnürt daraus Pakete für alle Zielplattformen.
|
||||
|
||||
### Schritt 1: JAR erstellen
|
||||
```bash
|
||||
./gradlew :frontend:shells:meldestelle-desktop:jvmJar
|
||||
```
|
||||
|
||||
### Schritt 2: Pakete bauen
|
||||
```bash
|
||||
# Erstellt den Windows-Installer und die HTML-Downloadseite
|
||||
conveyor make site
|
||||
```
|
||||
|
||||
### Schritt 3: Ergebnisse
|
||||
Die fertigen Installer (z.B. `.msi` für Windows) befinden sich im neu erstellten Ordner `output/`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Problembehandlung & Optimierung
|
||||
|
||||
### Native Access Warnungen
|
||||
Die App benötigt Zugriff auf native Bibliotheken (Netty/SQLite). Der notwendige Parameter `--enable-native-access=ALL-UNNAMED` ist bereits fest hinterlegt.
|
||||
|
||||
### Firewall-Konfiguration
|
||||
Für Netzwerk-Tests (Discovery/Chat) müssen die Ports 8090, 8080 und 5353 (UDP) geöffnet sein.
|
||||
Nutzen Sie dafür das bereitgestellte Skript:
|
||||
```bash
|
||||
sudo ./setup-firewall-linux.sh
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user