69 lines
3.5 KiB
Markdown
69 lines
3.5 KiB
Markdown
# Backend-Architektur – Veranstaltungs-Tool (Konzept)
|
||
|
||
## Ziel
|
||
Mandantenfähiges Backend mit 3 Schichten pro fachlicher Domäne und mehreren Clients/Entry-Points.
|
||
|
||
## Struktur
|
||
|
||
```
|
||
api/
|
||
├── public/index.php ← Entrypoint
|
||
└── src/
|
||
├── UI/{ClientName}/{FeatureName}/ ← pro Client + Use-Case (PascalCase, deutsch)
|
||
│ ├── Controller/ REST-Endpunkte (/api/*), Commands etc.
|
||
│ ├── Request/ Request-DTOs
|
||
│ └── Response/ Response-DTOs
|
||
├── Logic/{FeatureName}/ ← Business Rules pro Use-Case
|
||
│ ├── Manager/ Cache, Workflow, Aggregate
|
||
│ ├── Calculator/ Berechnungen (Statistiken)
|
||
│ ├── Model/ Feature-Modelle
|
||
│ ├── Provider/*ProviderInterface Interfaces für Data-Layer
|
||
│ ├── Processor/*ProcessorInterface Interface für Verarbeitungslogik
|
||
│ └── Shared/ Feature-spezifisches Shared (wenn notwendig)
|
||
├── Data/{FeatureName}/ ← Domain-Objects, DB-Zugriff pro Use-Case
|
||
│ ├── Entity/ Doctrine Entities
|
||
│ └── Repository/ Repo-Interfaces + Implementierungen
|
||
└── Shared/ ← Nur wirklich entitätsübergreifende Basics
|
||
├── BaseEntity.php
|
||
└── UuidGenerator.php
|
||
```
|
||
|
||
## Client-Namenskonvention
|
||
- `API` → REST-Schnittstelle (UI/API/*)
|
||
- `Console` → Symfony Commands (UI/Console/*)
|
||
|
||
## Feature-Namenskonvention
|
||
Use-Case-basiert, PascalCode auf Deutsch. ZB:
|
||
- `Personen` (nicht Personenliste / PersonController)
|
||
- `Veranstaltungen` (nicht VeranstaltungenIndex)
|
||
- `Anwesenheit` (nicht AnwesenheitsstatusErfassung)
|
||
|
||
Beispiel-Pfad: `UI/API/Personen/Controller/PersonenController.php`
|
||
|
||
**Model/** pro Feature – Ordner mit ggf. mehreren Models definiert die Feature-Grenze.
|
||
|
||
## Entry-Points
|
||
Mehrere Clients via Router-basierte Routing:
|
||
- `/api/*` → REST-Controller (`UI/API/{Feature}/Controller/`)
|
||
- Console → Symfony Commands (`UI/Console/{Feature}/Command/`)
|
||
- Messages → Messenger Handler
|
||
|
||
## Entscheidungen
|
||
|
||
### Provider und Processoren
|
||
**Provider** implementieren die `*ProviderInterface`. Sie rufen Daten ab – per Doctrine Repositories/Entities oder über API-Aufrufe. Das Mapping zwischen Entities und Model-Objekten erfolgt in separaten **Mapper**-Klassen, die in **Data/** liegen. Provider binden so die Data-Schicht an die Logic-Schicht.
|
||
|
||
**Processoren** funktionieren analog für schreibende Prozesse (`*ProcessorInterface`).
|
||
|
||
### Shared-Klassen
|
||
Echt entitätsbergreifende Basis-Klassen (`BaseEntity`, `UuidGenerator`) leben in `src/Shared/`. Feature-spezifisches Shared liegt innerhalb des Features, zB:
|
||
```
|
||
src/Logic/Veranstaltungsmanagement/Shared/JsonSerializer.php
|
||
```
|
||
|
||
### Multi-Tenant Scoping
|
||
Alle Repository-Queries werden per **Doctrine SQL Builder Trait** mit `mandant_id` gefiltert. Der Scope wird automatisch angehängt – sowohl lesend als auch schreibend. Tenantübergreifende Operationen sind technisch nicht möglich, da alle Repos implicit scopen. Das schützt vor unbeabsichtigten Mandanten-Überschneidungen. Bei Bedarf kann eine explizite WithoutScope-Schicht eingeführt werden.
|
||
|
||
### Dependency Injection
|
||
Nur explizit über `services.yaml`, wenn notwendig. Standardmäßig wird Auto-Wiring mit Konventionen verwendet (`*ProviderInterface`, `*ProcessorInterface`).
|