9.4 KiB
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 suchensave(member)- Mitglied speichern (erstellen/aktualisieren)delete(id)- Mitglied löschen
Such-Operationen
findByMembershipNumber(number)- Nach Mitgliedsnummer suchenfindByEmail(email)- Nach E-Mail-Adresse suchenfindByName(searchTerm, limit)- Nach Namen suchen (Teilübereinstimmung)findAllActive(limit, offset)- Alle aktiven MitgliederfindAll(limit, offset)- Alle Mitglieder (aktiv und inaktiv)
Datumsbasierte Abfragen
findByMembershipStartDateRange(start, end)- Mitglieder nach Startdatum-BereichfindByMembershipEndDateRange(start, end)- Mitglieder nach Enddatum-BereichfindMembersWithExpiringMembership(daysAhead)- Mitglieder mit ablaufender Mitgliedschaft
Validierungs-Operationen
existsByMembershipNumber(number, excludeId)- Prüfung auf doppelte MitgliedsnummerexistsByEmail(email, excludeId)- Prüfung auf doppelte E-Mail-Adresse
Zähl-Operationen
countActive()- Anzahl aktiver MitgliedercountAll()- 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
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 MitgliedsisMembershipValid()- Prüfung der Mitgliedschaftsgültigkeitvalidate()- Datenvalidierung mit FehlerlistewithUpdatedTimestamp()- Kopie mit aktualisiertem Zeitstempel
Repository-Operationen
Erweiterte Such-Features
// 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
// 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.
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 abrufenGET /api/members/{id}- Mitglied nach ID abrufenGET /api/members/search?name={name}- Mitglieder nach Namen suchenGET /api/members/expiring?days={days}- Mitglieder mit ablaufender MitgliedschaftPOST /api/members- Neues Mitglied erstellenPUT /api/members/{id}- Mitglied aktualisierenDELETE /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_dateis_active(Boolean)address,emergency_contact(Optional)created_at,updated_at(Timestamps)
Service-Konfiguration
# 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:
@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
FROM openjdk:21-jre-slim
COPY members-service.jar app.jar
EXPOSE 8082
ENTRYPOINT ["java", "-jar", "/app.jar"]
Kubernetes
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
# 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
- Mitgliedschaftstypen - Verschiedene Mitgliedschaftskategorien
- Beitragsverwaltung - Integration mit Zahlungssystem
- Mitgliedschaftshistorie - Tracking von Änderungen
- Bulk-Operationen - Massenimport/-export
- Benachrichtigungen - Automatische E-Mail-Benachrichtigungen
- Reporting - Mitgliedschaftsstatistiken und Reports
Letzte Aktualisierung: 25. Juli 2025
Für weitere Informationen zur Gesamtarchitektur siehe README.md.