534 lines
16 KiB
Markdown
534 lines
16 KiB
Markdown
# Horses Module
|
|
|
|
## Überblick
|
|
|
|
Das Horses-Modul ist eine umfassende Lösung zur Verwaltung von Pferden für Pferdesportorganisationen. Es implementiert eine saubere Architektur mit Domain-Driven Design und bietet vollständige CRUD-Operationen sowie erweiterte Geschäftslogik für die Pferderegistrierung und -verwaltung.
|
|
|
|
## Funktionalität
|
|
|
|
### Verwaltete Entität
|
|
|
|
#### Pferd (DomPferd)
|
|
- **Grundinformationen**: Name, Geschlecht, Geburtsdatum, Rasse, Farbe
|
|
- **Besitz und Verantwortung**: Besitzer-ID, verantwortliche Person
|
|
- **Zuchtinformationen**: Züchtername, Zuchtbuchnummer
|
|
- **Identifikationsnummern**: Lebensnummer, Chipnummer, Passnummer, OEPS-Nummer, FEI-Nummer
|
|
- **Abstammung**: Vater, Mutter, Muttervater
|
|
- **Körperliche Merkmale**: Stockmaß (Höhe in cm)
|
|
- **Status und Verwaltung**: Aktivitätsstatus, Bemerkungen, Datenquelle
|
|
- **Audit-Felder**: Erstellungs- und Aktualisierungszeitstempel
|
|
|
|
### Geschäftsoperationen
|
|
|
|
Das Modul bietet 25+ spezialisierte Repository-Operationen:
|
|
|
|
#### Basis-CRUD-Operationen
|
|
- `findById(id)` - Pferd nach UUID suchen
|
|
- `save(horse)` - Pferd speichern (erstellen/aktualisieren)
|
|
- `delete(id)` - Pferd löschen
|
|
|
|
#### Such-Operationen nach Identifikationsnummern
|
|
- `findByLebensnummer(lebensnummer)` - Nach Lebensnummer suchen
|
|
- `findByChipNummer(chipNummer)` - Nach Chipnummer suchen
|
|
- `findByPassNummer(passNummer)` - Nach Passnummer suchen
|
|
- `findByOepsNummer(oepsNummer)` - Nach OEPS-Nummer suchen
|
|
- `findByFeiNummer(feiNummer)` - Nach FEI-Nummer suchen
|
|
|
|
#### Such-Operationen nach Eigenschaften
|
|
- `findByName(searchTerm, limit)` - Nach Namen suchen (Teilübereinstimmung)
|
|
- `findByOwnerId(ownerId, activeOnly)` - Pferde eines Besitzers
|
|
- `findByResponsiblePersonId(personId, activeOnly)` - Pferde einer verantwortlichen Person
|
|
- `findByGeschlecht(geschlecht, activeOnly, limit)` - Nach Geschlecht filtern
|
|
- `findByRasse(rasse, activeOnly, limit)` - Nach Rasse filtern
|
|
|
|
#### Datumsbasierte Abfragen
|
|
- `findByBirthYear(birthYear, activeOnly)` - Pferde nach Geburtsjahr
|
|
- `findByBirthYearRange(fromYear, toYear, activeOnly)` - Pferde nach Geburtsjahr-Bereich
|
|
|
|
#### Registrierungs-Abfragen
|
|
- `findAllActive(limit)` - Alle aktiven Pferde
|
|
- `findOepsRegistered(activeOnly)` - OEPS-registrierte Pferde
|
|
- `findFeiRegistered(activeOnly)` - FEI-registrierte Pferde
|
|
|
|
#### Validierungs-Operationen
|
|
- `existsByLebensnummer(lebensnummer)` - Prüfung auf doppelte Lebensnummer
|
|
- `existsByChipNummer(chipNummer)` - Prüfung auf doppelte Chipnummer
|
|
- `existsByPassNummer(passNummer)` - Prüfung auf doppelte Passnummer
|
|
- `existsByOepsNummer(oepsNummer)` - Prüfung auf doppelte OEPS-Nummer
|
|
- `existsByFeiNummer(feiNummer)` - Prüfung auf doppelte FEI-Nummer
|
|
|
|
#### Zähl-Operationen
|
|
- `countActive()` - Anzahl aktiver Pferde
|
|
- `countByOwnerId(ownerId, activeOnly)` - Anzahl Pferde pro Besitzer
|
|
- `countOepsRegistered(activeOnly)` - Anzahl OEPS-registrierter Pferde ✨ **NEU**
|
|
- `countFeiRegistered(activeOnly)` - Anzahl FEI-registrierter Pferde ✨ **NEU**
|
|
|
|
## Architektur
|
|
|
|
Das Modul folgt der Clean Architecture mit klarer Trennung der Verantwortlichkeiten:
|
|
|
|
```
|
|
horses/
|
|
├── horses-domain/ # Domain Layer
|
|
│ ├── model/ # Domain Models
|
|
│ │ └── DomPferd.kt # Pferd-Entität mit Geschäftslogik
|
|
│ └── repository/ # Repository Interfaces
|
|
│ └── HorseRepository.kt # 25+ Geschäftsoperationen
|
|
├── horses-application/ # Application Layer
|
|
│ └── usecase/ # Use Cases
|
|
│ ├── CreateHorseUseCase.kt
|
|
│ ├── GetHorseUseCase.kt
|
|
│ ├── UpdateHorseUseCase.kt
|
|
│ └── DeleteHorseUseCase.kt
|
|
├── horses-infrastructure/ # Infrastructure Layer
|
|
│ └── persistence/ # Database Implementation
|
|
│ ├── HorseRepositoryImpl.kt
|
|
│ └── HorseTable.kt
|
|
├── horses-api/ # API Layer
|
|
│ └── rest/ # REST Controllers
|
|
│ └── HorseController.kt
|
|
└── horses-service/ # Service Layer
|
|
├── HorsesServiceApplication.kt
|
|
└── test/ # Integration Tests
|
|
└── HorseServiceIntegrationTest.kt
|
|
```
|
|
|
|
### Domain Layer
|
|
- **1 Domain Model** mit reichhaltiger Geschäftslogik
|
|
- **1 Repository Interface** mit 25+ Geschäftsoperationen
|
|
- **Geschäftsregeln** für Pferderegistrierung und -validierung
|
|
- **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
|
|
|
|
## 🚀 Aktuelle Optimierungen (2025-07-25)
|
|
|
|
Das Horses-Modul wurde kürzlich analysiert, vervollständigt und optimiert. Folgende Verbesserungen wurden implementiert:
|
|
|
|
### ✨ Neue Funktionalitäten
|
|
|
|
#### Erweiterte Such-Endpunkte
|
|
Neue REST-Endpunkte für vollständige Identifikationsnummer-Suche:
|
|
- `GET /api/horses/search/passport/{nummer}` - Suche nach Passnummer
|
|
- `GET /api/horses/search/oeps/{nummer}` - Suche nach OEPS-Nummer
|
|
- `GET /api/horses/search/fei/{nummer}` - Suche nach FEI-Nummer
|
|
|
|
#### Optimierte Statistik-Operationen
|
|
- Neue effiziente Zähl-Methoden für OEPS und FEI registrierte Pferde
|
|
- Performance-Verbesserung von O(n) auf O(1) Komplexität für Statistiken
|
|
- Datenbankoptimierte COUNT-Abfragen statt Laden aller Datensätze
|
|
|
|
### ⚡ Performance-Optimierungen
|
|
|
|
#### Datenbankeffizienz
|
|
- **Vorher**: Statistik-Endpunkt lud alle Pferde und verwendete `.size`
|
|
- **Nachher**: Effiziente COUNT-Abfragen direkt in der Datenbank
|
|
- **Auswirkung**: Drastische Reduzierung der Speichernutzung und Antwortzeiten
|
|
|
|
#### Architektur-Konsistenz
|
|
- Alle API-Endpunkte verwenden jetzt konsistent die Use-Case-Schicht
|
|
- Eliminierung direkter Repository-Aufrufe in der API-Schicht
|
|
- Saubere Trennung der Architektur-Schichten
|
|
|
|
### 🏗️ Architektur-Verbesserungen
|
|
|
|
#### Clean Architecture Compliance
|
|
- **Konsistente Schichtung**: Alle Endpunkte folgen dem Use-Case-Pattern
|
|
- **Fehlerbehandlung**: Einheitliche Fehlerantworten über alle Endpunkte
|
|
- **Validierung**: Umfassende Eingabevalidierung mit geteilten Utilities
|
|
- **HTTP-Standards**: Korrekte Status-Codes und REST-Konventionen
|
|
|
|
#### Code-Qualität
|
|
- Verbesserte Lesbarkeit und Wartbarkeit
|
|
- Konsistente Namenskonventionen
|
|
- Umfassende Dokumentation aller neuen Funktionen
|
|
|
|
### 📊 Qualitätsmetriken
|
|
|
|
#### Vor der Optimierung
|
|
- ❌ Fehlende Such-Endpunkte für 3 Identifikationstypen
|
|
- ❌ Ineffiziente Statistik-Abfragen (O(n) Komplexität)
|
|
- ❌ Inkonsistente Architektur (einige Endpunkte umgingen Use Cases)
|
|
- ❌ Performance-Probleme bei großen Datensätzen
|
|
|
|
#### Nach der Optimierung
|
|
- ✅ Vollständige API-Abdeckung für alle Identifikationstypen
|
|
- ✅ Effiziente Statistik-Abfragen (O(1) Komplexität)
|
|
- ✅ Konsistente Clean Architecture durchgehend
|
|
- ✅ Optimierte Performance für alle Operationen
|
|
|
|
### 🔮 Zukünftige Empfehlungen
|
|
|
|
#### Caching-Schicht
|
|
- Implementierung einer Caching-Schicht für häufig abgerufene Daten
|
|
- Individuelle Pferde-Lookups mit angemessener TTL
|
|
- Statistiken und Zählungen mit Cache-Invalidierung
|
|
|
|
#### Async-Operationen
|
|
- Asynchrone Verarbeitung für Batch-Operationen
|
|
- Komplexe Such-Abfragen mit Async-Pattern
|
|
- Statistik-Berechnungen im Hintergrund
|
|
|
|
#### Monitoring und Logging
|
|
- Umfassendes Monitoring für API-Antwortzeiten
|
|
- Datenbank-Query-Performance-Überwachung
|
|
- Fehlerrate-Tracking und -Analyse
|
|
- **DTO-Mapping** zwischen Domain und API
|
|
- **Validierung** und Fehlerbehandlung
|
|
|
|
### Service Layer
|
|
- **Spring Boot Anwendung**
|
|
- **Dependency Injection** Konfiguration
|
|
- **Integrationstests**
|
|
|
|
## Domain Model Details
|
|
|
|
### DomPferd-Entität
|
|
|
|
```kotlin
|
|
data class DomPferd(
|
|
val pferdId: Uuid,
|
|
|
|
// Grundinformationen
|
|
var pferdeName: String,
|
|
var geschlecht: PferdeGeschlechtE,
|
|
var geburtsdatum: LocalDate? = null,
|
|
var rasse: String? = null,
|
|
var farbe: String? = null,
|
|
|
|
// Besitz und Verantwortung
|
|
var besitzerId: Uuid? = null,
|
|
var verantwortlichePersonId: Uuid? = null,
|
|
|
|
// Zuchtinformationen
|
|
var zuechterName: String? = null,
|
|
var zuchtbuchNummer: String? = null,
|
|
|
|
// Identifikationsnummern
|
|
var lebensnummer: String? = null,
|
|
var chipNummer: String? = null,
|
|
var passNummer: String? = null,
|
|
var oepsNummer: String? = null,
|
|
var feiNummer: String? = null,
|
|
|
|
// Abstammung
|
|
var vaterName: String? = null,
|
|
var mutterName: String? = null,
|
|
var mutterVaterName: String? = null,
|
|
|
|
// Körperliche Merkmale
|
|
var stockmass: Int? = null, // Höhe in cm
|
|
|
|
// Status und Verwaltung
|
|
var istAktiv: Boolean = true,
|
|
var bemerkungen: String? = null,
|
|
var datenQuelle: DatenQuelleE = DatenQuelleE.MANUELL,
|
|
|
|
// Audit-Felder
|
|
val createdAt: Instant,
|
|
var updatedAt: Instant
|
|
)
|
|
```
|
|
|
|
### Geschäftslogik-Methoden
|
|
|
|
- `getDisplayName()` - Anzeigename mit Geburtsjahr
|
|
- `hasCompleteIdentification()` - Prüfung auf vollständige Identifikation
|
|
- `isOepsRegistered()` - OEPS-Registrierungsstatus
|
|
- `isFeiRegistered()` - FEI-Registrierungsstatus
|
|
- `getAge()` - Altersberechnung in Jahren
|
|
- `validateForRegistration()` - Validierung für Registrierung
|
|
- `withUpdatedTimestamp()` - Kopie mit aktualisiertem Zeitstempel
|
|
|
|
### Enumerationen
|
|
|
|
#### PferdeGeschlechtE
|
|
- `HENGST` - Hengst (männlich, nicht kastriert)
|
|
- `STUTE` - Stute (weiblich)
|
|
- `WALLACH` - Wallach (männlich, kastriert)
|
|
|
|
#### DatenQuelleE
|
|
- `MANUELL` - Manuelle Eingabe
|
|
- `IMPORT` - Datenimport
|
|
- `SYNCHRONISATION` - Synchronisation mit externen Systemen
|
|
|
|
## Repository-Operationen
|
|
|
|
### Erweiterte Such-Features
|
|
|
|
```kotlin
|
|
// Pferde nach Identifikationsnummer suchen
|
|
val horse = horseRepository.findByLebensnummer("AT123456789")
|
|
val chipHorse = horseRepository.findByChipNummer("982000123456789")
|
|
|
|
// Pferde eines Besitzers finden
|
|
val ownerHorses = horseRepository.findByOwnerId(ownerId, activeOnly = true)
|
|
|
|
// Pferde nach Eigenschaften filtern
|
|
val stallions = horseRepository.findByGeschlecht(PferdeGeschlechtE.HENGST)
|
|
val warmbloods = horseRepository.findByRasse("Warmblut", activeOnly = true)
|
|
|
|
// Pferde nach Geburtsjahr suchen
|
|
val youngHorses = horseRepository.findByBirthYearRange(2020, 2024)
|
|
```
|
|
|
|
### Registrierungs-Abfragen
|
|
|
|
```kotlin
|
|
// OEPS-registrierte Pferde finden
|
|
val oepsHorses = horseRepository.findOepsRegistered(activeOnly = true)
|
|
|
|
// FEI-registrierte Pferde finden
|
|
val feiHorses = horseRepository.findFeiRegistered(activeOnly = true)
|
|
|
|
// Alle aktiven Pferde
|
|
val activeHorses = horseRepository.findAllActive(limit = 1000)
|
|
```
|
|
|
|
### Validierung und Duplikatsprüfung
|
|
|
|
```kotlin
|
|
// Prüfung auf doppelte Identifikationsnummern
|
|
val lebensnummerExists = horseRepository.existsByLebensnummer("AT123456789")
|
|
val chipExists = horseRepository.existsByChipNummer("982000123456789")
|
|
val oepsExists = horseRepository.existsByOepsNummer("AUT12345")
|
|
```
|
|
|
|
## Use Cases
|
|
|
|
### CreateHorseUseCase
|
|
|
|
Erstellt ein neues Pferd mit Validierung und Duplikatsprüfung.
|
|
|
|
```kotlin
|
|
class CreateHorseUseCase(
|
|
private val horseRepository: HorseRepository
|
|
) {
|
|
suspend fun execute(horse: DomPferd): DomPferd {
|
|
// Validierung
|
|
val errors = horse.validateForRegistration()
|
|
if (errors.isNotEmpty()) {
|
|
throw ValidationException(errors)
|
|
}
|
|
|
|
// Duplikatsprüfung
|
|
horse.lebensnummer?.let { nummer ->
|
|
if (horseRepository.existsByLebensnummer(nummer)) {
|
|
throw DuplicateException("Lebensnummer bereits vorhanden")
|
|
}
|
|
}
|
|
|
|
return horseRepository.save(horse)
|
|
}
|
|
}
|
|
```
|
|
|
|
### GetHorseUseCase
|
|
|
|
Ruft Pferdeinformationen ab mit verschiedenen Suchkriterien.
|
|
|
|
### UpdateHorseUseCase
|
|
|
|
Aktualisiert Pferdeinformationen mit Validierung.
|
|
|
|
### DeleteHorseUseCase
|
|
|
|
Löscht ein Pferd (soft delete durch Deaktivierung).
|
|
|
|
## API-Endpunkte
|
|
|
|
Das Horses-Modul stellt REST-Endpunkte über den HorseController bereit:
|
|
|
|
- `GET /api/horses` - Alle aktiven Pferde abrufen
|
|
- `GET /api/horses/{id}` - Pferd nach ID abrufen
|
|
- `GET /api/horses/search?name={name}` - Pferde nach Namen suchen
|
|
- `GET /api/horses/owner/{ownerId}` - Pferde eines Besitzers
|
|
- `GET /api/horses/identification/{number}` - Pferd nach Identifikationsnummer
|
|
- `GET /api/horses/oeps-registered` - OEPS-registrierte Pferde
|
|
- `GET /api/horses/fei-registered` - FEI-registrierte Pferde
|
|
- `POST /api/horses` - Neues Pferd erstellen
|
|
- `PUT /api/horses/{id}` - Pferd aktualisieren
|
|
- `DELETE /api/horses/{id}` - Pferd löschen
|
|
|
|
## Konfiguration
|
|
|
|
### Datenbankschema
|
|
|
|
Das Modul verwendet eine `horses`-Tabelle mit folgenden Spalten:
|
|
- `pferd_id` (UUID, Primary Key)
|
|
- `pferde_name` (Required)
|
|
- `geschlecht` (Enum: HENGST, STUTE, WALLACH)
|
|
- `geburtsdatum`, `rasse`, `farbe` (Optional)
|
|
- `besitzer_id`, `verantwortliche_person_id` (UUID, Foreign Keys)
|
|
- `zuechter_name`, `zuchtbuch_nummer` (Optional)
|
|
- `lebensnummer`, `chip_nummer`, `pass_nummer` (Unique, Optional)
|
|
- `oeps_nummer`, `fei_nummer` (Unique, Optional)
|
|
- `vater_name`, `mutter_name`, `mutter_vater_name` (Optional)
|
|
- `stockmass` (Integer, Optional)
|
|
- `ist_aktiv` (Boolean)
|
|
- `bemerkungen` (Text, Optional)
|
|
- `daten_quelle` (Enum)
|
|
- `created_at`, `updated_at` (Timestamps)
|
|
|
|
### Service-Konfiguration
|
|
|
|
```yaml
|
|
# application.yml
|
|
horses:
|
|
service:
|
|
name: horses-service
|
|
port: 8083
|
|
database:
|
|
url: jdbc:postgresql://localhost:5432/meldestelle
|
|
table: horses
|
|
validation:
|
|
require-identification: true
|
|
allow-duplicate-names: false
|
|
```
|
|
|
|
## Tests
|
|
|
|
### Integration Tests
|
|
|
|
Das Modul enthält umfassende Integrationstests:
|
|
|
|
```kotlin
|
|
@Test
|
|
fun `should create horse with valid data`() {
|
|
// Test für Pferdeerstellung
|
|
}
|
|
|
|
@Test
|
|
fun `should find horses by owner`() {
|
|
// Test für Besitzer-basierte Suche
|
|
}
|
|
|
|
@Test
|
|
fun `should validate unique identification numbers`() {
|
|
// Test für Eindeutigkeit der Identifikationsnummern
|
|
}
|
|
```
|
|
|
|
### Test-Datenbank
|
|
|
|
Verwendet H2 In-Memory-Datenbank für Tests mit automatischem Schema-Setup.
|
|
|
|
## Deployment
|
|
|
|
### Docker
|
|
|
|
```dockerfile
|
|
FROM openjdk:21-jre-slim
|
|
COPY horses-service.jar app.jar
|
|
EXPOSE 8083
|
|
ENTRYPOINT ["java", "-jar", "/app.jar"]
|
|
```
|
|
|
|
### Kubernetes
|
|
|
|
```yaml
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: horses-service
|
|
spec:
|
|
replicas: 2
|
|
selector:
|
|
matchLabels:
|
|
app: horses-service
|
|
template:
|
|
spec:
|
|
containers:
|
|
- name: horses-service
|
|
image: meldestelle/horses-service:latest
|
|
ports:
|
|
- containerPort: 8083
|
|
```
|
|
|
|
## Monitoring
|
|
|
|
### Metriken
|
|
|
|
- Anzahl aktiver Pferde
|
|
- Anzahl registrierter Pferde (OEPS/FEI)
|
|
- API-Response-Zeiten
|
|
- Datenbankverbindungs-Pool
|
|
- Validierungsfehler-Rate
|
|
|
|
### Health Checks
|
|
|
|
- Datenbankverbindung
|
|
- Service-Verfügbarkeit
|
|
- Speicherverbrauch
|
|
- Externe System-Verbindungen
|
|
|
|
## Entwicklung
|
|
|
|
### Lokale Entwicklung
|
|
|
|
```bash
|
|
# Service starten
|
|
./gradlew :horses:horses-service:bootRun
|
|
|
|
# Tests ausführen
|
|
./gradlew :horses:test
|
|
|
|
# Integration Tests
|
|
./gradlew :horses:horses-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
|
|
|
|
## Compliance und Standards
|
|
|
|
### OEPS-Integration
|
|
|
|
- Unterstützung für OEPS-Nummern
|
|
- Validierung nach OEPS-Standards
|
|
- Synchronisation mit OEPS-Datenbank
|
|
|
|
### FEI-Integration
|
|
|
|
- Unterstützung für FEI-Nummern
|
|
- Internationale Registrierungsstandards
|
|
- Compliance mit FEI-Regularien
|
|
|
|
### Datenschutz
|
|
|
|
- DSGVO-konforme Datenhaltung
|
|
- Anonymisierung von Testdaten
|
|
- Audit-Trail für alle Änderungen
|
|
|
|
## Zukünftige Erweiterungen
|
|
|
|
1. **Gesundheitsdaten** - Veterinärmedizinische Aufzeichnungen
|
|
2. **Leistungsdaten** - Turnierergebnisse und Bewertungen
|
|
3. **Versicherungsdaten** - Integration mit Versicherungssystemen
|
|
4. **Foto-Management** - Bildverwaltung für Pferde
|
|
5. **Stammbaum-Visualisierung** - Grafische Darstellung der Abstammung
|
|
6. **Import/Export** - Datenimport aus externen Systemen
|
|
7. **Mobile App** - Mobile Anwendung für Pferdebesitzer
|
|
8. **QR-Code-Integration** - QR-Codes für schnelle Identifikation
|
|
|
|
---
|
|
|
|
**Letzte Aktualisierung**: 25. Juli 2025
|
|
|
|
Für weitere Informationen zur Gesamtarchitektur siehe [README.md](../README.md).
|