docs: Migrationsplan für Projekt-Restrukturierung hinzugefügt
- Detaillierter Plan zur Migration von alter zu neuer Modulstruktur - Umfasst Überführung von shared-kernel zu core-Modulen - Definiert Migration von Fachdomänen zu bounded contexts: * master-data → masterdata-Module * member-management → members-Module * horse-registry → horses-Module * event-management → events-Module - Beschreibt Verlagerung von api-gateway zu infrastructure/gateway - Strukturiert nach Domain-driven Design Prinzipien - Berücksichtigt Clean Architecture Layering (domain, application, infrastructure, api)
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
# Members Module
|
||||
|
||||
## Überblick
|
||||
|
||||
Das Members-Modul ist eine umfassende Lösung zur Verwaltung von Mitgliedern 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 Mitgliederverwaltung.
|
||||
|
||||
## Funktionalität
|
||||
|
||||
### Verwaltete Entität
|
||||
|
||||
#### Mitglied (Member)
|
||||
- **Persönliche Informationen**: Vor- und Nachname, E-Mail, Telefon, Geburtsdatum
|
||||
- **Mitgliedschaftsinformationen**: Mitgliedsnummer, Start-/Enddatum, Aktivitätsstatus
|
||||
- **Zusätzliche Informationen**: Adresse, Notfallkontakt
|
||||
- **Audit-Felder**: Erstellungs- und Aktualisierungszeitstempel
|
||||
- **Geschäftslogik**: Validierung, Mitgliedschaftsgültigkeit, Vollständiger Name
|
||||
|
||||
### Geschäftsoperationen
|
||||
|
||||
Das Modul bietet 18+ spezialisierte Repository-Operationen:
|
||||
|
||||
#### Basis-CRUD-Operationen
|
||||
- `findById(id)` - Mitglied nach UUID suchen
|
||||
- `save(member)` - Mitglied speichern (erstellen/aktualisieren)
|
||||
- `delete(id)` - Mitglied löschen
|
||||
|
||||
#### Such-Operationen
|
||||
- `findByMembershipNumber(number)` - Nach Mitgliedsnummer suchen
|
||||
- `findByEmail(email)` - Nach E-Mail-Adresse suchen
|
||||
- `findByName(searchTerm, limit)` - Nach Namen suchen (Teilübereinstimmung)
|
||||
- `findAllActive(limit, offset)` - Alle aktiven Mitglieder
|
||||
- `findAll(limit, offset)` - Alle Mitglieder (aktiv und inaktiv)
|
||||
|
||||
#### Datumsbasierte Abfragen
|
||||
- `findByMembershipStartDateRange(start, end)` - Mitglieder nach Startdatum-Bereich
|
||||
- `findByMembershipEndDateRange(start, end)` - Mitglieder nach Enddatum-Bereich
|
||||
- `findMembersWithExpiringMembership(daysAhead)` - Mitglieder mit ablaufender Mitgliedschaft
|
||||
|
||||
#### Validierungs-Operationen
|
||||
- `existsByMembershipNumber(number, excludeId)` - Prüfung auf doppelte Mitgliedsnummer
|
||||
- `existsByEmail(email, excludeId)` - Prüfung auf doppelte E-Mail-Adresse
|
||||
|
||||
#### Zähl-Operationen
|
||||
- `countActive()` - Anzahl aktiver Mitglieder
|
||||
- `countAll()` - Gesamtanzahl aller Mitglieder
|
||||
|
||||
## Architektur
|
||||
|
||||
Das Modul folgt der Clean Architecture mit klarer Trennung der Verantwortlichkeiten:
|
||||
|
||||
```
|
||||
members/
|
||||
├── members-domain/ # Domain Layer
|
||||
│ ├── model/ # Domain Models
|
||||
│ │ └── Member.kt # Mitglied-Entität mit Geschäftslogik
|
||||
│ ├── repository/ # Repository Interfaces
|
||||
│ │ └── MemberRepository.kt # 18+ Geschäftsoperationen
|
||||
│ └── events/ # Domain Events
|
||||
│ └── MemberEvents.kt # Mitgliedschafts-Events
|
||||
├── members-application/ # Application Layer
|
||||
│ └── usecase/ # Use Cases
|
||||
│ └── FindExpiringMembershipsUseCase.kt
|
||||
├── members-infrastructure/ # Infrastructure Layer
|
||||
│ ├── persistence/ # Database Implementation
|
||||
│ │ ├── MemberRepositoryImpl.kt
|
||||
│ │ └── MemberTable.kt
|
||||
│ └── repository/ # Alternative Implementations
|
||||
│ └── InMemoryMemberRepository.kt
|
||||
├── members-api/ # API Layer
|
||||
│ └── rest/ # REST Controllers
|
||||
│ └── MemberController.kt
|
||||
└── members-service/ # Service Layer
|
||||
├── MembersServiceApplication.kt
|
||||
└── test/ # Integration Tests
|
||||
└── MemberServiceIntegrationTest.kt
|
||||
```
|
||||
|
||||
### Domain Layer
|
||||
- **1 Domain Model** mit reichhaltiger Geschäftslogik
|
||||
- **1 Repository Interface** mit 18+ Geschäftsoperationen
|
||||
- **Domain Events** für Mitgliedschaftsänderungen
|
||||
- **Keine Abhängigkeiten** zu anderen Layern
|
||||
|
||||
### Application Layer
|
||||
- **Use Cases** für komplexe Geschäftsoperationen
|
||||
- **Orchestrierung** von Domain-Services
|
||||
- **Anwendungslogik** ohne UI-Abhängigkeiten
|
||||
|
||||
### Infrastructure Layer
|
||||
- **Datenbankzugriff** mit Exposed ORM
|
||||
- **Repository-Implementierung** mit PostgreSQL
|
||||
- **In-Memory-Repository** für Tests
|
||||
- **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
|
||||
- **Integrationstests**
|
||||
|
||||
## Domain Model Details
|
||||
|
||||
### Member-Entität
|
||||
|
||||
```kotlin
|
||||
data class Member(
|
||||
val memberId: Uuid,
|
||||
|
||||
// Persönliche Informationen
|
||||
var firstName: String,
|
||||
var lastName: String,
|
||||
var email: String,
|
||||
var phone: String? = null,
|
||||
var dateOfBirth: LocalDate? = null,
|
||||
|
||||
// Mitgliedschaftsinformationen
|
||||
var membershipNumber: String,
|
||||
var membershipStartDate: LocalDate,
|
||||
var membershipEndDate: LocalDate? = null,
|
||||
var isActive: Boolean = true,
|
||||
|
||||
// Zusätzliche Informationen
|
||||
var address: String? = null,
|
||||
var emergencyContact: String? = null,
|
||||
|
||||
// Audit-Felder
|
||||
val createdAt: Instant,
|
||||
var updatedAt: Instant
|
||||
)
|
||||
```
|
||||
|
||||
### Geschäftslogik-Methoden
|
||||
|
||||
- `getFullName()` - Vollständiger Name des Mitglieds
|
||||
- `isMembershipValid()` - Prüfung der Mitgliedschaftsgültigkeit
|
||||
- `validate()` - Datenvalidierung mit Fehlerliste
|
||||
- `withUpdatedTimestamp()` - Kopie mit aktualisiertem Zeitstempel
|
||||
|
||||
## Repository-Operationen
|
||||
|
||||
### Erweiterte Such-Features
|
||||
|
||||
```kotlin
|
||||
// Mitglieder mit ablaufender Mitgliedschaft finden
|
||||
val expiringMembers = memberRepository.findMembersWithExpiringMembership(30)
|
||||
|
||||
// Mitglieder nach Datumsbereich suchen
|
||||
val newMembers = memberRepository.findByMembershipStartDateRange(
|
||||
startDate = LocalDate(2024, 1, 1),
|
||||
endDate = LocalDate(2024, 12, 31)
|
||||
)
|
||||
|
||||
// Namenssuche mit Teilübereinstimmung
|
||||
val searchResults = memberRepository.findByName("Schmidt", limit = 10)
|
||||
```
|
||||
|
||||
### Validierung und Duplikatsprüfung
|
||||
|
||||
```kotlin
|
||||
// Prüfung auf doppelte Mitgliedsnummer
|
||||
val numberExists = memberRepository.existsByMembershipNumber("M2024001")
|
||||
|
||||
// Prüfung auf doppelte E-Mail (mit Ausschluss für Updates)
|
||||
val emailExists = memberRepository.existsByEmail(
|
||||
email = "max@example.com",
|
||||
excludeMemberId = existingMember.memberId
|
||||
)
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
### FindExpiringMembershipsUseCase
|
||||
|
||||
Findet Mitglieder mit ablaufenden Mitgliedschaften und kann automatische Benachrichtigungen auslösen.
|
||||
|
||||
```kotlin
|
||||
class FindExpiringMembershipsUseCase(
|
||||
private val memberRepository: MemberRepository
|
||||
) {
|
||||
suspend fun execute(daysAhead: Int = 30): List<Member> {
|
||||
return memberRepository.findMembersWithExpiringMembership(daysAhead)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API-Endpunkte
|
||||
|
||||
Das Members-Modul stellt REST-Endpunkte über den MemberController bereit:
|
||||
|
||||
- `GET /api/members` - Alle aktiven Mitglieder abrufen
|
||||
- `GET /api/members/{id}` - Mitglied nach ID abrufen
|
||||
- `GET /api/members/search?name={name}` - Mitglieder nach Namen suchen
|
||||
- `GET /api/members/expiring?days={days}` - Mitglieder mit ablaufender Mitgliedschaft
|
||||
- `POST /api/members` - Neues Mitglied erstellen
|
||||
- `PUT /api/members/{id}` - Mitglied aktualisieren
|
||||
- `DELETE /api/members/{id}` - Mitglied löschen
|
||||
|
||||
## Konfiguration
|
||||
|
||||
### Datenbankschema
|
||||
|
||||
Das Modul verwendet eine `members`-Tabelle mit folgenden Spalten:
|
||||
- `member_id` (UUID, Primary Key)
|
||||
- `first_name`, `last_name`, `email` (Required)
|
||||
- `phone`, `date_of_birth` (Optional)
|
||||
- `membership_number` (Unique)
|
||||
- `membership_start_date`, `membership_end_date`
|
||||
- `is_active` (Boolean)
|
||||
- `address`, `emergency_contact` (Optional)
|
||||
- `created_at`, `updated_at` (Timestamps)
|
||||
|
||||
### Service-Konfiguration
|
||||
|
||||
```yaml
|
||||
# application.yml
|
||||
members:
|
||||
service:
|
||||
name: members-service
|
||||
port: 8082
|
||||
database:
|
||||
url: jdbc:postgresql://localhost:5432/meldestelle
|
||||
table: members
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
### Integration Tests
|
||||
|
||||
Das Modul enthält umfassende Integrationstests:
|
||||
|
||||
```kotlin
|
||||
@Test
|
||||
fun `should find members with expiring membership`() {
|
||||
// Test-Implementierung für ablaufende Mitgliedschaften
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should validate unique membership number`() {
|
||||
// Test für Eindeutigkeit der Mitgliedsnummer
|
||||
}
|
||||
```
|
||||
|
||||
### Test-Datenbank
|
||||
|
||||
Verwendet H2 In-Memory-Datenbank für Tests mit automatischem Schema-Setup.
|
||||
|
||||
## Deployment
|
||||
|
||||
### Docker
|
||||
|
||||
```dockerfile
|
||||
FROM openjdk:21-jre-slim
|
||||
COPY members-service.jar app.jar
|
||||
EXPOSE 8082
|
||||
ENTRYPOINT ["java", "-jar", "/app.jar"]
|
||||
```
|
||||
|
||||
### Kubernetes
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: members-service
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: members-service
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: members-service
|
||||
image: meldestelle/members-service:latest
|
||||
ports:
|
||||
- containerPort: 8082
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Metriken
|
||||
|
||||
- Anzahl aktiver Mitglieder
|
||||
- Anzahl ablaufender Mitgliedschaften
|
||||
- API-Response-Zeiten
|
||||
- Datenbankverbindungs-Pool
|
||||
|
||||
### Health Checks
|
||||
|
||||
- Datenbankverbindung
|
||||
- Service-Verfügbarkeit
|
||||
- Speicherverbrauch
|
||||
|
||||
## Entwicklung
|
||||
|
||||
### Lokale Entwicklung
|
||||
|
||||
```bash
|
||||
# Service starten
|
||||
./gradlew :members:members-service:bootRun
|
||||
|
||||
# Tests ausführen
|
||||
./gradlew :members:test
|
||||
|
||||
# Integration Tests
|
||||
./gradlew :members:members-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
|
||||
|
||||
## Zukünftige Erweiterungen
|
||||
|
||||
1. **Mitgliedschaftstypen** - Verschiedene Mitgliedschaftskategorien
|
||||
2. **Beitragsverwaltung** - Integration mit Zahlungssystem
|
||||
3. **Mitgliedschaftshistorie** - Tracking von Änderungen
|
||||
4. **Bulk-Operationen** - Massenimport/-export
|
||||
5. **Benachrichtigungen** - Automatische E-Mail-Benachrichtigungen
|
||||
6. **Reporting** - Mitgliedschaftsstatistiken und Reports
|
||||
|
||||
---
|
||||
|
||||
**Letzte Aktualisierung**: 25. Juli 2025
|
||||
|
||||
Für weitere Informationen zur Gesamtarchitektur siehe [README.md](../README.md).
|
||||
Reference in New Issue
Block a user