refactor: Migrate from monolithic to modular architecture

1. **Dokumentation der Architektur:**
    - Vervollständigen Sie die C4-Diagramme im docs-Verzeichnis
    - Dokumentieren Sie die wichtigsten Architekturentscheidungen in ADRs

2. **Redis-Integration finalisieren:**
    - Implementieren Sie die verteilte Cache-Lösung für die Offline-Fähigkeit
    - Nutzen Sie Redis Streams für das Event-Sourcing
This commit is contained in:
stefan
2025-07-23 14:29:40 +02:00
parent a256622f37
commit 9282dd0eb4
52 changed files with 5648 additions and 3 deletions
@@ -3,6 +3,9 @@ plugins {
}
dependencies {
// Apply platform BOM for version management
implementation(platform(projects.platform.platformBom))
implementation(projects.core.coreDomain)
implementation(projects.core.coreUtils)
@@ -0,0 +1,76 @@
package at.mocode.infrastructure.eventstore.api
import at.mocode.core.domain.event.DomainEvent
import java.util.UUID
/**
* Interface for serializing and deserializing domain events.
*/
interface EventSerializer {
/**
* Serializes a domain event to a map of strings to strings.
* This format is suitable for storage in Redis Streams.
*
* @param event The event to serialize
* @return A map of strings to strings representing the event
*/
fun serialize(event: DomainEvent): Map<String, String>
/**
* Deserializes a map of strings to strings to a domain event.
*
* @param data The map of strings to strings to deserialize
* @return The deserialized domain event
*/
fun deserialize(data: Map<String, String>): DomainEvent
/**
* Gets the type of a domain event.
* This is used to determine the type of event when deserializing.
*
* @param event The event to get the type of
* @return The type of the event as a string
*/
fun getEventType(event: DomainEvent): String
/**
* Gets the type of a domain event from a serialized map.
*
* @param data The serialized event data
* @return The type of the event as a string
*/
fun getEventType(data: Map<String, String>): String
/**
* Registers a domain event class with the serializer.
* This is used to map event types to their corresponding classes.
*
* @param eventClass The class of the event to register
* @param eventType The type of the event as a string
*/
fun registerEventType(eventClass: Class<out DomainEvent>, eventType: String)
/**
* Gets the aggregate ID from a serialized event.
*
* @param data The serialized event data
* @return The aggregate ID
*/
fun getAggregateId(data: Map<String, String>): UUID
/**
* Gets the event ID from a serialized event.
*
* @param data The serialized event data
* @return The event ID
*/
fun getEventId(data: Map<String, String>): UUID
/**
* Gets the version from a serialized event.
*
* @param data The serialized event data
* @return The version
*/
fun getVersion(data: Map<String, String>): Long
}
@@ -0,0 +1,99 @@
package at.mocode.infrastructure.eventstore.api
import at.mocode.core.domain.event.DomainEvent
import java.util.UUID
/**
* Interface for an event store that persists domain events.
*/
interface EventStore {
/**
* Appends an event to the event store.
*
* @param event The event to append
* @param streamId The ID of the event stream (typically the aggregate ID)
* @param expectedVersion The expected version of the stream (for optimistic concurrency)
* @return The new version of the stream
* @throws ConcurrencyException if the expected version doesn't match the actual version
*/
fun appendToStream(event: DomainEvent, streamId: UUID, expectedVersion: Long): Long
/**
* Appends multiple events to the event store.
*
* @param events The events to append
* @param streamId The ID of the event stream (typically the aggregate ID)
* @param expectedVersion The expected version of the stream (for optimistic concurrency)
* @return The new version of the stream
* @throws ConcurrencyException if the expected version doesn't match the actual version
*/
fun appendToStream(events: List<DomainEvent>, streamId: UUID, expectedVersion: Long): Long
/**
* Reads events from a stream.
*
* @param streamId The ID of the event stream to read from
* @param fromVersion The version to start reading from (inclusive)
* @param toVersion The version to read to (inclusive), or null to read all events
* @return The events in the stream
*/
fun readFromStream(streamId: UUID, fromVersion: Long = 0, toVersion: Long? = null): List<DomainEvent>
/**
* Reads all events from all streams.
*
* @param fromPosition The position to start reading from (inclusive)
* @param maxCount The maximum number of events to read, or null to read all events
* @return The events in all streams
*/
fun readAllEvents(fromPosition: Long = 0, maxCount: Int? = null): List<DomainEvent>
/**
* Gets the current version of a stream.
*
* @param streamId The ID of the event stream
* @return The current version of the stream, or -1 if the stream doesn't exist
*/
fun getStreamVersion(streamId: UUID): Long
/**
* Subscribes to events from a specific stream.
*
* @param streamId The ID of the event stream to subscribe to
* @param fromVersion The version to start subscribing from (inclusive)
* @param handler The handler to call for each event
* @return A subscription that can be used to unsubscribe
*/
fun subscribeToStream(streamId: UUID, fromVersion: Long = 0, handler: (DomainEvent) -> Unit): Subscription
/**
* Subscribes to all events from all streams.
*
* @param fromPosition The position to start subscribing from (inclusive)
* @param handler The handler to call for each event
* @return A subscription that can be used to unsubscribe
*/
fun subscribeToAll(fromPosition: Long = 0, handler: (DomainEvent) -> Unit): Subscription
}
/**
* Interface for a subscription to an event stream.
*/
interface Subscription {
/**
* Unsubscribes from the event stream.
*/
fun unsubscribe()
/**
* Checks if the subscription is active.
*
* @return true if the subscription is active, false otherwise
*/
fun isActive(): Boolean
}
/**
* Exception thrown when there is a concurrency conflict in the event store.
*/
class ConcurrencyException(message: String) : RuntimeException(message)