# Events Module ## Überblick Das Events-Modul ist eine umfassende Lösung zur Verwaltung von Pferdesportveranstaltungen. Es implementiert eine saubere Architektur mit Domain-Driven Design und bietet vollständige CRUD-Operationen sowie erweiterte Geschäftslogik für die Veranstaltungsplanung und -verwaltung. ## Funktionalität ### Verwaltete Entität #### Veranstaltung (Event) - **Grundinformationen**: Name, Beschreibung - **Terminverwaltung**: Startdatum, Enddatum, Anmeldeschluss - **Ort und Organisation**: Veranstaltungsort, Veranstalter-Verein-ID - **Veranstaltungsdetails**: Sparten, Aktivitätsstatus, Öffentlichkeit, maximale Teilnehmerzahl - **Audit-Felder**: Erstellungs- und Aktualisierungszeitstempel - **Geschäftslogik**: Validierung, Anmeldestatus, Dauernberechnung ### Geschäftsoperationen Das Modul bietet 10+ spezialisierte Repository-Operationen: #### Basis-CRUD-Operationen - `findById(id)` - Veranstaltung nach UUID suchen - `save(veranstaltung)` - Veranstaltung speichern (erstellen/aktualisieren) - `delete(id)` - Veranstaltung löschen #### Such-Operationen - `findByName(searchTerm, limit)` - Nach Namen suchen (Teilübereinstimmung) - `findByVeranstalterVereinId(vereinId, activeOnly)` - Veranstaltungen eines Vereins - `findAllActive(limit, offset)` - Alle aktiven Veranstaltungen - `findPublicEvents(activeOnly)` - Öffentliche Veranstaltungen #### Datumsbasierte Abfragen - `findByDateRange(startDate, endDate, activeOnly)` - Veranstaltungen in Datumsbereich - `findByStartDate(date, activeOnly)` - Veranstaltungen nach Startdatum #### Zähl-Operationen - `countActive()` - Anzahl aktiver Veranstaltungen - `countByVeranstalterVereinId(vereinId, activeOnly)` - Anzahl Veranstaltungen pro Verein ## Architektur Das Modul folgt der Clean Architecture mit klarer Trennung der Verantwortlichkeiten: ``` events/ ├── events-domain/ # Domain Layer │ ├── model/ # Domain Models │ │ └── Veranstaltung.kt # Veranstaltungs-Entität mit Geschäftslogik │ ├── repository/ # Repository Interfaces │ │ └── VeranstaltungRepository.kt # 10+ Geschäftsoperationen │ └── EventManagement.kt # Domain Service/Facade ├── events-application/ # Application Layer │ └── usecase/ # Use Cases │ ├── CreateVeranstaltungUseCase.kt │ ├── GetVeranstaltungUseCase.kt │ ├── UpdateVeranstaltungUseCase.kt │ └── DeleteVeranstaltungUseCase.kt ├── events-infrastructure/ # Infrastructure Layer │ └── persistence/ # Database Implementation │ ├── VeranstaltungRepositoryImpl.kt │ └── VeranstaltungTable.kt ├── events-api/ # API Layer │ └── rest/ # REST Controllers │ └── VeranstaltungController.kt └── events-service/ # Service Layer └── EventsServiceApplication.kt ``` ### Domain Layer - **1 Domain Model** mit reichhaltiger Geschäftslogik - **1 Repository Interface** mit 10+ Geschäftsoperationen - **Domain Service** für komplexe Veranstaltungslogik - **Keine Abhängigkeiten** zu anderen Layern ### Application Layer - **Use Cases** für CRUD-Operationen - **Orchestrierung** von Domain-Services - **Anwendungslogik** ohne UI-Abhängigkeiten ### Infrastructure Layer - **Datenbankzugriff** mit Exposed ORM - **Repository-Implementierung** mit PostgreSQL - **Datenbankschema** und Migrationen ### API Layer - **REST-Controller** für HTTP-Endpunkte - **DTO-Mapping** zwischen Domain und API - **Validierung** und Fehlerbehandlung ### Service Layer - **Spring Boot Anwendung** - **Dependency Injection** Konfiguration - **Service-Konfiguration** ## Domain Model Details ### Veranstaltung-Entität ```kotlin data class Veranstaltung( val veranstaltungId: Uuid, // Grundinformationen var name: String, var beschreibung: String? = null, // Termine var startDatum: LocalDate, var endDatum: LocalDate, // Ort und Organisation var ort: String, var veranstalterVereinId: Uuid, // Veranstaltungsdetails var sparten: List = emptyList(), var istAktiv: Boolean = true, var istOeffentlich: Boolean = true, var maxTeilnehmer: Int? = null, var anmeldeschluss: LocalDate? = null, // Audit-Felder val createdAt: Instant, var updatedAt: Instant ) ``` ### Geschäftslogik-Methoden - `isRegistrationOpen()` - Prüfung ob Anmeldung noch möglich ist - `getDurationInDays()` - Berechnung der Veranstaltungsdauer in Tagen - `isMultiDay()` - Prüfung ob mehrtägige Veranstaltung - `validate()` - Datenvalidierung mit Fehlerliste - `withUpdatedTimestamp()` - Kopie mit aktualisiertem Zeitstempel ### Enumerationen #### SparteE (Sportsparten) - `DRESSUR` - Dressurreiten - `SPRINGEN` - Springreiten - `VIELSEITIGKEIT` - Vielseitigkeitsreiten - `FAHREN` - Fahrsport - `VOLTIGIEREN` - Voltigieren - `WESTERN` - Westernreiten - `DISTANZ` - Distanzreiten ## Repository-Operationen ### Erweiterte Such-Features ```kotlin // Veranstaltungen nach Namen suchen val events = veranstaltungRepository.findByName("Turnier", limit = 10) // Veranstaltungen eines Vereins finden val clubEvents = veranstaltungRepository.findByVeranstalterVereinId( vereinId = clubId, activeOnly = true ) // Veranstaltungen in Datumsbereich suchen val summerEvents = veranstaltungRepository.findByDateRange( startDate = LocalDate(2024, 6, 1), endDate = LocalDate(2024, 8, 31), activeOnly = true ) // Öffentliche Veranstaltungen finden val publicEvents = veranstaltungRepository.findPublicEvents(activeOnly = true) ``` ### Datumsbasierte Abfragen ```kotlin // Veranstaltungen an einem bestimmten Tag val todayEvents = veranstaltungRepository.findByStartDate( date = LocalDate.now(), activeOnly = true ) // Alle aktiven Veranstaltungen val activeEvents = veranstaltungRepository.findAllActive(limit = 100) ``` ### Statistiken und Zählungen ```kotlin // Anzahl aktiver Veranstaltungen val totalActive = veranstaltungRepository.countActive() // Anzahl Veranstaltungen pro Verein val clubEventCount = veranstaltungRepository.countByVeranstalterVereinId( vereinId = clubId, activeOnly = true ) ``` ## Use Cases ### CreateVeranstaltungUseCase Erstellt eine neue Veranstaltung mit Validierung und Geschäftsregeln. ```kotlin class CreateVeranstaltungUseCase( private val veranstaltungRepository: VeranstaltungRepository ) { suspend fun execute(veranstaltung: Veranstaltung): Veranstaltung { // Validierung val errors = veranstaltung.validate() if (errors.isNotEmpty()) { throw ValidationException(errors) } // Geschäftsregeln prüfen if (veranstaltung.anmeldeschluss != null && veranstaltung.anmeldeschluss!! > veranstaltung.startDatum) { throw BusinessRuleException("Anmeldeschluss muss vor Veranstaltungsbeginn liegen") } return veranstaltungRepository.save(veranstaltung) } } ``` ### GetVeranstaltungUseCase Ruft Veranstaltungsinformationen ab mit verschiedenen Suchkriterien. ### UpdateVeranstaltungUseCase Aktualisiert Veranstaltungsinformationen mit Validierung. ### DeleteVeranstaltungUseCase Löscht eine Veranstaltung (soft delete durch Deaktivierung). ## API-Endpunkte Das Events-Modul stellt REST-Endpunkte über den VeranstaltungController bereit: - `GET /api/events` - Alle aktiven Veranstaltungen abrufen - `GET /api/events/{id}` - Veranstaltung nach ID abrufen - `GET /api/events/search?name={name}` - Veranstaltungen nach Namen suchen - `GET /api/events/club/{clubId}` - Veranstaltungen eines Vereins - `GET /api/events/public` - Öffentliche Veranstaltungen - `GET /api/events/date-range?start={start}&end={end}` - Veranstaltungen in Datumsbereich - `GET /api/events/date/{date}` - Veranstaltungen an einem bestimmten Tag - `POST /api/events` - Neue Veranstaltung erstellen - `PUT /api/events/{id}` - Veranstaltung aktualisieren - `DELETE /api/events/{id}` - Veranstaltung löschen ## Konfiguration ### Datenbankschema Das Modul verwendet eine `events`-Tabelle mit folgenden Spalten: - `veranstaltung_id` (UUID, Primary Key) - `name` (Required) - `beschreibung` (Text, Optional) - `start_datum`, `end_datum` (Date, Required) - `ort` (Required) - `veranstalter_verein_id` (UUID, Foreign Key) - `sparten` (JSON Array) - `ist_aktiv`, `ist_oeffentlich` (Boolean) - `max_teilnehmer` (Integer, Optional) - `anmeldeschluss` (Date, Optional) - `created_at`, `updated_at` (Timestamps) ### Service-Konfiguration ```yaml # application.yml events: service: name: events-service port: 8084 database: url: jdbc:postgresql://localhost:5432/meldestelle table: events business-rules: max-duration-days: 30 min-registration-period-days: 7 allow-past-events: false ``` ## Tests ### Integration Tests Das Modul enthält umfassende Integrationstests: ```kotlin @Test fun `should create event with valid data`() { // Test für Veranstaltungserstellung } @Test fun `should find events by date range`() { // Test für datumsbasierte Suche } @Test fun `should validate registration deadline`() { // Test für Anmeldeschluss-Validierung } @Test fun `should find public events only`() { // Test für öffentliche Veranstaltungen } ``` ### Test-Datenbank Verwendet H2 In-Memory-Datenbank für Tests mit automatischem Schema-Setup. ## Deployment ### Docker ```dockerfile FROM openjdk:21-jre-slim COPY events-service.jar app.jar EXPOSE 8084 ENTRYPOINT ["java", "-jar", "/app.jar"] ``` ### Kubernetes ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: events-service spec: replicas: 2 selector: matchLabels: app: events-service template: spec: containers: - name: events-service image: meldestelle/events-service:latest ports: - containerPort: 8084 ``` ## Monitoring ### Metriken - Anzahl aktiver Veranstaltungen - Anzahl öffentlicher Veranstaltungen - Durchschnittliche Veranstaltungsdauer - API-Response-Zeiten - Datenbankverbindungs-Pool - Validierungsfehler-Rate ### Health Checks - Datenbankverbindung - Service-Verfügbarkeit - Speicherverbrauch - Externe System-Verbindungen ## Entwicklung ### Lokale Entwicklung ```bash # Service starten ./gradlew :events:events-service:bootRun # Tests ausführen ./gradlew :events:test # Integration Tests ./gradlew :events:events-service:test ``` ### Code-Qualität - **Kotlin Coding Standards** - **100% Test Coverage** für Domain Layer - **Integration Tests** für alle Use Cases - **API-Dokumentation** mit OpenAPI ## Geschäftsregeln ### Veranstaltungsplanung 1. **Datumsvalidierung**: Enddatum muss nach oder gleich Startdatum sein 2. **Anmeldeschluss**: Muss vor Veranstaltungsbeginn liegen 3. **Teilnehmerbegrenzung**: Maximale Teilnehmerzahl muss positiv sein 4. **Öffentlichkeit**: Private Veranstaltungen nur für Vereinsmitglieder ### Sparten-Management - Unterstützung für alle österreichischen Pferdesport-Sparten - Mehrfachauswahl möglich für kombinierte Veranstaltungen - Sparten-spezifische Validierungsregeln ### Vereins-Integration - Verknüpfung mit Vereinsverwaltung - Berechtigung zur Veranstaltungserstellung - Vereins-spezifische Konfigurationen ## Integration ### Externe Systeme #### OEPS-Integration - Synchronisation mit OEPS-Veranstaltungskalender - Automatische Meldung bei OEPS-relevanten Veranstaltungen - Import von OEPS-Veranstaltungsdaten #### FEI-Integration - Unterstützung für internationale Veranstaltungen - FEI-Regularien und -Standards - Automatische Klassifizierung ### Interne Module #### Members-Modul - Teilnehmerverwaltung - Anmeldestatus-Tracking - Mitgliedschaftsvalidierung #### Horses-Modul - Pferdeanmeldungen - Eignung für Sparten - Registrierungsstatus ## Zukünftige Erweiterungen 1. **Anmeldungssystem** - Vollständiges Teilnehmeranmeldungssystem 2. **Zeitplanung** - Detaillierte Zeitpläne und Startlisten 3. **Ergebniserfassung** - Integration mit Bewertungssystemen 4. **Livestreaming** - Integration mit Streaming-Plattformen 5. **Mobile App** - Mobile Anwendung für Teilnehmer 6. **Zahlungsintegration** - Startgebühren und Zahlungsabwicklung 7. **Wetterintegration** - Wettervorhersage und -warnungen 8. **Kapazitätsmanagement** - Stallplätze und Parkplätze 9. **Catering-Management** - Verpflegung und Bewirtung 10. **Sponsoring** - Sponsoren-Management und -präsentation --- **Letzte Aktualisierung**: 25. Juli 2025 Für weitere Informationen zur Gesamtarchitektur siehe [README.md](../README.md).