458 lines
12 KiB
Markdown
458 lines
12 KiB
Markdown
# 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<SparteE> = 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).
|