Files
4plants/Doku/architektur.md
T
2026-06-17 15:50:21 +00:00

7.5 KiB

🌿 Architektur-Dokumentation: Gartenprojekt (Symfony)

1. Vision & Kernprinzipien

Das Ziel dieser Architektur ist eine strikte Trennung zwischen technischer Infrastruktur, Geschäftslogik und den Liefermechanismen. Wir verfolgen einen Ansatz, der an Clean Architecture und Hexagonal Architecture angelehnt ist.

Grundregeln:

  • Unidirektionaler Fluss: UI \rightarrow Logic \rightarrow Data. Ein Layer darf niemals Informationen aus einem übergeordneten Layer importieren.
  • Dependency Inversion: Die Logic-Schicht definiert die Anforderungen (Interfaces). Die Data-Schicht implementiert diese. Die Logik ist somit vollständig unabhängig von der Datenbank-Technologie oder externen APIs.
  • Model-Zentrierung: Das Model ist das Herzstück der Applikation. Es ist ein anämisches POPO (Plain Old PHP Object) und dient als primärer Datenträger zwischen den Schichten.
  • Atomarität: Business-Operationen sind atomar. Entweder alles wird gespeichert oder nichts (Transaction Management via TransactionManagerInterface).

2. Die Schichtenarchitektur

🟢 UI Layer (Delivery Mechanisms)

Die UI-Schicht ist die dünne Eintrittspforte. Sie besitzt keine Geschäftslogik.

  • Einstiegspunkte: Http (Controller), Console (Commands), Queue (MessageHandlers).
  • Verantwortlichkeiten:
    • Mapping von Input auf DTOs.
    • Syntaktische Validierung via Symfony Constraints am DTO.
    • Grobe Autorisierungsprüfung (Rollen-basiert).
    • Aufruf des entsprechenden UseCase.

🔵 Logic Layer (Business Core)

Hier wird definiert, was das System tut. Die Logik ist in Orchestrierung und zustandslose Fachlogik unterteilt.

A. Orchestrierung & State

  • UseCase: Der Dirigent eines Business-Prozesses. Er koordiniert: Authorization \rightarrow Validation \rightarrow Calculation \rightarrow Save. Er steuert die Transaktionsgrenzen.
  • Manager: Zuständig für das State Management. Implementiert das Cache-Aside Pattern (Prüfung Cache vor Provider) und steuert die Invalidierung via Cache-Tags nach Schreibvorgängen.

B. Spezialisierte Logik (Stateless Services)

Zur Vermeidung von "Fat Managers" wird Fachlogik ausgelagert:

  • Calculators: Pure Functions für Berechnungen \rightarrow gibt Werte zurück.
  • Policies: Business-Regelprüfungen \rightarrow gibt boolean zurück.
  • Validators: Komplexe semantische Zustandsprüfungen \rightarrow wirft DomainException.
  • Strategies: Kapselung austauschbarer Algorithmen.

C. Domain Objekte

  • Models: Primäre Datencontainer (z.B. GardenPlan). Anämisch und unabhängig von der DB.
  • DTOs: Transportobjekte zwischen UI und Logic.
  • Domain Events: Dünne Ereignisse, die manuell im UseCase nach erfolgreichem Commit getriggert werden.

🔴 Data Layer (Infrastructure)

Die technische Realisierung. Alles hier ist austauschbar, solange die Interfaces der Logic-Schicht erfüllt werden.

  • Provider / Processor: Implementierungen der Interfaces (Provider = Lesen | Processor = Schreiben).
  • Entities: Technische Repräsentationen für Doctrine (z.B. GardenPlanEntity).
  • Mappers: Explizite Klassen, die zwischen Entity \leftrightarrow Model transformieren (KI-generiert/manuell).

3. Technischer Workflow & Pipeline

Der Schreib-Pfad (Write Flow)

UI \rightarrow DTO \rightarrow UseCase (Start Transaction) \rightarrow Auth Check \rightarrow Validator \rightarrow Policy \rightarrow Calculator \rightarrow Manager \rightarrow Processor \rightarrow Mapper \rightarrow Entity \rightarrow DB \rightarrow Commit \rightarrow Trigger Events.

Der Lese-Pfad (Read Flow)

UI \rightarrow UseCase \rightarrow Manager (Cache check) \rightarrow Provider Interface \rightarrow Implementation \rightarrow Mapper \rightarrow Model \rightarrow UI.


4. Querschnittsfunktionen

Dependency Injection & Composition Root

Um eine strikte Entkopplung zu gewährleisten, wird die Logic-Schicht niemals direkt auf konkrete Implementierungen referenzieren (kein hartcodiertes #[Autowire(service: ...)]).

  • Implicit Autowiring: Bei einer einzigen Implementierung pro Interface nutzt Symfony das Standard-Autowiring.
  • Composition Root: Die services.yaml fungiert als zentrale Konfigurationsinstanz, in der Interfaces auf konkrete Implementierungen gemappt werden (Alias/Bind), um die Infrastruktur von außen steuerbar zu machen.

Fehlermanagement & Exception-Handling

Ein zentrales System mappt fachliche Fehler auf HTTP-Standards:

  • Hierarchie: Alle Fachfehler erben von einer Basis-DomainException.
  • Mapping: Ein Symfony ExceptionListener fängt diese ab und mappt sie auf Statuscodes:
    • ResourceNotFoundException \rightarrow 404
    • AccessDeniedException \rightarrow 403
    • BusinessRuleViolationException \rightarrow 422/400
  • Format: Die Antwort erfolgt im RFC 7807 (Problem Details for HTTP APIs) Format, um dem Frontend präzise, maschinenlesbare Fehler zu liefern.

Transaktionssteuerung & Asynchronität

  • Transaction Management: Abstrahiert über ein TransactionManagerInterface.
  • Messenger: Outbound-Nachrichten werden erst nach erfolgreichem DB-Commit versendet, um inkonsistente Benachrichtigungen ("Ghost Notifications") zu vermeiden.

5. Namensmusterkatalog

Komponente Muster Beispiel
Model [Entity] GardenPlan
Entity [Entity]Entity GardenPlanEntity
UseCase [Action][Entity]UseCase CreateGardenPlanUseCase
Manager [Entity]Manager GardenPlanManager
Calculator [Topic]Calculator SpacingCalculator
Policy [Rule]Policy CompatibilityPolicy
Validator [Entity]Validator GardenLayoutValidator
Provider Interface [Entity]ProviderInterface GardenPlanProviderInterface
Processor Interface [Entity]ProcessorInterface GardenPlanProcessorInterface
Mapper [Src]To[Tgt]Mapper GardenPlanEntityToModelMapper
DTO [Action][Entity]Dto UpdateGardenPlanDto

6. Ordnerstruktur (Hybrid-Feature Ansatz)

src/
├── UI/
│   ├── Http/Controller/[Feature]/      # z.B. /Planning/GardenPlanController.php
│   ├── Console/Command/[Feature]/     # z.B. /Irrigation/StartWateringCommand.php
│   └── Queue/MessageHandler/[Feature]/ # z.B. /Notification/SendMailHandler.php
│
├── Logic/
│   ├── UseCase/[Feature]/              # z.B. /Planning/CreateGardenPlanUseCase.php
│   ├── Manager/[Feature]/              # z.B. /Planning/GardenPlanManager.php
│   ├── Domain/
│   │   ├── Model/[Feature]/            # z.B. /Planning/GardenPlan.php
│   │   ├── DTO/[Feature]/             # z.B. /Planning/UpdatePlanDto.php
│   │   └── Service/[Feature]/          # Calculator, Policy, Validator, Strategy
│   └── InfrastructureInterface/        # Provider & Processor Interfaces
│
├── Data/
│   ├── Doctrine/
│   │   ├── Entity/[Feature]/           # z.B. /Planning/GardenPlanEntity.php
│   │   └── Mapping/[Feature]/          # z.B. /Planning/GardenPlanMapper.php
│   └── Implementation/
│       ├── Provider/[Feature]/         # Realisierung der Interfaces
│       └── Processor/[Feature]/        # Realisierung der Interfaces