Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a74b0bb815 | |||
| 40cf1e5d22 | |||
| ce63303b2c | |||
| e4988b4397 | |||
| 8816e8d297 | |||
| 98d0bf0c7b | |||
| 0a90b57c2a | |||
| 0ab62a2752 | |||
| 6070709bf2 | |||
| 763c2a9157 | |||
| 4f715d10bb | |||
| 0b830eb675 | |||
| 4c37ecb952 | |||
| c25ef17a4a | |||
| e5e3b4cfec |
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
* **🏗️ [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.
|
* **📜 [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**.
|
* **👷 [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.
|
* **🎨 [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.
|
* **🖌️ [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.
|
* **🐧 [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).
|
* **🧐 [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.
|
* **🧹 [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
|
## 2. Der "Meldestelle"-Workflow
|
||||||
1. **Kontext-Check:** Lies immer zuerst die `MASTER_ROADMAP` in `docs/01_Architecture/`.
|
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 |
|
| [03_Domain](./docs/03_Domain) | Fachlichkeit, Turnierregeln, Entities |
|
||||||
| [07_Infrastructure](./docs/07_Infrastructure) | Docker, Keycloak, CI/CD, Zora-Infrastruktur |
|
| [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
|
## 📜 Lizenz
|
||||||
|
|
||||||
Dieses Projekt steht unter der [MIT License](LICENSE).
|
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 io.valkey.springframework.data.valkey.serializer.StringValkeySerializer
|
||||||
import kotlinx.coroutines.joinAll
|
import kotlinx.coroutines.joinAll
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.testcontainers.containers.GenericContainer
|
import org.testcontainers.containers.GenericContainer
|
||||||
@@ -70,7 +70,7 @@ class ValkeyDistributedCachePerformanceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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" }
|
logger.info { "Starting concurrent access test" }
|
||||||
val numberOfCoroutines = 100
|
val numberOfCoroutines = 100
|
||||||
val operationsPerCoroutine = 50
|
val operationsPerCoroutine = 50
|
||||||
|
|||||||
+1
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
package at.mocode.zns.importer
|
package at.mocode.zns.importer
|
||||||
|
|
||||||
|
import at.mocode.core.domain.model.ReiterLizenz
|
||||||
import at.mocode.masterdata.domain.repository.*
|
import at.mocode.masterdata.domain.repository.*
|
||||||
import at.mocode.zns.parser.ZnsFunktionaerParser
|
import at.mocode.zns.parser.ZnsFunktionaerParser
|
||||||
import at.mocode.zns.parser.ZnsPferdParser
|
import at.mocode.zns.parser.ZnsPferdParser
|
||||||
|
|||||||
+1
-10
@@ -3,6 +3,7 @@
|
|||||||
package at.mocode.masterdata.domain.model
|
package at.mocode.masterdata.domain.model
|
||||||
|
|
||||||
import at.mocode.core.domain.model.DatenQuelleE
|
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.model.ReiterLizenzKlasseE
|
||||||
import at.mocode.core.domain.serialization.InstantSerializer
|
import at.mocode.core.domain.serialization.InstantSerializer
|
||||||
import at.mocode.core.domain.serialization.LocalDateSerializer
|
import at.mocode.core.domain.serialization.LocalDateSerializer
|
||||||
@@ -14,16 +15,6 @@ import kotlin.time.Clock
|
|||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
import kotlin.uuid.Uuid
|
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.
|
* 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.DatenQuelleE
|
||||||
import at.mocode.core.domain.model.ReiterAltersKlasseE
|
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.domain.model.ReiterLizenzKlasseE
|
||||||
import at.mocode.core.utils.database.DatabaseFactory
|
import at.mocode.core.utils.database.DatabaseFactory
|
||||||
import at.mocode.masterdata.domain.model.Reiter
|
import at.mocode.masterdata.domain.model.Reiter
|
||||||
import at.mocode.masterdata.domain.model.ReiterLizenz
|
|
||||||
import at.mocode.masterdata.domain.repository.ReiterRepository
|
import at.mocode.masterdata.domain.repository.ReiterRepository
|
||||||
import org.jetbrains.exposed.v1.core.ResultRow
|
import org.jetbrains.exposed.v1.core.ResultRow
|
||||||
import org.jetbrains.exposed.v1.core.and
|
import org.jetbrains.exposed.v1.core.and
|
||||||
|
|||||||
+16
-13
@@ -38,7 +38,7 @@ plugins {
|
|||||||
// ### ALLPROJECTS CONFIGURATION ###
|
// ### ALLPROJECTS CONFIGURATION ###
|
||||||
// ##################################################################
|
// ##################################################################
|
||||||
|
|
||||||
val isWasmEnabled = findProperty("enableWasm")?.toString()?.toBoolean() ?: false
|
val isWasmEnabled: Boolean = findProperty("enableWasm")?.toString()?.toBoolean() ?: false
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
// Zentrale Versionierung — liest version.properties (SemVer)
|
// Zentrale Versionierung — liest version.properties (SemVer)
|
||||||
@@ -47,10 +47,10 @@ val versionProps =
|
|||||||
java.util.Properties().also { props ->
|
java.util.Properties().also { props ->
|
||||||
rootProject.file("version.properties").inputStream().use { props.load(it) }
|
rootProject.file("version.properties").inputStream().use { props.load(it) }
|
||||||
}
|
}
|
||||||
val vMajor = versionProps.getProperty("VERSION_MAJOR", "1")
|
val vMajor: String = versionProps.getProperty("VERSION_MAJOR", "1")
|
||||||
val vMinor = versionProps.getProperty("VERSION_MINOR", "0")
|
val vMinor: String = versionProps.getProperty("VERSION_MINOR", "0")
|
||||||
val vPatch = versionProps.getProperty("VERSION_PATCH", "0")
|
val vPatch: String = versionProps.getProperty("VERSION_PATCH", "0")
|
||||||
val vQualifier = versionProps.getProperty("VERSION_QUALIFIER", "").trim()
|
val vQualifier: String = versionProps.getProperty("VERSION_QUALIFIER", "").trim()
|
||||||
val semVer = if (vQualifier.isBlank()) "$vMajor.$vMinor.$vPatch" else "$vMajor.$vMinor.$vPatch-$vQualifier"
|
val semVer = if (vQualifier.isBlank()) "$vMajor.$vMinor.$vPatch" else "$vMajor.$vMinor.$vPatch-$vQualifier"
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
@@ -113,7 +113,7 @@ subprojects {
|
|||||||
// (A) Source map configuration is handled via `gradle.properties` (global Kotlin/JS settings)
|
// (A) Source map configuration is handled via `gradle.properties` (global Kotlin/JS settings)
|
||||||
// to avoid compiler-flag incompatibilities across toolchains.
|
// 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.
|
// This significantly reduces build times during Desktop development.
|
||||||
// Flag is defined at the beginning of the script.
|
// Flag is defined at the beginning of the script.
|
||||||
|
|
||||||
@@ -176,16 +176,18 @@ subprojects {
|
|||||||
// Applies to all Exec-based tasks (covers Yarn/NPM invocations used by Kotlin JS plugin)
|
// Applies to all Exec-based tasks (covers Yarn/NPM invocations used by Kotlin JS plugin)
|
||||||
tasks.withType<Exec>().configureEach {
|
tasks.withType<Exec>().configureEach {
|
||||||
// Merge existing NODE_OPTIONS with --no-deprecation
|
// Merge existing NODE_OPTIONS with --no-deprecation
|
||||||
val current = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
|
val current: String? = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
|
||||||
val merged = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
|
val merged: String = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
|
||||||
environment("NODE_OPTIONS", merged)
|
environment("NODE_OPTIONS", merged)
|
||||||
// Also set the legacy switch to silence warnings entirely
|
// Also set the legacy switch to silence warnings entirely
|
||||||
environment("NODE_NO_WARNINGS", "1")
|
environment("NODE_NO_WARNINGS", "1")
|
||||||
// Set a Chrome binary path to avoid snap permission issues
|
// 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("CHROME_BIN", "/usr/bin/google-chrome-stable")
|
||||||
environment("CHROMIUM_BIN", "/usr/bin/chromium")
|
environment("CHROMIUM_BIN", "/usr/bin/chromium")
|
||||||
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
|
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------
|
// ------------------------------
|
||||||
// Detekt & Ktlint default setup
|
// Detekt & Ktlint default setup
|
||||||
@@ -276,7 +278,6 @@ tasks.register("checkBundleBudget") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shells.forEach { shell ->
|
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"
|
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
|
// Budgets are keyed by a Gradle path with colons but without leading colon in config for readability
|
||||||
val budgetKeyCandidates =
|
val budgetKeyCandidates =
|
||||||
@@ -371,8 +372,8 @@ tasks.register("staticAnalysis") {
|
|||||||
|
|
||||||
// Apply Dokka (V2) automatically to Kotlin subprojects
|
// Apply Dokka (V2) automatically to Kotlin subprojects
|
||||||
subprojects {
|
subprojects {
|
||||||
plugins.withId("org.jetbrains.kotlin.jvm") { apply(plugin = "org.jetbrains.dokka") }
|
plugins.withId("org.jetbrains.kotlin.jvm") { pluginManager.apply("org.jetbrains.dokka") }
|
||||||
plugins.withId("org.jetbrains.kotlin.multiplatform") { apply(plugin = "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
|
// Aggregate tasks to build multi-module docs in Markdown (GFM) and HTML
|
||||||
@@ -469,14 +470,16 @@ tasks.register("docs") {
|
|||||||
// Apply Node warning suppression on root project Exec tasks as well
|
// 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
|
// Ensures aggregated Kotlin/JS tasks created at root (e.g., kotlinNpmInstall) inherit the env
|
||||||
tasks.withType<Exec>().configureEach {
|
tasks.withType<Exec>().configureEach {
|
||||||
val current = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
|
val current: String? = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS")
|
||||||
val merged = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
|
val merged: String = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation"
|
||||||
environment("NODE_OPTIONS", merged)
|
environment("NODE_OPTIONS", merged)
|
||||||
environment("NODE_NO_WARNINGS", "1")
|
environment("NODE_NO_WARNINGS", "1")
|
||||||
// Set a Chrome binary path to avoid snap permission issues
|
// 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("CHROME_BIN", "/usr/bin/google-chrome-stable")
|
||||||
environment("CHROMIUM_BIN", "/usr/bin/chromium")
|
environment("CHROMIUM_BIN", "/usr/bin/chromium")
|
||||||
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
|
environment("PUPPETEER_EXECUTABLE_PATH", "/usr/bin/chromium")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.wrapper {
|
tasks.wrapper {
|
||||||
|
|||||||
@@ -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
|
package at.mocode.zns.parser
|
||||||
|
|
||||||
import at.mocode.core.domain.model.DatenQuelleE
|
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.model.ReiterLizenzKlasseE
|
||||||
import at.mocode.core.utils.parser.FixedWidthLineReader
|
import at.mocode.core.utils.parser.FixedWidthLineReader
|
||||||
import at.mocode.masterdata.domain.model.Reiter
|
import at.mocode.masterdata.domain.model.Reiter
|
||||||
import at.mocode.masterdata.domain.model.ReiterLizenz
|
|
||||||
import kotlin.uuid.ExperimentalUuidApi
|
import kotlin.uuid.ExperimentalUuidApi
|
||||||
import kotlin.uuid.Uuid
|
import kotlin.uuid.Uuid
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
type: Roadmap
|
type: Roadmap
|
||||||
status: ACTIVE
|
status: ACTIVE
|
||||||
owner: Lead Architect
|
owner: Lead Architect
|
||||||
last_update: 2026-05-06
|
last_update: 2026-06-15
|
||||||
---
|
---
|
||||||
|
|
||||||
# MASTER ROADMAP: Meldestelle
|
# MASTER ROADMAP: Meldestelle
|
||||||
|
|
||||||
🏗️ **[Lead Architect]** | 30. April 2026
|
🏗️ **[Lead Architect]** | 15. Juni 2026
|
||||||
|
|
||||||
**Strategisches Ziel:**
|
**Strategisches Ziel:**
|
||||||
Entwicklung einer ÖTO-konformen, offline-fähigen Turnier-Meldestelle als Compose Desktop App (KMP).
|
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.
|
- 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.
|
- 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.
|
* **Infrastruktur:** ✅ "Zora" (MS-R1, ARM64) ist live. Gitea & Registry laufen.
|
||||||
* **Networking:** ✅ Pangolin Tunnel ersetzt Cloudflare.
|
* **Networking:** ✅ Pangolin Tunnel ersetzt Cloudflare.
|
||||||
* **CI/CD:** ✅ Gitea Actions mit ARM64-Runner (VM 102) aktiv. Docker-Publish Pipeline grün.
|
* **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).
|
* **Code-Basis:** ✅ Backend (Java 25 / Spring Boot / Kotlin), Frontend (KMP/Compose Desktop).
|
||||||
* **Domain-Design:** ✅ 6 Bounded Contexts (SCS-Architektur) definiert. Ubiquitous Language erstellt.
|
* **Domain-Design:** ✅ 6 Bounded Contexts (SCS-Architektur) definiert. Ubiquitous Language erstellt.
|
||||||
* **Domain-Modelle:** ✅ `Reiter`, `DomNennung`, `DomNennungsTransfer`, `Pferd`, `Funktionaer`, `Verein`,
|
* **Domain-Modelle:** ✅ `Reiter`, `Nennung`, `NennungsTransfer`, `Pferd`, `Funktionaer`, `Verein`,
|
||||||
`DomBewerb`, `DomAbteilung`, `DomStartliste`, `DomVeranstaltung`, `DomTurnier`, `DomAusschreibung` implementiert.
|
`Bewerb`, `Abteilung`, `DomStartliste`, `Veranstaltung`, `Turnier`, `Ausschreibung` implementiert.
|
||||||
Enums ÖTO-konform.
|
Enums ÖTO-konform.
|
||||||
* **Dokumentation:** ✅ Konsolidiert. ÖTO-Regelwerk-Referenzen (Abteilungs-Schwellenwerte) dokumentiert.
|
* **Dokumentation:** 🧹 Sanierung abgeschlossen (5-Säulen-Struktur). Reality-Reset durchgeführt.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -155,15 +155,15 @@ Code-Stand.*
|
|||||||
|
|
||||||
| Dokument | Pfad |
|
| Dokument | Pfad |
|
||||||
|-------------------------------|----------------------------------------------------------------------------------------------|
|
|-------------------------------|----------------------------------------------------------------------------------------------|
|
||||||
| Ubiquitous Language | `docs/03_Domain/01_Glossary/Ubiquitous_Language.md` |
|
| Ubiquitous Language | `docs/02_Domain/01_Glossary/Ubiquitous_Language.md` |
|
||||||
| Abteilungs-Schwellenwerte | `docs/03_Domain/02_Reference/OETO_Regelwerk/Abteilungs-Trennungs-Schwellenwerte.md` |
|
| Abteilungs-Schwellenwerte | `docs/02_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` |
|
| Warn-Logik-Spezifikation | `docs/02_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` |
|
| Session Log (DDD) | `docs/05_Governance/Journal/_archive/2026-03-24_Session_Log_DDD_Ubiquitous_Language.md` |
|
||||||
| Infrastruktur | `docs/07_Infrastructure/Zora_System_Architektur.md` |
|
| Infrastruktur | `docs/04_Operations/Infrastructure/Zora_System_Architektur.md` |
|
||||||
| Deployment Guide | `docs/07_Infrastructure/Guides/Setup_Git_Deployment_Zora.md` |
|
| Deployment Guide | `docs/04_Operations/Infrastructure/Guides/Setup_Git_Deployment_Zora.md` |
|
||||||
| Backup Guide | `docs/07_Infrastructure/Guides/Setup_Backup_Zora.md` |
|
| Backup Guide | `docs/04_Operations/Infrastructure/Guides/Setup_Backup_Zora.md` |
|
||||||
| CI/CD | `.gitea/workflows/docker-publish.yaml` |
|
| 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-Verzeichnis | `docs/01_Architecture/adr/` |
|
||||||
| ADR-0025: Plan-USB | `docs/01_Architecture/adr/0025-plan-usb-offline-integritaet.md` |
|
| 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` |
|
| ADR-0026: Lizenzierung | `docs/01_Architecture/adr/0026-offline-lizenzierung-pay-per-event.md` |
|
||||||
|
|||||||
+6
-5
@@ -2,11 +2,12 @@
|
|||||||
type: Reference
|
type: Reference
|
||||||
status: ACTIVE
|
status: ACTIVE
|
||||||
owner: Lead Architect & ÖTO/FEI Rulebook Expert
|
owner: Lead Architect & ÖTO/FEI Rulebook Expert
|
||||||
last_update: 2026-04-05
|
last_update: 2026-06-15
|
||||||
sources:
|
sources:
|
||||||
- ÖTO 2026, Abschnitt A I, § 2 & § 3 & § 4
|
- ÖTO 2026, Abschnitt A I, § 2 & § 3 & § 4
|
||||||
- Domain Workshop 2026-03-17
|
- Domain Workshop 2026-03-17
|
||||||
- Session 2026-03-24 (Architektur-Diskussion)
|
- Session 2026-03-24 (Architektur-Diskussion)
|
||||||
|
- Sanierung 2026-06-15 (Reality-Reset)
|
||||||
---
|
---
|
||||||
|
|
||||||
# Ubiquitous Language – Offizielle Domänen-Terminologie
|
# 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 |
|
| **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). | – |
|
| **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 |
|
| **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 |
|
| **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 |
|
| **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` |
|
| Veranstaltung, Turnier, Ausschreibung, Veranstalter | `event-management-context` |
|
||||||
| Bewerb, Abteilung, Startliste, Ergebnis, Richtverfahren | `competition-context` |
|
| Bewerb, Abteilung, Startliste, Ergebnis, Richtverfahren | `competition-context` |
|
||||||
| Nennung, Nennungs-Transfer, Startwunsch, ZNS-Import | `registration-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` |
|
| Nenngeld, Startgeld, Konto, Transaktion, Sportförderbeitrag | `billing-context` |
|
||||||
| Cup, Serie, Meisterschaft, Reglement, Endklassement | `series-context` *(Phase 2+)* |
|
| Cup, Serie, Meisterschaft, Reglement, Endklassement | `series-context` *(Phase 2+)* |
|
||||||
| Login, Rolle, Berechtigung | `identity-context` |
|
| 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.
|
- 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.
|
- Die **Paar-Bindung** (Punkte an Reiter+Pferd vs. nur Reiter) ist eine kritische Designentscheidung pro Reglement.
|
||||||
- Referenz-Dokument: [
|
- 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*
|
*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
Reference in New Issue
Block a user