feature(guideline)

This commit is contained in:
2025-08-15 21:17:09 +02:00
parent f5ca0ddb16
commit f84a7a1a49
4 changed files with 225 additions and 1175 deletions
-464
View File
@@ -1,464 +0,0 @@
# Meldestelle Development Guidelines
**Version:** 1.0
**Date:** 2025-08-15
**Status:** Active
This document outlines the development guidelines for the Meldestelle project, covering coding conventions, code organization, and testing approaches.
---
## 1. Coding Conventions
### 1.1 Language Standards
- **Primary Language:** Kotlin (JVM/Multiplatform)
- **Java Compatibility:** Target Java 21+
- **Kotlin Version:** Latest stable version
- **Code Style:** Official Kotlin coding conventions
### 1.2 Naming Conventions
#### Classes and Interfaces
```kotlin
// Use PascalCase for classes and interfaces
class MemberService
interface EventRepository
data class MemberRegistration
sealed class AuthResult
// Use descriptive names that reflect domain concepts
class HorseRegistrationService // Good
class HRS // Avoid abbreviations
```
#### Functions and Variables
```kotlin
// Use camelCase for functions and variables
fun authenticateUser(): AuthResult
val memberRepository: MemberRepository
suspend fun findByEmail(email: EmailAddress): Result<Member?, RepositoryError>
// Use descriptive test method names with "should" statements
@Test
fun `authenticate should return Success for valid credentials`()
```
#### Constants and Enums
```kotlin
// Use SCREAMING_SNAKE_CASE for constants
const val MAX_RETRY_ATTEMPTS = 3
const val DEFAULT_TIMEOUT_MS = 5000L
// Use PascalCase for enum values
enum class MemberStatus {
ACTIVE,
INACTIVE,
SUSPENDED
}
```
### 1.3 Code Structure Principles
#### Result Pattern Usage
```kotlin
// Always use Result pattern for operations that can fail
interface MemberRepository {
suspend fun findById(id: MemberId): Result<Member?, RepositoryError>
suspend fun save(member: Member): Result<Unit, RepositoryError>
}
// Result extensions for error handling
inline fun <T, E, R> Result<T, E>.mapError(transform: (E) -> R): Result<T, R> =
when (this) {
is Result.Success -> Result.Success(value)
is Result.Failure -> Result.Failure(transform(error))
}
```
#### Coroutines and Async Programming
```kotlin
// Use suspend functions for async operations
suspend fun processEventBatch(events: List<DomainEvent>): Result<Unit, ProcessingError>
// Prefer structured concurrency
class EventProcessor {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
suspend fun processEvents() = withContext(scope.coroutineContext) {
// Implementation
}
}
```
#### Documentation Standards
```kotlin
/**
* Authenticates a user with the given credentials.
*
* @param credentials The user credentials containing username and password
* @return AuthResult.Success with user data if authentication succeeds,
* AuthResult.Failure with error details if it fails
*/
suspend fun authenticate(credentials: UserCredentials): AuthResult
```
---
## 2. Code Organization and Package Structure
### 2.1 Overall Architecture
The project follows a **microservices architecture** with **Domain-Driven Design (DDD)** principles and **Clean Architecture** patterns.
#### High-Level Structure
```
Meldestelle/
├── core/ # Shared kernel - fundamental building blocks
│ ├── core-domain/ # Common domain types and interfaces
│ └── core-utils/ # Shared utilities and extensions
├── infrastructure/ # Cross-cutting infrastructure services
│ ├── auth/ # Authentication & authorization
│ ├── messaging/ # Event messaging (Kafka)
│ ├── cache/ # Distributed caching (Redis)
│ ├── gateway/ # API Gateway
│ └── monitoring/ # Observability and monitoring
├── [domain-services]/ # Domain-specific microservices
│ ├── members/ # Member management
│ ├── events/ # Event management
│ ├── horses/ # Horse registry
│ └── masterdata/ # Master data management
├── client/ # Client applications
│ ├── common-ui/ # Shared UI components (KMP)
│ ├── desktop-app/ # Desktop application
│ └── web-app/ # Web application
└── platform/ # Build and dependency management
```
### 2.2 Microservice Structure (Clean Architecture)
Each domain service follows a **4-layer architecture**:
```
domain-service/
├── domain-api/ # REST controllers, DTOs, API contracts
├── domain-application/ # Use cases, application logic, orchestration
├── domain-domain/ # Domain models, business rules, interfaces
└── domain-infrastructure/ # Technical implementations (DB, external APIs)
```
#### Layer Responsibilities
**`:domain-api` Layer:**
```kotlin
// REST Controllers
@RestController
@RequestMapping("/api/v1/members")
class MemberController(private val memberService: MemberService)
// DTOs for external communication
data class MemberRegistrationRequest(
val firstName: String,
val lastName: String,
val email: String
)
```
**`:domain-application` Layer:**
```kotlin
// Use cases and application services
class MemberApplicationService(
private val memberRepository: MemberRepository,
private val eventPublisher: EventPublisher
) {
suspend fun registerMember(command: RegisterMemberCommand): Result<MemberId, MemberError>
}
```
**`:domain-domain` Layer:**
```kotlin
// Domain models and business logic
data class Member(
val id: MemberId,
val personalInfo: PersonalInfo,
val membershipStatus: MembershipStatus
) {
fun activate(): Member = copy(membershipStatus = MembershipStatus.ACTIVE)
}
// Repository interfaces (implemented in infrastructure)
interface MemberRepository {
suspend fun findById(id: MemberId): Result<Member?, RepositoryError>
suspend fun save(member: Member): Result<Unit, RepositoryError>
}
```
**`:domain-infrastructure` Layer:**
```kotlin
// Technical implementations
class ExposedMemberRepository(
private val database: Database
) : MemberRepository {
override suspend fun findById(id: MemberId): Result<Member?, RepositoryError> {
// Database implementation using Exposed ORM
}
}
```
### 2.3 Package Naming Conventions
```kotlin
// Base package structure
at.mocode.[layer].[domain].[component]
// Examples
at.mocode.members.domain.model // Domain models
at.mocode.members.application.service // Application services
at.mocode.members.infrastructure.persistence // Persistence layer
at.mocode.infrastructure.messaging.kafka // Infrastructure components
at.mocode.core.utils.result // Core utilities
```
### 2.4 Dependency Rules
- **Core modules** must not depend on any other modules
- **Domain layer** must not depend on infrastructure or application layers
- **Application layer** can depend on domain layer only
- **Infrastructure layer** can depend on domain and application layers
- **API layer** orchestrates calls between application and infrastructure
---
## 3. Unit and Integration Testing Approaches
### 3.1 Testing Strategy Overview
The project follows a **comprehensive testing strategy** with multiple testing levels:
1. **Unit Tests** - Fast, isolated tests for individual components
2. **Integration Tests** - Tests for component interactions
3. **Performance Tests** - Load and throughput testing
4. **End-to-End Tests** - Full system workflow testing
### 3.2 Testing Stack
#### Core Testing Libraries
```kotlin
// Unit testing
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
testImplementation("io.mockk:mockk:1.13.8")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
// Integration testing
testImplementation("org.testcontainers:junit-jupiter:1.19.1")
testImplementation("org.testcontainers:kafka:1.19.1")
testImplementation("org.testcontainers:postgresql:1.19.1")
// Performance testing
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
```
### 3.3 Unit Testing Conventions
#### Test Structure and Naming
```kotlin
class AuthenticationServiceTest {
@BeforeEach
fun setUp() {
// Test setup
}
@Test
fun `authenticate should return Success for valid credentials`() = runTest {
// Given
val credentials = UserCredentials("user@example.com", "validPassword")
coEvery { userRepository.findByEmail(any()) } returns Result.Success(testUser)
// When
val result = authenticationService.authenticate(credentials)
// Then
assertTrue(result is AuthResult.Success)
assertEquals(testUser.id, result.user.id)
}
@Test
fun `authenticate should return Failure for invalid credentials`() = runTest {
// Given - When - Then pattern
}
}
```
#### Mocking Best Practices
```kotlin
class MemberServiceTest {
private val memberRepository = mockk<MemberRepository>()
private val eventPublisher = mockk<EventPublisher>()
private val memberService = MemberService(memberRepository, eventPublisher)
@Test
fun `should publish event when member is registered`() = runTest {
// Mock repository responses
coEvery { memberRepository.save(any()) } returns Result.Success(Unit)
coEvery { eventPublisher.publish(any()) } returns Result.Success(Unit)
// Test implementation
val result = memberService.registerMember(validCommand)
// Verify interactions
coVerify { eventPublisher.publish(any<MemberRegisteredEvent>()) }
}
}
```
### 3.4 Integration Testing Approaches
#### Database Integration Tests
```kotlin
@Testcontainers
class MemberRepositoryIntegrationTest {
companion object {
@Container
val postgres = PostgreSQLContainer<Nothing>("postgres:15-alpine")
}
@Test
fun `should persist and retrieve member correctly`() = runTest {
// Test with real database using Testcontainers
val member = createTestMember()
val saveResult = memberRepository.save(member)
assertTrue(saveResult.isSuccess())
val retrievedResult = memberRepository.findById(member.id)
assertTrue(retrievedResult.isSuccess())
assertEquals(member, retrievedResult.getOrNull())
}
}
```
#### Messaging Integration Tests
```kotlin
@Testcontainers
class KafkaEventPublisherIntegrationTest {
companion object {
@Container
val kafka = KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:latest"))
}
@Test
fun `should publish and consume events correctly`() = runTest {
val event = MemberRegisteredEvent(memberId = MemberId.generate())
val publishResult = eventPublisher.publish(event)
assertTrue(publishResult.isSuccess())
// Verify event was consumed
val consumedEvents = eventConsumer.consumeEvents(timeout = 5.seconds)
assertTrue(consumedEvents.any { it.memberId == event.memberId })
}
}
```
### 3.5 Performance Testing
#### Batch Processing Performance Tests
```kotlin
class KafkaBatchPerformanceTest {
@Test
fun `should process large batches within acceptable time limits`() = runTest {
val batchSize = 1000
val events = generateTestEvents(batchSize)
val startTime = System.currentTimeMillis()
val results = eventProcessor.processBatch(events)
val processingTime = System.currentTimeMillis() - startTime
assertTrue(results.all { it.isSuccess() })
assertTrue(processingTime < 5000) // Should complete within 5 seconds
println("[DEBUG_LOG] Processed $batchSize events in ${processingTime}ms")
}
}
```
### 3.6 Test Organization
#### Directory Structure
```
src/
├── main/kotlin/ # Production code
└── test/kotlin/ # Test code
├── unit/ # Unit tests (optional sub-organization)
├── integration/ # Integration tests
└── performance/ # Performance tests
```
#### Test Categories and Execution
```kotlin
// Use JUnit 5 tags for test categorization
@Tag("unit")
class MemberServiceTest
@Tag("integration")
class MemberRepositoryIntegrationTest
@Tag("performance")
class KafkaBatchPerformanceTest
```
### 3.7 Testing Guidelines
#### Best Practices
1. **Test Method Naming:** Use descriptive names with "should" statements
2. **AAA Pattern:** Arrange, Act, Assert structure
3. **One Assertion Per Test:** Focus on single behavior
4. **Test Data Builders:** Use factory methods for test data creation
5. **Coroutine Testing:** Use `runTest` for suspend functions
6. **Mock Verification:** Verify important interactions, not implementation details
#### Coverage Goals
- **Unit Tests:** 80%+ code coverage for domain and application layers
- **Integration Tests:** Cover all repository implementations and external integrations
- **Performance Tests:** Cover critical batch operations and high-load scenarios
#### Debugging Support
```kotlin
// Always prefix debug messages with [DEBUG_LOG]
@Test
fun `should handle concurrent requests`() = runTest {
println("[DEBUG_LOG] Starting concurrent request test with ${requestCount} requests")
// Test implementation
println("[DEBUG_LOG] Completed test. Success rate: ${successCount}/${requestCount}")
}
```
---
## 4. Additional Development Standards
### 4.1 Error Handling
- Use `Result` pattern consistently for operations that can fail
- Define domain-specific error types
- Avoid throwing exceptions in domain logic
### 4.2 Logging and Monitoring
- Use structured logging with appropriate log levels
- Include correlation IDs for request tracing
- Monitor key business metrics and technical performance
### 4.3 Security Considerations
- Validate all external inputs
- Use JWT tokens for authentication
- Implement proper authorization checks
- Secure sensitive configuration data
---
This guideline is a living document and should be updated as the project evolves and new patterns emerge.
+161
View File
@@ -0,0 +1,161 @@
# Meldestelle_Pro: Entwicklungs-Guideline
**Status:** Finalisiert & Verbindlich
**Version:** 1.0
**Stand:** 15. August 2025
## 1. Vision & Architektonische Grundpfeiler
Dieses Dokument definiert die verbindlichen technischen Richtlinien und Qualitätsstandards für das Projekt "
Meldestelle_Pro". Ziel ist die Schaffung einer modernen, skalierbaren und wartbaren Plattform für den Pferdesport.
Unsere Architektur basiert auf **vier Säulen**:
1. **Modularität & Skalierbarkeit** durch eine **Microservices-Architektur**
2. **Fachlichkeit im Code** durch **Domain-Driven Design (DDD)**
3. **Entkopplung & Resilienz** durch eine **ereignisgesteuerte Architektur (EDA)**
4. **Effizienz & Konsistenz** durch eine **Multiplattform-Client-Strategie (KMP)**
> **Grundsatz:** Jede Code-Änderung muss diese vier Grundprinzipien respektieren.
---
## 2. Coding Conventions & Code-Qualität
### 2.1. Sprach- und Stilstandards
* **Primärsprache:** Kotlin (JVM/Multiplatform)
* **Java-Kompatibilität:** Ziel ist Java 21+
* **Code-Stil:** Offizielle Kotlin Coding Conventions, durch `Detekt` geprüft.
### 2.2. Namenskonventionen
* **Klassen & Interfaces:** `PascalCase` (z.B. `MemberService`, `EventRepository`)
* **Funktionen & Variablen:** `camelCase` (z.B. `authenticateUser`, `memberRepository`)
* **Testmethoden:** Beschreibend mit Backticks (z.B. `` `should return Success for valid credentials` ``)
* **Konstanten:** `SCREAMING_SNAKE_CASE` (z.B. `MAX_RETRY_ATTEMPTS`)
* **Enums:** `PascalCase` für Werte (z.B. `MemberStatus.ACTIVE`)
### 2.3. Value Classes für Typsicherheit
Primitive Typen (UUID, String, Long) für IDs oder spezifische Werte müssen in typsichere `value class`-Wrapper gekapselt
werden.
```kotlin
@JvmInline
value class MemberId(val value: UUID) {
companion object {
fun of(value: String): Result<MemberId, ValidationError> =
runCatching { UUID.fromString(value) }
.map { MemberId(it) }
.mapError { ValidationError.INVALID_UUID }
}
}
```
### 2.4. Error-Handling & Logging
* **`Result`-Pattern:** Für erwartbare Geschäftsfehler ist das `Result`-Pattern zu verwenden. Exceptions sind für
unerwartete, technische Fehler reserviert.
* **Fehler-Hierarchie:** Wir verwenden eine `sealed class`-Hierarchie, um Fehlerarten klar zu kategorisieren (
`DomainError`, `ValidationError`, `BusinessError`, `TechnicalError`).
* **Structured Logging:** Logs müssen strukturiert sein und eine Korrelations-ID enthalten, um Anfragen über
Service-Grenzen hinweg zu verfolgen.
```kotlin
logger.info {
"Creating member" with mapOf(
"memberId" to command.memberId.value,
"correlationId" to MDC.get("correlationId")
)
}
```
---
## 3. Backend-Entwicklungsrichtlinien
### 3.1. Microservice-Struktur (Clean Architecture)
Jeder fachliche Microservice folgt der 4-Layer-Struktur (`api`, `application`, `domain`, `infrastructure`).
### 3.2. Repository-Pattern
Jede Repository-Methode muss das `Result`-Pattern verwenden.
```kotlin
interface MemberRepository {
suspend fun findById(id: MemberId): Result<Member?, RepositoryError>
suspend fun save(member: Member): Result<Unit, RepositoryError>
}
```
### 3.3. Messaging & Event-Naming
* **Event-Naming Convention:** Domänen-Events folgen dem Muster `{Domain}{Entity}{Action}Event`.
```kotlin
data class MemberPersonalDataUpdatedEvent(...) : DomainEvent(...)
```
---
## 4. Frontend-Entwicklungsrichtlinien
Das Frontend folgt konsequent dem **Model-View-ViewModel (MVVM)**-Muster und der **Kotlin Multiplatform (KMP)**
-Strategie. Der UI-Code wird nach **fachlichen Features** (vertikale Schnitte) strukturiert.
---
## 5. Testing
Tests sind ein integraler Bestandteil jedes Features und müssen einen hohen Standard erfüllen.
### 5.1. Test-Pyramide & Werkzeuge
* **Unit-Tests (80 %+ Abdeckung):** Für Domänen- und Anwendungslogik (JUnit 5, MockK).
* **Integrationstests:** Decken alle Repository-Implementierungen und externen Integrationen ab.
* **Testcontainers als Goldstandard:** Jede Interaktion mit externer Infrastruktur (DB, Cache, Broker) **muss** mit
**Testcontainers** getestet werden.
### 5.2. Debugging
Debug-Ausgaben im Test-Code müssen mit `[DEBUG_LOG]` beginnen, um sie leicht identifizieren und filtern zu können.
---
## 6. Infrastruktur- & Betriebs-Spezifikationen
### 6.1. Kafka-Konfiguration
Die Konfiguration muss auf maximale Zuverlässigkeit ausgelegt sein:
```yaml
# in application.yml
kafka:
producer:
acks: all
enable-idempotence: true
max-in-flight-requests-per-connection: 1
consumer:
group-id-prefix: "meldestelle-${spring.application.name}"
auto-offset-reset: earliest
enable-auto-commit: false
```
### 6.2. Datenbank-Migrationen (Flyway)
Migrations-Skripte müssen einer klaren Namenskonvention folgen.
* **Pattern:** `V{version}__{description}.sql` (z.B., `V001__Create_member_tables.sql`)
* **Repeatable:** `R__{description}.sql` (z.B., `R__Update_member_view.sql`)
### 6.3. API-Dokumentation (OpenAPI)
Alle öffentlichen REST-Endpunkte müssen mit OpenAPI-Annotationen (`@Operation`, `@ApiResponse`) dokumentiert werden, um
eine klare und interaktive API-Dokumentation zu generieren.
@@ -0,0 +1,64 @@
# Guideline: Zyklus "Tracer Bullet"
* **Zyklus-Start:** 15. August 2025
* **Status:** In Arbeit
* **Basis:** Diese Guideline erweitert die [Master-Guideline](./master-guideline.md)
## 1. Ziel des Zyklus
Das oberste und einzige Ziel dieses Entwicklungszyklus ist die **Validierung der gesamten technischen Architektur
End-to-End**. Wir wollen beweisen, dass eine Anfrage vom Client den gesamten technischen Stack (Gateway, Service
Discovery, Backend-Service) erfolgreich durchlaufen und eine Antwort zurückliefern kann.
Am Ende dieses Zyklus werden wir einen stabilen, qualitätsgesicherten und dokumentierten Unterbau haben, auf dem die
Entwicklung der fachlichen Features aufsetzen kann.
## 2. Umfang (Was gehört zu diesem Zyklus?)
Die folgenden Module und Aufgaben sind Teil dieses Zyklus:
* **Backend-Infrastruktur (`:core` & `:infrastructure`):**
* Vollständige Überarbeitung, Optimierung und Testabdeckung aller Infrastruktur-Module (`cache`, `event-store`,
`auth`, `messaging`, `monitoring`, `gateway`).
* Implementierung einer robusten Logging- und Konfigurations-Infrastruktur.
* **Temporärer Test-Service (`:temp:ping-service`):**
* Erstellung eines minimalen Spring-Boot-Service, der nur einen `GET /ping`-Endpunkt bereitstellt.
* **Frontend-Infrastruktur (`:client`):**
* Aufbau einer sauberen, leeren Grundstruktur für die Kotlin Multiplatform App nach dem MVVM-Muster.
* Implementierung einer minimalen UI mit einem "Ping"-Button und einem Anzeigefeld für die Antwort.
## 3. Spezifische Richtlinien für diesen Zyklus
* **Fokus auf Technik, nicht Fachlichkeit:** Jede Zeile Code, die in diesem Zyklus geschrieben wird, dient
ausschließlich der Stabilisierung der technischen Infrastruktur. Es wird keine komplexe Geschäftslogik implementiert.
* **Qualitätsstandards gelten uneingeschränkt:** Auch für diesen technischen Zyklus gelten alle Regeln der
Master-Guideline. Insbesondere:
* **Tests sind Pflicht:** Jede neue oder geänderte Komponente muss durch Tests (insbesondere **Testcontainers** für
Infrastruktur) abgesichert werden.
* **Kein `println`:** Es wird ausschließlich der strukturierte Logger verwendet.
* **Dokumentation ist Teil der Aufgabe:** Jedes Modul, das wir überarbeiten, wird mit einer aktualisierten und präzisen
`README.md`-Datei abgeschlossen.
## 4. Definition of Done (Wann sind wir fertig?)
Dieser Zyklus ist abgeschlossen, wenn **alle** der folgenden Kriterien erfüllt sind:
* [ ] Alle `:core` und `:infrastructure`-Module wurden überarbeitet, sind fehlerfrei testbar und ihre `README.md`
-Dateien sind auf dem neuesten Stand.
* [ ] Der `:temp:ping-service` ist implementiert, getestet und lauffähig.
* [ ] Die `:client:web-app` ist mit einer sauberen MVVM-Struktur aufgesetzt und startet fehlerfrei.
* [ ] **Der End-to-End "Tracer Bullet"-Test ist erfolgreich:**
* [ ] Alle Docker-Container (`docker-compose up`) starten.
* [ ] Der `gateway`-Service startet.
* [ ] Der `ping-service` startet und registriert sich erfolgreich bei Consul.
* [ ] Die `web-app` startet.
* [ ] Ein Klick auf den "Ping"-Button in der Web-App führt zu einer `GET`-Anfrage an das Gateway, wird korrekt an
den `ping-service` weitergeleitet und die Antwort `"pong"` wird erfolgreich in der UI angezeigt.
* [ ] Der gesamte `clean build` des Projekts läuft ohne Fehler und **ohne Warnungen**.
* [ ] Die `master-guideline.md` und die `trace-bullet-guideline.md` sind finalisiert.
## 5. Lessons Learned (nach Abschluss)
- [ ] Was hat gut funktioniert?
- [ ] Was würden wir beim nächsten Zyklus anders machen?
- [ ] Welche Standards müssen in die Master-Guideline übernommen werden?