Initial commit: Docker infrastructure for fullstack Vollversammlung app

This commit is contained in:
2026-06-28 15:37:48 +02:00
commit 2960855bca
21 changed files with 1434 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
# 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`).