7.9 KiB
Architekturleitlinien
Dieses Dokument beschreibt die technische Architektur des Projekts. Es dient als Referenz für die Entwicklung und wird kontinuierlich erweitert.
1. Schichtenmodell (Layered Architecture)
Die Anwendung ist in drei strikt getrennte Layer unterteilt:
UI layer (src/UI)
- Verantwortung: Präsentation, Handling von User-Input, API-Endpunkte, CLI-Commands.
- Struktur: Folgt einer domänenorientierten Struktur
src/UI/{Module}/{Interface}/{Feature}/...(z.B.src/UI/Sales/Http/OrderController.php), um maximale Symmetrie zu den anderen Layern zu gewährleisten. - Regel: Darf ausschließlich die Logic-Layer aufrufen. Ein direkter Zugriff auf die Data-Layer ist untersagt.
Logic Layer (src/Logic)
- Verantwortung: Implementierung der Geschäftslogik und Orchestrierung von Prozessen.
- Komponenten:
- UseCases / Workflows: Repräsentieren eine spezifische Geschäftsaktion (z.B.
CreateUserUseCase). Nutzen DTOs für den Datentransfer. - BusinessQueries: Spezifische Abfragen für geschäftsrelevante Daten.
- Manager: Orchestratoren, die z.B. Caching-Strategien implementieren und zwischen verschiedenen Providern/Processoren vermitteln.
- Models: Kernlogik-Objekte zur internen Verarbeitung innerhalb der Logic Layer.
- UseCases / Workflows: Repräsentieren eine spezifische Geschäftsaktion (z.B.
- Regel: Ist unabhängig von der UI-Layer und definiert die Anforderungen an die Data-Layer über Interfaces.
Data Layer (src/Data)
- Verantwortung: Persistenz, Datenabruf und Kommunikation mit externen Systemen.
- Struktur: Spiegelt exakt die Verzeichnisstruktur der Logic Layer wider (
src/Data/{Module}/{Feature}/...), um eine konsistente Auffindbarkeit zwischen Domänenlogik und technischer Implementierung zu gewährleisten. - Komponenten:
- Repositories: Zugriff auf Datenbankentitäten.
- Entities: Domain-Modelle für die Persistenz (spiegeln DB-Schema).
- Provider / Processor Interfaces: Definieren den Datenaustausch mit der Logic-Layer.
- Mapper: Transformation zwischen Entity und Business Model.
- Regel: Kennt keine Geschäftslogik und ist nur für die Bereitstellung/Speicherung von Daten zuständig.
2. Datenfluss & Kommunikation
Flussrichtung
UI Layer \rightarrow Logic Layer \rightarrow Data Layer
Kommunikationsregeln
- Eintrittspunkt: Die UI-Layer ruft immer einen UseCase, Workflow oder eine BusinessQuery in der Logic-Layer auf.
- Orchestrierung: Manager in der Logic-Layer organisieren den Zugriff (z.B. Cache-Check) und delegieren die eigentliche Arbeit an Provider- oder Processor-Interfaces der Data-Layer.
- Entkopplung: Die Logic-Layer sollte idealerweise gegen Interfaces der Data-Layer programmieren, um die Austauschbarkeit der Datenquelle zu gewährleisten.
3. Validierungsstrategie
Das Prinzip lautet: Jeder Layer validiert das, was er in seinem Kontext validieren kann.
- UI Layer: Syntaktische Validierung (z. B. Format, Pflichtfelder, Typen). Ziel ist es, ungültigen Input so früh wie möglich abzufangen.
- Logic Layer: Semantische/Business-Validierung (z. B. Logik-Checks gegen Geschäftsregeln, Berechtigungen).
- Data Layer: Technische Integrität (z. B. Unique-Constraints der Datenbank, korrekte Datentypen in der Persistenzschicht).
4. Fehlerbehandlung & Exceptions
Die Fehlerbehandlung folgt einem strikten Trennungsprinzip zwischen Domain-Logik und Präsentationsschicht.
Domain Exceptions
In der Logic Layer werden spezifische Domain-Exceptions geworfen (z. B. UserNotFoundException, InsufficientFundsException). Diese Exceptions beschreiben das was des Fehlers, nicht die technische Umsetzung.
Zentralisierte Fehlerübersetzung
Die UI Layer übernimmt die Übersetzung dieser Exceptions in benutzerfreundliche Antworten:
- Es wird ein zentraler Exception-Subscriber/Listener eingesetzt, um
try-catch-Blöcke in den Controllern zu vermeiden. - Dieser Subscriber fängt die Domain-Exceptions ab und wandelt sie in das entsprechende Format (z.B. HTTP 404 für
NotFoundException, HTTP 400 für Business-Fehler) um.
5. Asynchrone Kommunikation (Message Bus)
Zur Entkopplung zeitintensiver Prozesse wird ein Message-Bus eingesetzt. Dabei gilt folgende Struktur zur Vermeidung von Framework-Abhängigkeiten in der Logikschicht:
Messagen & Dispatching
- Messages: Liegen in
src/Logic, da sie eine geschäftliche Absicht (Business Intent) repräsentieren. - Dispatcher Entkopplung: Die Logic Layer nutzt ein eigenes Interface (z. B.
EventPublisherInterface), um Nachrichten zu versenden. Die technische Implementierung dieses Interfaces erfolgt außerhalb der Logikschicht (Framework-Bridge), sodass die Business-Logik unabhängig vom Symfony Messenger bleibt.
Message Handler
- Ort: Message-Handler befinden sich in der UI Layer.
- Rolle: Da ein asynchroner Nachrichteneingang ein externer Eintrittspunkt ist, fungiert der Handler als Adapter. Er nimmt die Message entgegen und delegiert die eigentliche Verarbeitung an einen entsprechenden UseCase oder Workflow in der Logic Layer.
6. Teststrategie
Um eine hohe Codequalität und Wartbarkeit zu gewährleisten, wird eine pyramidale Teststrategie verfolgt:
Unit Tests (Logic Layer)
- Fokus: Reine Geschäftslogik, Models, UseCases.
- Regel: Diese Tests dürfen keine echte Datenbank oder externe APIs nutzen. Abhängigkeiten zur Data Layer werden zwingend durch Mocks/Doubles der Interfaces ersetzt.
- Ziel: Schnelle Ausführung und vollständige Abdeckung der Edge-Cases in der Business-Logik.
Integration Tests (Data & UI Layer)
- Fokus: Korrekte Persistenz (Repositories, Processor) und korrekte Endpunkt-Konfiguration (Controller, Handler).
- Regel: Nutzen eine echte Test-Datenbank oder einen In-Memory-Speicher. Hier wird geprüft, ob die Kommunikation zwischen den Schichten und zum Framework funktioniert.
Functional / E2E Tests
- Fokus: Durchlauf kompletter Business-Szenarien von der UI bis zur Data Layer.
7. Logging & Observability
Für das System-Logging wird der PSR-3 Standard verwendet:
- Standard: In allen Layern ist die direkte Verwendung des
Psr\Log\LoggerInterfacezulässig. - Entkopplung: Da es sich um ein Interface handelt, bleibt die Business-Logik unabhängig von der konkreten Implementierung (z.B. Monolog).
- Konfiguration: Die Steuerung (Kanäle, Log-Level, Speicherorte) erfolgt rein über die Framework-Konfiguration, nicht im Code.
8. Komponenten-Definitionen
8. Security & Autorisierung
Die Absicherung der Anwendung erfolgt auf drei Ebenen:
1. Authentifizierung
Die Identitätsprüfung (Authentication) wird primär über die Framework-Infrastruktur in der UI Layer gelöst (z.B. JWT, Session), da dies ein technisches Anliegen darstellt.
2. Grobkörnige Autorisierung
Die Prüfung allgemeiner Zugriffsrechte basierend auf Rollen (z.B. ROLE_ADMIN) erfolgt ebenfalls in der UI Layer direkt an den Controllern oder Handlern mittels Framework-Annotationen/Attributen.
3. Feinkörnige / Business-Autorisierung
Für objektspezifische Berechtigungen (z. B. "Darf dieser User dieses Dokument bearbeiten?") wird folgendes Muster angewendet:
- UI Layer: Einsatz von Symfony Voters, die als Adapter fungieren.
- Logic Layer: Die eigentliche Entscheidungsgrundlage liegt in einem
PermissionServiceoder einerBusinessQuery. Der Voter ruft diesen Service auf, um eine Entscheidung basierend auf Business-Regeln zu treffen. - Ziel: Die fachlichen Berechtigungsregeln bleiben unabhängig vom Framework und zentral in der Logic Layer gesammelt.
9. Komponenten-Definitionen
| Komponente | Ort | Zweck |
|---|---|---|
| UseCase / Workflow | src/Logic |
Einzelschrittliche Geschäftsoperation. |
| BusinessQuery | src/Logic |
Funktionale Abfrage von Geschäftsdaten. |
| Manager | src/Logic |
Cache-Steuerung und Koordination von Providern. |
| Provider | src/Data |
Bereitstellung von Daten (Read). |
| Processor | src/Data |
Verarbeitung/Persistierung von Daten (Write). |