meldestelle/domains/horses/README-HORSES.md
StefanMo 9ea2b74a81
Merge pull request #18
* MP-19 Refactoring: Einführung der "Registry" & "Masterdata" Trennung …

* MP-19 Refactoring: Frontend Tabula Rasa

* MP-19 Refactoring: Frontend Tabula Rasa

* refactoring:

* MP-20 fix(docker/clients): include `:domains` module in web/desktop b…

* MP-20 fix(web-app build): resolve JS compile error and add dev/prod b…

* MP-20 fix(web-app): remove vendor.js reference and harden JS bootstra…

* MP-20 fixing: clients

* MP-20 fixing: clients
2025-11-30 14:13:12 +01:00

562 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).