tooling: make .junie/.gemini docs-first (remove legacy guidelines)

This commit is contained in:
2026-01-13 14:32:49 +01:00
parent 696c2e0bd8
commit ff0e1a36cc
66 changed files with 347 additions and 8923 deletions
@@ -0,0 +1,30 @@
# ADR-0000: Vorlage für Architekturentscheidungsaufzeichnungen
## Status
[Vorgeschlagen | Akzeptiert | Veraltet | Ersetzt]
Falls sie ersetzt, fügen Sie einen Verweis auf die neue ADR ein: `[ADR-XXX](XXX-filename.md)`
## Kontext
Beschreiben Sie den Kontext und die Problemstellung, z. B. in freier Form mit zwei bis drei Sätzen. Sie können das
Problem auch in Form einer Frage formulieren.
## Entscheidung
Beschreiben Sie die getroffene Entscheidung.
## Konsequenzen
Beschreiben Sie den resultierenden Kontext nach Anwendung der Entscheidung. Alle Konsequenzen sollten hier aufgeführt
werden, nicht nur die "positiven". Eine bestimmte Entscheidung kann positive, negative und neutrale Konsequenzen haben,
die alle das Team und das Projekt in der Zukunft beeinflussen.
## Betrachtete Alternativen
Welche anderen Optionen wurden in Betracht gezogen und warum wurden sie nicht gewählt?
## Referenzen
- [Link zu relevanter Dokumentation, Diskussionen usw.]
@@ -0,0 +1,75 @@
# ADR-0001: Modulare Architektur
## Status
Akzeptiert
## Kontext
Das Meldestelle-System wurde ursprünglich als monolithische Anwendung entwickelt. Mit zunehmender Komplexität und Größe
des Systems traten mehrere Herausforderungen auf:
1. Der Quellcode wurde schwer zu warten und zu verstehen
2. Entwicklungsteams mussten sich eng koordinieren, was die Entwicklung verlangsamte
3. Die gesamte Anwendung musste skaliert werden, auch wenn nur bestimmte Teile mehr Ressourcen benötigten
4. Technologieentscheidungen wurden durch die monolithische Architektur eingeschränkt
Das Team musste entscheiden, ob es mit dem monolithischen Ansatz fortfahren oder zu einer modularenen Architektur
migrieren sollte.
## Entscheidung
Wir haben uns entschieden, von einer monolithischen Struktur zu einer modularen Architektur zu migrieren und das System
in die folgenden Module zu organisieren:
- **core**: Gemeinsame Kernkomponenten
- **masterdata**: Stammdatenverwaltung
- **members**: Mitgliederverwaltung
- **horses**: Pferderegistrierung
- **events**: Veranstaltungsverwaltung
- **infrastructure**: Gemeinsame Infrastrukturkomponenten
- **client**: Client-Anwendungen
Jedes Domänenmodul (masterdata, members, horses, events) folgt einem Clean-Architecture-Ansatz mit separaten API-,
Anwendung-, Domänen-, Infrastruktur- und Service-Schichten.
## Konsequenzen
### Positive
- **Verbesserte Wartbarkeit**: Kleinere, fokussierte Module sind leichter zu verstehen und zu warten
- **Unabhängige Entwicklung**: Teams können an verschiedenen Modulen mit minimaler Koordination arbeiten
- **Selektive Skalierung**: Einzelne Module können basierend auf ihren spezifischen Anforderungen skaliert werden
- **Technologieflexibilität**: Verschiedene Module können je nach Bedarf unterschiedliche Technologien verwenden
- **Klare Grenzen**: Domänengrenzen sind explizit definiert, was die konzeptionelle Integrität des Systems verbessert
### Negative
- **Erhöhte Komplexität**: Die Gesamtsystemarchitektur ist komplexer
- **Deployment-Overhead**: Mehr Komponenten müssen bereitgestellt und verwaltet werden
- **Leistungsüberlegungen**: Modulübergreifende Kommunikation fügt Latenz hinzu
- **Migrationsaufwand**: Erheblicher Aufwand erforderlich, um von der monolithischen Struktur zu migrieren
### Neutral
- **Teamorganisation**: Teams müssen um Module statt um Features herum organisiert werden
- **Dokumentationsbedarf**: Umfassendere Dokumentation ist erforderlich, um das System als Ganzes zu verstehen
## Betrachtete Alternativen
### Erweiterter Monolith
Wir haben in Betracht gezogen, die interne Struktur des Monolithen mit besseren Modulgrenzen zu verbessern, ihn aber als
eine einzige bereitstellbare Einheit zu behalten. Dies wäre einfacher bereitzustellen gewesen, hätte aber die Probleme
mit der Skalierung und Technologieflexibilität nicht gelöst.
### Microservices
Wir haben einen feingranularen Microservices-Ansatz mit vielen kleineren Diensten in Betracht gezogen. Dies hätte
maximale Flexibilität geboten, aber für unsere aktuellen Bedürfnisse übermäßige Komplexität und betrieblichen Overhead
eingeführt.
## Referenzen
- [Modular Monoliths von Simon Brown](https://meldestelle-pro.youtrack.cloud/api/files/526-8?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTh8QldrSXd1MHoyUlE1T3lZSjBDNVh4Ry1zcGZZM1lWSlE0VXN2M2FQSXNDbw0K&updated=1762338956551)
- [Clean Architecture von Robert C. Martin](https://meldestelle-pro.youtrack.cloud/api/files/526-10?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTEwfF9XbVdSakVpSW5HV1VjalY3UjhCMGFub2NIQXdPTUkyM3FFTnNTdGNIRmsNCg&updated=1762339225451)
@@ -0,0 +1,78 @@
# ADR-0002: Domain-Driven Design
## Status
Akzeptiert
## Kontext
Mit der Weiterentwicklung des Meldestelle-Systems zur Bewältigung komplexer Geschäftsregeln für die Verwaltung von
Reitsportveranstaltungen standen wir vor folgenden Herausforderungen:
1. Aufrechterhaltung einer klaren Trennung zwischen Geschäftslogik und technischen Belangen
2. Sicherstellung, dass das System das Verständnis der Domänenexperten vom Problemraum genau widerspiegelt
3. Schaffung einer gemeinsamen Sprache zwischen technischen und nicht-technischen Stakeholdern
4. Organisation des Codes in einer Weise, die die Geschäftsdomänen widerspiegelt
Wir benötigten einen architektonischen Ansatz, der diese Herausforderungen adressiert und eine solide Grundlage für die
in [ADR-0001](0001-modular-architecture-de.md) beschriebene modulare Architektur bietet.
## Entscheidung
Wir haben uns entschieden, Domain-Driven Design (DDD)-Prinzipien für die Organisation unseres Quellcodes und die
Gestaltung unseres Systems zu übernehmen. Dies umfasst:
1. **Ubiquitäre Sprache**: Entwicklung einer gemeinsamen Sprache, die von Domänenexperten und Entwicklern geteilt wird
2. **Bounded Contexts**: Definition expliziter Grenzen zwischen verschiedenen Domänenbereichen (masterdata, members, horses, events)
3. **Schichtenarchitektur**: Organisation jedes Domänenmoduls in Schichten:
- Domänenschicht: Enthält Domänenmodelle, Entitäten, Wertobjekte und Domänendienste
- Anwendungsschicht: Enthält Anwendungsdienste, Anwendungsfälle und Befehls-/Abfragehandler
- Infrastrukturschicht: Enthält technische Implementierungen von Repositories, Messaging usw.
- API-Schicht: Definiert die Schnittstellen für die Interaktion mit der Domäne
4. **Aggregate**: Identifizierung von Aggregat-Roots, die Konsistenzgrenzen aufrechterhalten
5. **Repositories**: Verwendung des Repository-Musters zur Abstraktion des Datenzugriffs
6. **Domänen-Events**: Verwendung von Events zur Kommunikation zwischen Bounded Contexts
## Konsequenzen
### Positive
- **Business-Technologie-Ausrichtung**: Die Codestruktur spiegelt direkt die Geschäftsdomänen wider
- **Verbesserte Kommunikation**: Ubiquitäre Sprache erleichtert die Kommunikation zwischen technischen und nicht-technischen Stakeholdern
- **Wartbarkeit**: Klare Trennung der Belange macht den Code leichter zu warten
- **Testbarkeit**: Domänenlogik kann unabhängig von Infrastrukturbelangen getestet werden
- **Flexibilität**: Änderungen in einem Bounded Context haben minimale Auswirkungen auf andere
### Negative
- **Lernkurve**: DDD-Konzepte erfordern Zeit, um sie richtig zu erlernen und anzuwenden
- **Initialer Entwicklungsaufwand**: Mehr Vorabdesign und Diskussion ist erforderlich
- **Potenzielle Überentwicklung**: Risiko, komplexe DDD-Muster anzuwenden, wo einfachere Lösungen ausreichen würden
### Neutral
- **Teamorganisation**: Teams benötigen Domänenwissen sowie technische Fähigkeiten
- **Dokumentationsbedarf**: Domänenmodelle und Bounded Contexts müssen gut dokumentiert sein
## Betrachtete Alternativen
### Transaction Script Pattern
Wir haben die Verwendung eines einfacheren Transaction Script Patterns in Betracht gezogen, bei dem die Geschäftslogik
um Prozeduren statt um Domänenobjekte organisiert ist. Dies wäre anfänglich einfacher zu implementieren gewesen, wäre
aber mit zunehmender Komplexität der Geschäftslogik schwieriger zu warten geworden.
### Anemic Domain Model
Wir haben die Verwendung eines anämischen Domänenmodells in Betracht gezogen, bei dem Domänenobjekte einfache
Datencontainer sind und die Geschäftslogik in separaten Serviceklassen liegt. Dies wäre für Entwickler mit
CRUD-basiertem Hintergrund vertrauter gewesen, hätte aber nicht die Vorteile der Kapselung und der reichhaltigen
Domänenmodellierung geboten.
## Referenzen
- [Domain-Driven Design von Eric Evans](https://meldestelle-pro.youtrack.cloud/api/files/526-11?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTExfE9KWGJodXhlT0Q0UEdYREpfNllaV1RXakU4YUZYbXZJb1JIdjJDVWVnZkUNCg&updated=1762339700786)
- [Implementing Domain-Driven Design von Vaughn Vernon](https://meldestelle-pro.youtrack.cloud/api/files/526-14?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTE0fEx6NXJCT2NrMFNWMHRfc1pIbVRTc04xQ1Q2OEtEdzdMc1djaTNIMmRCNFENCg&updated=1762340142201)
- [Clean Architecture von Robert C. Martin](https://meldestelle-pro.youtrack.cloud/api/files/526-10?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTEwfF9XbVdSakVpSW5HV1VjalY3UjhCMGFub2NIQXdPTUkyM3FFTnNTdGNIRmsNCg&updated=1762339225451)
@@ -0,0 +1,91 @@
# ADR-0003: Microservices-Architektur
## Status
Akzeptiert
## Kontext
Nach der Entscheidung, eine modulare Architektur ([ADR-0001](0001-modular-architecture-de.md)) und Domain-Driven
Design ([ADR-0002](0002-domain-driven-design-de.md)) zu übernehmen, mussten wir die Deployment-Strategie für unsere
Module festlegen. Zu den wichtigsten Überlegungen gehörten:
1. Unabhängige Skalierbarkeit verschiedener Teile des Systems
2. Deployment-Unabhängigkeit, um Teams zu ermöglichen, Änderungen ohne Koordination mit anderen Teams zu veröffentlichen
3. Technologieunabhängigkeit, um verschiedenen Diensten die Verwendung unterschiedlicher Technologien nach Bedarf zu
ermöglichen
4. Resilienz, um sicherzustellen, dass Ausfälle in einem Teil des Systems nicht das gesamte System beeinträchtigen
5. Klare Zuständigkeitsgrenzen, die mit den Team-Verantwortlichkeiten übereinstimmen
## Entscheidung
Wir haben uns entschieden, eine Microservices-Architektur zu implementieren, bei der jedes Domänenmodul als separater
Dienst bereitgestellt wird:
- **masterdata-service**: Verwaltet Stammdaten wie Standorte, Disziplinen usw.
- **members-service**: Verwaltet Mitgliederregistrierung und -profile
- **horses-service**: Verwaltet Pferderegistrierung und -informationen
- **events-service**: Verwaltet Veranstaltungserstellung, -planung und -anmeldungen
Jeder Dienst:
- Hat sein eigenes Datenbankschema
- Ist unabhängig bereitstellbar
- Kommuniziert mit anderen Diensten über klar definierte APIs und nachrichtenbasierte Kommunikation
- Ist für seine eigene Domänenlogik gemäß DDD-Prinzipien verantwortlich
Wir haben auch unterstützende Infrastrukturdienste implementiert:
- **gateway**: API-Gateway für Routing und Authentifizierung
- **auth**: Authentifizierung- und Autorisierungsdienst (Keycloak)
- **cache**: Caching-Dienst (Redis)
- **messaging**: Message Broker für die Kommunikation zwischen Diensten (Kafka)
- **monitoring**: Überwachung- und Beobachtbarkeitsdienste
## Konsequenzen
### Positive
- **Unabhängige Skalierbarkeit**: Jeder Dienst kann basierend auf seinen spezifischen Lastanforderungen skaliert werden
- **Deployment-Unabhängigkeit**: Teams können Änderungen an ihren Diensten bereitstellen, ohne sich mit anderen Teams
abstimmen zu müssen
- **Technologieflexibilität**: Verschiedene Dienste können je nach Bedarf unterschiedliche Technologien verwenden
- **Resilienz**: Ausfälle in einem Dienst beeinträchtigen nicht unbedingt andere
- **Klare Zuständigkeit**: Jeder Dienst hat klare Zuständigkeitsgrenzen, die mit den Team-Verantwortlichkeiten
übereinstimmen
- **Kleinere Codebasen**: Jeder Dienst hat eine kleinere, fokussierte Codebasis
### Negative
- **Komplexität verteilter Systeme**: Microservices bringen die Herausforderungen verteilter Systeme mit sich
- **Betrieblicher Mehraufwand**: Mehr Dienste müssen bereitgestellt, überwacht und gewartet werden
- **Herausforderungen bei der Datenkonsistenz**: Die Aufrechterhaltung der Datenkonsistenz über Dienste hinweg erfordert
sorgfältiges Design
- **Netzwerklatenz**: Die Kommunikation zwischen Diensten fügt Latenz hinzu
- **Testkomplexität**: End-to-End-Tests werden komplexer
### Neutral
- **Teamorganisation**: Teams müssen um Dienste statt um Features herum organisiert werden
- **Dokumentationsbedarf**: Dienstschnittstellen und -interaktionen müssen gut dokumentiert sein
## Betrachtete Alternativen
### Modularer Monolith
Wir haben die Implementierung eines modularen Monolithen in Betracht gezogen, bei dem alle Module als eine einzige
Anwendung bereitgestellt werden, jedoch mit klaren Modulgrenzen. Dies wäre einfacher bereitzustellen gewesen und hätte
die Herausforderungen verteilter Systeme vermieden, hätte aber nicht die Vorteile der unabhängigen Skalierbarkeit und
Bereitstellung geboten.
### Service-basierte Architektur
Wir haben eine Dienst-basierte Architektur mit weniger bzw. größeren Diensten in Betracht gezogen, die mehrere
Domänenbereiche umfassen würden. Dies hätte den betrieblichen Overhead reduziert, aber es schwieriger gemacht, klare
Domänengrenzen und unabhängige Skalierbarkeit aufrechtzuerhalten.
## Referenzen
- [Microservices von Martin Fowler](https://meldestelle-pro.youtrack.cloud/api/files/526-16?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTE2fFViVXRuTGdXcFhIcFRwdG03ZHlSZEZ5ZEc2MG5VVVB3SGJ4OUFRRG82QlENCg&updated=1762340608616)
- [Building Microservices von Sam Newman](https://meldestelle-pro.youtrack.cloud/api/files/526-17?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTE3fDdjaXJoZ0NlWlQ1MW9tZ0UwdC1fLVZEZ0pUcFF6QnNScTcxN0Z6YlVUazQNCg&updated=1762340788707)
- [Microservices Patterns von Chris Richardson](https://meldestelle-pro.youtrack.cloud/api/files/526-20?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTIwfDM5S08yMXVENmFRa1NPaEROQlR1N1Nvc0lWWUJXU0hCR1JYTVJXSDA2RGcNCg&updated=1762340989301)
@@ -0,0 +1,84 @@
# ADR-0004: Ereignisgesteuerte Kommunikation
## Status
Akzeptiert
## Kontext
Mit der Einführung einer Microservices-Architektur ([ADR-0003](0003-microservices-architecture-de.md)) mussten wir die
effektivste Art der Kommunikation zwischen den Diensten bestimmen. Zu den wichtigsten Überlegungen gehörten:
1. Lose Kopplung zwischen Diensten, um ihre Unabhängigkeit zu erhalten
2. Asynchrone Verarbeitungsfähigkeiten zur Verbesserung der Systemresilienz und Skalierbarkeit
3. Zuverlässige Kommunikation, um sicherzustellen, dass wichtige Informationen nicht verloren gehen
4. Unterstützung für komplexe Workflows, die mehrere Dienste umfassen
5. Fähigkeit, den Zustand des Systems für Audit- und Debugging-Zwecke zu rekonstruieren
## Entscheidung
Wir haben uns entschieden, ein ereignisgesteuertes Kommunikationsmuster mit Apache Kafka als Message Broker zu
implementieren. Die wichtigsten Aspekte dieses Ansatzes umfassen:
1. **Domänen-Ereignisse**: Dienste veröffentlichen Domänen-Ereignisse, wenn signifikante Zustandsänderungen auftreten
2. **Event Sourcing**: Für kritische Daten speichern wir alle Ereignisse, die zum aktuellen Zustand geführt haben
3. **Nachrichtenbasierte Kommunikation**: Dienste kommunizieren hauptsächlich über asynchrone Nachrichten
4. **Choreographie**: Komplexe Workflows werden durch Ereignis-Choreographie statt Orchestrierung implementiert
5. **Ereignis-Schema-Registry**: Wir führen eine Registry von Ereignis-Schemas durch, um Kompatibilität zu gewährleisten
Die Implementierung umfasst:
- Kafka als zentraler Message Broker
- Schema-Registry zur Verwaltung von Ereignis-Schemas
- Ereignis-Handler in jedem Dienst zur Verarbeitung von Ereignissen aus anderen Diensten
- Ereignis-Publisher in jedem Dienst zur Veröffentlichung von Domänen-Ereignissen
## Konsequenzen
### Positive
- **Lose Kopplung**: Dienste sind entkoppelt und teilen nur die Ereignis-Verträge
- **Skalierbarkeit**: Asynchrone Verarbeitung ermöglicht bessere Skalierbarkeit unter Last
- **Resilienz**: Dienste können weiter funktionieren, auch wenn andere Dienste nicht verfügbar sind
- **Audit-Trail**: Event Sourcing bietet einen vollständigen Audit-Trail aller Zustandsänderungen
- **Flexibilität**: Neue Konsumenten können hinzugefügt werden, ohne Publisher zu modifizieren
### Negative
- **Eventuelle Konsistenz**: Das System ist letztendlich konsistent, was schwer zu verstehen sein kann
- **Komplexität**: Ereignisgesteuerte Systeme sind komplexer zu entwerfen, zu implementieren und zu debuggen
- **Reihenfolgegarantien**: Die korrekte Reihenfolge von Ereignissen sicherzustellen kann herausfordernd sein
- **Idempotenz**: Dienste müssen doppelte Ereignisse korrekt behandeln
- **Lernkurve**: Entwickler müssen ereignisgesteuerte Muster und Praktiken erlernen
### Neutral
- **Überwachungsbedarf**: Umfassende Überwachung ist erforderlich, um den Ereignisfluss zu verfolgen
- **Testansatz**: Teststrategien müssen asynchrones Verhalten berücksichtigen
## Betrachtete Alternativen
### Synchrone REST-APIs
Wir haben die Verwendung synchroner REST-APIs als primären Kommunikationsmechanismus in Betracht gezogen. Dies wäre
einfacher zu implementieren und zu debuggen gewesen, hätte aber zu einer engeren Kopplung zwischen Diensten und
verringerter Resilienz geführt.
### Request-Response-Messaging
Wir haben ein Request-Response-Messaging-Muster in Betracht gezogen, bei dem Dienste Anfragen senden und auf Antworten
warten. Dies hätte einige der Vorteile asynchroner Kommunikation geboten und gleichzeitig ein vertrautes
Request-Response-Modell beibehalten, hätte aber das Publish-Subscribe-Muster nicht so effektiv unterstützt.
### GraphQL-Federation
Wir haben die Verwendung von GraphQL-Federation zur Zusammensetzung von APIs aus mehreren Diensten in Betracht gezogen.
Dies hätte eine einheitliche API für Clients geboten, hätte aber eine enge Kopplung zwischen Diensten beibehalten und
asynchrone Workflows nicht so effektiv unterstützt.
## Referenzen
- [Enterprise Integration Patterns](https://meldestelle-pro.youtrack.cloud/api/files/526-22?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTIyfGNVMDU5cXJTbi0wRDRvWngwLXhTc0RDTzZZOTZBaTFtQzBpZ3RVYjBxTVkNCg&updated=1762342095790)
- [Event-Driven Architecture von Martin Fowler](https://meldestelle-pro.youtrack.cloud/api/files/526-24?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTI0fDJsSEFZbnJzRWpCOWlkU3BIZ0ZOTDRIeDlmY0F2NUhMZklseE9WNnBhWkUNCg&updated=1762342654487)
- [Apache Kafka Dokumentation](https://kafka.apache.org/documentation/)
- [Event Sourcing Pattern](https://meldestelle-pro.youtrack.cloud/api/files/526-26?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTI2fEZURXo4SVVIbmtwcUExVFlab3BLZkVyRFlZS3B1bTFNX1ROMFR4aElBMW8NCg&updated=1762343212733)
@@ -0,0 +1,100 @@
# ADR-0005: Polyglotte Persistenz
## Status
Akzeptiert
## Kontext
Als Teil unserer Microservices-Architektur ([ADR-0003](0003-microservices-architecture-de.md)) mussten wir die am besten
geeignete Datenspeicherstrategie bestimmen. Verschiedene Teile unseres Systems haben unterschiedliche Anforderungen an
die Datenspeicherung:
1. Einige Daten erfordern starke Konsistenz und komplexe Beziehungen
2. Einige Daten müssen mit sehr geringer Latenz abgerufen werden
3. Einige Daten sind ereignisbasiert und müssen in einem Zeitreihenformat gespeichert werden
4. Verschiedene Dienste haben unterschiedliche Datenzugriffsmuster
Ein Einheitsansatz für die Datenspeicherung würde Kompromisse erzwingen, die die Leistung, Skalierbarkeit oder
Entwicklungsproduktivität beeinträchtigen könnten.
## Entscheidung
Wir haben uns entschieden, eine polyglotte Persistenzstrategie zu implementieren, die verschiedene
Datenspeichertechnologien für verschiedene Anwendungsfälle nutzt:
1. **PostgresQL**: Als primäre relationale Datenbank zur Speicherung strukturierter Daten mit komplexen Beziehungen
- Wird von allen Domänendiensten für ihre primäre Datenspeicherung verwendet
- Jeder Dienst hat sein eigenes Datenbankschema, um Isolation zu gewährleisten
2. **Redis**: Als verteilter Cache für schnellen Datenzugriff
- Wird für das Caching häufig abgerufener Daten verwendet
- Wird für die Sitzungsspeicherung verwendet
- Wird für Rate-Limiting verwendet
3. **Kafka**: Als Event-Store für Event Sourcing
- Wird zur Speicherung von Domänenereignissen für Event Sourcing verwendet
- Ermöglicht Event-Replay zum Wiederaufbau des Zustands
4. **Elasticsearch** (geplant): für Volltextsuchfunktionen
- Wird für erweiterte Suchfunktionen über mehrere Domänen hinweg verwendet werden
Jeder Dienst ist für die Verwaltung seiner eigenen Datenspeicherung verantwortlich, und Dienste dürfen nicht direkt auf
die Datenbanken anderer Dienste zugreifen.
## Konsequenzen
### Positive
- **Optimierte Leistung**: Jede Art von Daten wird in der am besten geeigneten Speichertechnologie gespeichert
- **Skalierbarkeit**: Verschiedene Speichertechnologien können unabhängig voneinander basierend auf ihren spezifischen
Anforderungen skaliert werden
- **Flexibilität**: Teams können die beste Speichertechnologie für ihre spezifischen Anwendungsfälle wählen
- **Resilienz**: Probleme mit einer Speichertechnologie beeinträchtigen nicht unbedingt andere
### Negative
- **Betriebliche Komplexität**: Mehrere Speichertechnologien müssen bereitgestellt, überwacht und gewartet werden
- **Herausforderungen bei der Datenkonsistenz**: Die Aufrechterhaltung der Konsistenz über verschiedene
Speichertechnologien hinweg erfordert sorgfältiges Design
- **Lernkurve**: Teams müssen mit mehreren Speichertechnologien vertraut sein
- **Komplexität bei Backup und Wiederherstellung**: Verschiedene Speichertechnologien haben unterschiedliche Backup- und
Wiederherstellungsverfahren
### Neutral
- **Daten-Governance**: Umfassende Daten-Governance ist über alle Speichertechnologien hinweg erforderlich
- **Überwachungsbedarf**: Jede Speichertechnologie erfordert ihren eigenen Überwachungsansatz
## Betrachtete Alternativen
### Einzelne Datenbank für alle Dienste
Wir haben die Verwendung einer einzelnen PostgresQL-Datenbank mit separaten Schemas für jeden Dienst in Betracht
gezogen. Dies hätte den Betrieb vereinfacht, hätte aber einen Single Point of Failure geschaffen und hätte es uns nicht
ermöglicht, für verschiedene Datenzugriffsmuster zu optimieren.
### Datenbank pro Dienst, gleiche Technologie
Wir haben die Verwendung von PostgresQL für alle Dienste, aber mit separaten Datenbanken in Betracht gezogen. Dies hätte
Dienstisolation geboten und gleichzeitig den Betrieb vereinfacht, hätte es uns aber nicht ermöglicht, für verschiedene
Datenzugriffsmuster zu optimieren.
### Vollständig verteilter NoSQL-Ansatz
Wir haben die Verwendung eines vollständig verteilten NoSQL-Ansatzes mit Technologien wie Cassandra oder MongoDB für die
gesamte Datenspeicherung in Betracht gezogen. Dies hätte eine ausgezeichnete Skalierbarkeit geboten, hätte aber die
Modellierung komplexer Beziehungen erschwert und hätte signifikante Änderungen an unseren Entwicklungspraktiken
erfordert.
## Referenzen
- [Polyglot Persistence von Martin Fowler](https://meldestelle-pro.youtrack.cloud/api/files/526-28?sign=MTc2MjU2MDAwMDAwMHwyLTF8NTI2LTI4fERaVkFWVmlEbVJJbTVZSFE2SWlrbmRydHNaeDdxZUFaRExpdkNxbk9wVEkNCg&updated=1762343428460)
- [PostgresQL Dokumentation](https://www.postgresql.org/docs/)
- [Redis Dokumentation](https://redis.io/documentation)
- [Apache Kafka Dokumentation](https://kafka.apache.org/documentation/)
- [Elasticsearch Dokumentation](https://www.elastic.co/docs/solutions/search)
@@ -0,0 +1,90 @@
# ADR-0006: Authentifizierung und Autorisierung mit Keycloak
## Status
Akzeptiert
## Kontext
Als Teil unserer Microservices-Architektur ([ADR-0003](0003-microservices-architecture-de.md)) benötigten wir eine
robuste und zentralisierte Lösung für Authentifizierung und Autorisierung. Zu den wichtigsten Anforderungen gehörten:
1. Single Sign-On (SSO) über alle Dienste und Anwendungen hinweg
2. Unterstützung für mehrere Authentifizierungsmethoden (Benutzername/Passwort, OAuth, SAML)
3. Feingranulare Autorisierung mit rollenbasierter Zugriffssteuerung (RBAC)
4. Benutzerverwaltungsfunktionen einschließlich Selbstregistrierung und Profilmanagement
5. Integration mit externen Identitätsanbietern
6. Sicherheits-Best-Practices einschließlich Passwortrichtlinien und Kontosperrung
7. Tokenbasierte Authentifizierung für die Kommunikation zwischen Diensten
Die Implementierung dieser Funktionen von Grund auf wäre zeitaufwändig und fehleranfällig und würde Ressourcen von
unserer Kerngeschäftsfunktionalität abziehen.
## Entscheidung
Wir haben uns entschieden, Keycloak (Version 26.4.2) als unsere Identitäts- und Zugriffsverwaltungslösung zu verwenden.
Keycloak ist eine Open-Source-Identitäts- und Zugriffsverwaltungslösung, die Folgendes bietet:
1. **Benutzerauthentifizierung**: Mehrere Authentifizierungsmethoden und -abläufe
2. **Benutzerföderation**: Integration mit LDAP, Active Directory und anderen Benutzerspeichern
3. **Identitätsvermittlung**: Integration mit externen Identitätsanbietern (Google, Facebook usw.)
4. **Single Sign-On**: Über alle Anwendungen und Dienste hinweg
5. **Feingranulare Autorisierung**: Rollen- und attributbasierte Zugriffssteuerung
6. **Benutzerverwaltung**: Selbstregistrierung, Profilmanagement, Passwortrichtlinien
7. **Tokenbasierte Authentifizierung**: JWT-Tokens für die Kommunikation zwischen Diensten
Unsere Implementierung umfasst:
- Keycloak-Server, der als containerised Dienst bereitgestellt wird
- Integration mit unserem API-Gateway für die Token-Validierung
- Client-Adapter für unsere Dienste und Anwendungen
- Benutzerdefinierte Themes und E-Mail-Vorlagen
- Rollen- und Gruppendefinitionen, die auf unser Domänenmodell abgestimmt sind
## Konsequenzen
### Positive
- **Umfassende Lösung**: Keycloak bietet eine vollständige Identitäts- und Zugriffsverwaltungslösung
- **Standards-Konformität**: Keycloak implementiert Industriestandards (OAuth 2.0, OpenID Connect, SAML)
- **Reduzierter Entwicklungsaufwand**: Wir müssen Authentifizierung und Autorisierung nicht von Grund auf implementieren
- **Sicherheit**: Keycloak folgt Sicherheits-Best-Practices und wird aktiv gewartet
- **Flexibilität**: Keycloak unterstützt mehrere Authentifizierungsmethoden und Identitätsanbieter
### Negative
- **Betriebliche Komplexität**: Keycloak fügt einen weiteren Dienst hinzu, der bereitgestellt und gewartet werden muss
- **Lernkurve**: Teams müssen Keycloak-Konzepte und APIs erlernen
- **Leistungsüberlegungen**: Die Token-Validierung fügt den Anfragen einen gewissen Overhead hinzu
- **Abhängigkeit**: Wir sind für Authentifizierung und Autorisierung von Keycloak abhängig
### Neutral
- **Konfigurationsbedarf**: Keycloak erfordert sorgfältige Konfiguration, um mit unseren Sicherheitsanforderungen
übereinzustimmen
- **Upgrade-Management**: Keycloak-Upgrades müssen sorgfältig verwaltet werden
## Betrachtete Alternativen
### Eigener Authentifizierungsdienst
Wir haben in Betracht gezogen, unseren eigenen Authentifizierungsdienst zu entwickeln. Dies hätte uns vollständige
Kontrolle über die Implementierung gegeben, hätte aber erheblichen Entwicklungsaufwand und laufende Wartung erfordert.
### Auth0
Wir haben die Verwendung von Auth0, einer kommerziellen Identity-as-a-Service (IDaaS)-Lösung, in Betracht gezogen. Auth0
hätte ähnliche Funktionen wie Keycloak mit weniger betrieblichem Overhead geboten, hätte aber laufende Kosten und
potenzielle Anbieterabhängigkeit mit sich gebracht.
### Spring Security mit JWT
Wir haben die Verwendung von Spring Security mit JWT-Tokens für Authentifizierung und Autorisierung in Betracht gezogen.
Dies hätte sich gut in unsere Spring-basierten Dienste integriert, hätte aber mehr Entwicklungsaufwand erfordert und
hätte nicht die umfassenden Identitätsverwaltungsfunktionen von Keycloak geboten.
## Referenzen
- [Keycloak Dokumentation](https://www.keycloak.org/documentation)
- [OAuth 2.0 und OpenID Connect](https://oauth.net/2/)
- [JWT (JSON Web Tokens)](https://jwt.io/)
@@ -0,0 +1,92 @@
# ADR-0007: API-Gateway-Muster
## Status
Akzeptiert
## Kontext
Mit unserer Microservices-Architektur ([ADR-0003](0003-microservices-architecture-de.md)) standen wir vor mehreren
Herausforderungen im Zusammenhang mit der Client-Service-Kommunikation:
1. Clients müssten die Standorte und Schnittstellen mehrerer Dienste kennen
2. Verschiedene Clients (Web, Desktop, Mobil) müssten mehrere Aufrufe an verschiedene Dienste tätigen
3. Authentifizierung und Autorisierung müssten konsistent über alle Dienste hinweg implementiert werden
4. Querschnittsbelange wie Rate-Limiting, Logging und Monitoring müssten in jedem Dienst implementiert werden
5. API-Versionierung und Abwärtskompatibilität müssten über alle Dienste hinweg verwaltet werden
6. Die Netzwerksicherheit wäre komplexer, wenn mehrere Dienste direkt exponiert würden
Wir benötigten eine Lösung, die die Client-Service-Kommunikation vereinfachen und gleichzeitig diese Herausforderungen
adressieren würde.
## Entscheidung
Wir haben uns entschieden, das API-Gateway-Muster mit Spring Cloud Gateway (Spring Boot) zu implementieren. Das
API-Gateway dient als einziger Eingangspunkt für alle Client-Anfragen und bietet die folgenden Funktionen:
1. **Anfrage-Routing**: Deklaratives Routing auf Basis von Prädikaten und Filtern
2. **Authentifizierung und Autorisierung**: Integration mit
Keycloak ([ADR-0006](0006-authentication-authorization-keycloak-de.md)), Validierung über JWKs; Kontext-Propagation
zu Backends
3. **Rate-Limiting**: Token-Bucket/Burst-Limits via Gateway-Filter (optional Redis-gestützt)
4. **Anfrage/Antwort-Transformation**: Manipulation von Headern/Body per Global/Gateway-Filtern
5. **Logging und Monitoring**: Micrometer/Prometheus, strukturierte Logs, verteiltes Tracing
6. **Caching**: Selektiv per Downstream oder Reverse-Proxy; Gateway-seitig per Filter möglich
7. **API-Dokumentation**: Aggregation/Weiterleitung von OpenAPI-Dokumentation
8. **Service-Discovery**: Integration mit Consul/Eureka
Unsere Implementierung umfasst:
- Eine Spring-Cloud-Gateway-Applikation (Spring Boot), containerized
- Integration mit Keycloak für Authentifizierung und Autorisierung
- Benutzerdefinierte Global/Gateway-Filter für Rate-Limiting, Logging, Monitoring
- Micrometer/Actuator für Metriken und Health
- Service-Discovery-Integration
## Konsequenzen
### Positive
- **Vereinfachte Client-Entwicklung**: Clients müssen nur mit einem einzigen Endpunkt kommunizieren
- **Konsistente Sicherheit**: Authentifizierung und Autorisierung werden konsistent gehandhabt
- **Zentralisierte Querschnittsbelange**: Rate-Limiting, Logging und Monitoring werden einmal implementiert
- **Verbesserte Sicherheit**: Interne Dienste werden nicht direkt Clients ausgesetzt
- **Flexibilität**: Das Gateway kann Anfragen und Antworten für verschiedene Clients anpassen
### Negative
- **Single Point of Failure**: Das Gateway wird zu einer kritischen Komponente, die hochverfügbar sein muss
- **Leistung-Overhead**: Anfragen durchlaufen einen zusätzlichen Netzwerk-Hop
- **Komplexität**: Das Gateway muss eine breite Palette von Funktionalitäten handhaben
- **Entwicklung-Engpass**: Änderungen am Gateway können Koordination über Teams hinweg erfordern
### Neutral
- **Deployment-Überlegungen**: Das Gateway muss angemessen bereitgestellt und skaliert werden
- **Versionierungsstrategie**: API-Versionierung muss immer noch verwaltet werden, wenn auch an einem Ort
## Betrachtete Alternativen
### Direkte Client-zu-Service-Kommunikation
Wir haben in Betracht gezogen, Clients die direkte Kommunikation mit Diensten zu ermöglichen. Dies hätte den
Netzwerk-Hop durch das Gateway eliminiert, hätte aber die Client-Entwicklung komplexer gemacht und hätte die
Implementierung von Querschnittsbelangen in jedem Dienst erfordert.
### Backend for Frontend (BFF)-Muster
Wir haben die Implementierung separater Backend for Frontend (BFF)-Dienste für jeden Client-Typ in Betracht gezogen.
Dies hätte mehr klientenspezifische Optimierungen ermöglicht, hätte aber den Entwicklungs- und Betriebsaufwand erhöht.
### Service Mesh
Wir haben die Verwendung eines Service Mesh wie Istio oder Linkerd zur Handhabung der Service-zu-Service-Kommunikation
in Betracht gezogen. Dies hätte viele der gleichen Vorteile für die Service-zu-Service-Kommunikation geboten, hätte aber
die Herausforderungen der Client-zu-Service-Kommunikation nicht so effektiv adressiert.
## Referenzen
- <https://spring.io/projects/spring-cloud-gateway>
- <https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html>
- <https://www.keycloak.org/documentation>
- <https://microservices.io/patterns/apigateway.html>
@@ -0,0 +1,99 @@
# ADR-0008: Multiplatform-Client-Anwendungen
## Status
Akzeptiert
## Kontext
Unser System benötigt Client-Anwendungen für verschiedene Benutzerrollen und Plattformen:
1. Desktop-Anwendungen für Administratoren und Veranstaltungsorganisatoren, die umfangreiche Funktionalität benötigen
2. Web-Anwendungen für Mitglieder und Pferdebesitzer, die von verschiedenen Geräten aus auf das System zugreifen müssen
3. Potenzielle zukünftige mobile Anwendungen für den Zugriff unterwegs
Die Entwicklung und Wartung separater Codebasen für jede Plattform würde erfordern:
- Doppelte Implementierung von Geschäftslogik und UI-Komponenten
- Mehrere Teams mit unterschiedlicher Plattformexpertise
- Koordination, um eine konsistente Benutzererfahrung über Plattformen hinweg zu gewährleisten
- Höhere Wartungskosten, da Funktionen und Fehlerbehebungen mehrfach implementiert werden müssten
Wir benötigten eine Lösung, die es uns ermöglicht, Code über Plattformen hinweg zu teilen und gleichzeitig auf jeder
Plattform eine native Benutzererfahrung zu bieten.
## Entscheidung
Wir haben uns entschieden, Kotlin Multiplatform und Compose Multiplatform für unsere Client-Anwendungen zu verwenden:
1. **Kotlin Multiplatform**: Ermöglicht die gemeinsame Nutzung von Geschäftslogik, Datenmodellen und API-Client-Code
über Plattformen hinweg
2. **Compose Multiplatform**: Bietet ein deklaratives UI-Framework, das auf Desktop-, Web- und mobilen Plattformen
funktioniert
Unsere Implementierung umfasst:
- **common-ui**: Gemeinsame UI-Komponenten und Geschäftslogik
- **desktop-app**: Desktop-Anwendung für Administratoren und Veranstaltungsorganisatoren
- **web-app**: Web-Anwendung für Mitglieder und Pferdebesitzer
Die Architektur folgt einem Model-View-ViewModel (MVVM)-Muster:
- **Model**: Gemeinsame Datenmodelle und Repository-Implementierungen
- **ViewModel**: Gemeinsame Geschäftslogik und Zustandsverwaltung
- **View**: Plattformspezifische UI-Implementierungen mit Compose Multiplatform
Wir verwenden einen modularen Ansatz, bei dem plattformspezifischer Code minimiert wird und der größte Teil des Codes
über Plattformen hinweg geteilt wird.
## Konsequenzen
### Positive
- **Codesharing**: Wesentliche Teile des Codes werden über Plattformen hinweg geteilt, was Duplizierung reduziert
- **Konsistente Benutzererfahrung**: UI-Komponenten und Verhalten sind über Plattformen hinweg konsistent
- **Einheitliche Sprache**: Kotlin wird für alle Plattformen verwendet, was die Entwicklung vereinfacht
- **Reduzierter Wartungsaufwand**: Fehlerbehebungen und Funktionen können einmal implementiert und über Plattformen
hinweg angewendet werden
- **Team-Effizienz**: Entwickler können mit demselben Skillset an mehreren Plattformen arbeiten
### Negative
- **Lernkurve**: Kotlin Multiplatform und Compose Multiplatform haben eine Lernkurve
- **Reife**: Compose Multiplatform entwickelt sich noch weiter, besonders für Web-Targets
- **Leistungsüberlegungen**: Es kann im Vergleich zu Plattform nativen Lösungen zu Leistungs-Overhead kommen
- **Plattformspezifische Funktionen**: Einige plattformspezifische Funktionen können schwieriger zu implementieren sein
- **Debugging-Komplexität**: Das Debugging über Plattformen hinweg kann komplexer sein
### Neutral
- **Komplexität des Build-Systems**: Das Build-System ist mit Multiplatform-Targets komplexer
- **Abhängigkeitsverwaltung**: Die Verwaltung von Abhängigkeiten über Plattformen hinweg erfordert sorgfältige
Überlegungen
## Betrachtete Alternativen
### Separate native Anwendungen
Wir haben die Entwicklung separater nativer Anwendungen für jede Plattform in Betracht gezogen (Java/JavaFX für Desktop,
JavaScript/React für Web). Dies hätte die beste Leistung und Zugriff auf Plattformfunktionen geboten, hätte aber eine
doppelte Implementierung von Geschäftslogik und UI-Komponenten erfordert.
### React Native
Wir haben die Verwendung von React Native für Mobile und Web mit einer separaten Desktop-Anwendung in Betracht gezogen.
Dies hätte Codesharing zwischen Mobile und Web ermöglicht, hätte aber immer noch eine separate Desktop-Lösung erfordert
und hätte JavaScript-Expertise erfordert.
### Flutter
Wir haben die Verwendung von Flutter für alle Plattformen in Betracht gezogen. Flutter bietet gute
plattformübergreifende Unterstützung, hätte aber das Erlernen von Dart erfordert und hätte weniger Integration mit
unseren Kotlin-basierten Backend-Diensten gehabt.
## Referenzen
- [Kotlin Multiplatform Dokumentation](https://kotlinlang.org/docs/multiplatform.html)
- [Compose Multiplatform Dokumentation](https://www.jetbrains.com/lp/compose-multiplatform/)
- [MVVM-Architekturmuster](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel)
- [Kotlin Multiplatform Mobile](https://kotlinlang.org/lp/mobile/)
@@ -0,0 +1,35 @@
# ADR-0009: Final KMP Architecture
Status: Accepted
Kontext
Wir schließen die Architektur-Entscheidungen für das Frontend als Kotlin Multiplatform (KMP) Projekt ab und bestätigen die finalen Bausteine sowie die Modulaufteilung. Die Plattformen Web (JS/WASM) und JVM/Desktop werden unterstützt.
Entscheidung
1. Plattformen: Kotlin Multiplatform mit Targets Web (JS/WASM) und JVM/Desktop.
2. Dependency Injection: Koin als DI-Framework für gemeinsame und plattformspezifische Layer.
3. Persistenz (Offline-First): SQLDelight als lokale Datenbank (Single Source of Truth), synchronisiert im Hintergrund.
4. Modulaufteilung im Frontend:
- shells: Ausführbare App-Shells (Bootstrap/Assembler, DI-Start, Plattformintegration)
- features: Vertikale Slices mit UI, Domain-Logik und Navigation pro Feature
- core: Gemeinsame Basis (design-system, domain, network, local-db, navigation)
5. Kommunikation: Features reden nicht direkt miteinander; Navigation + Shared-Domain-Modelle in core/domain.
Begründung
- KMP erlaubt maximale Codewiederverwendung über Web und JVM bei konsistentem Tooling.
- Koin bietet leichtgewichtige, idiomatische DI ohne Code-Generierung, geeignet für KMP.
- SQLDelight liefert typsichere Queries, portable Schemas und ist für Offline-First praxiserprobt.
- Die Trennung in shells/features/core fördert klare Zuständigkeiten, Testbarkeit und schrittweise Erweiterbarkeit.
Konsequenzen
- Projektstruktur und Gradle-Module folgen strikt der Aufteilung in `shells`, `features`, `core`.
- Der `apiClient` (core/network) wird via Koin als Named Binding injiziert; manuelles Setzen von Authorization-Headern ist untersagt.
- UI liest aus der lokalen Datenbank (SQLDelight); Synchronisation erfolgt über Hintergrundjobs.
Status / Nacharbeiten
- Diese ADR konsolidiert die KMP-Entscheidung und ersetzt frühere verstreute Notizen. Weitere Details (z. B. konkrete Module, Pfade) sind in `docs/ARCHITECTURE.md` dokumentiert.
+13
View File
@@ -0,0 +1,13 @@
Architecture Decision Records (ADRs)
Dieses Verzeichnis enthält Architekturentscheidungen in kurzer, überprüfbarer Form.
Namensschema: ADR-XXX-title.md mit fortlaufender Nummerierung.
- ADR-001 Koin als DI
- ADR-002 SQLDelight als Offline-DB
- ADR-003 Optimistic Locking (409) als Konfliktstrategie
- ADR-004 Freshness UI (Ampel)
- ADR-005 Core Domain & Feature Isolation
Siehe Template: ADR-000-template.md.