Initial commit: Docker infrastructure for fullstack Vollversammlung app
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
# Agents-Planung – Veranstaltungs-Tool
|
||||
|
||||
## Phase 1: Design
|
||||
|
||||
| Rolle | Aufgaben |
|
||||
|---|---|
|
||||
| **Architekt** | Systemarchitektur, Datenfluss, API-Konventionen, Auth-Fluss |
|
||||
| **Datenbank-Architekt** | Entities, Beziehungen, Indizes, Mandanten-Scoping auf DB-Ebene |
|
||||
|
||||
## Phase 2: Implementierung
|
||||
|
||||
| Rolle | Aufgaben |
|
||||
|---|---|
|
||||
| **DevOps-Coder** | docker-compose.yaml, Services, Konnektivitat |
|
||||
| **Backend-Coder** | Symfony boilerplate, Entities, CRUD-Controller, OAuth-Integration |
|
||||
| **Frontend-Coder** | React boilerplate, Router, State-Management, View-Komponenten, Statistikseite |
|
||||
|
||||
## Phase 3: Qualität
|
||||
|
||||
| Rolle | Aufgaben |
|
||||
|---|---|
|
||||
| **Tester** | Unit Tests, Functional Tests, E2E-Szenarien (Anwesenheitsprotokollierung, Mandantenisolation) |
|
||||
| **Security-Reviewer** | OAuth-Integration, Datenisolation, JWT/Session handling, SQL-Injection Check |
|
||||
| **Architekt (Review)** | Architektur-Conformance, Entwurfsentscheidungen nachprufen |
|
||||
|
||||
## Phase 4: Finale Integration
|
||||
|
||||
| Rolle | Aufgaben |
|
||||
|---|---|
|
||||
| **DevOps-Coder** | Environment-Konfiguration, Health-Checks |
|
||||
| **Tester** | Integrationstests, Gesamt-Workflow validieren |
|
||||
@@ -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`).
|
||||
@@ -0,0 +1,339 @@
|
||||
# Infrastruktur-Planung — Vollversammlung
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
1. [docker-compose.yaml – Services](#1-dockercomposeyaml--services)
|
||||
2. [Netzwerk & Volumes](#2-netzwerk--volumes)
|
||||
3. [api/ Verzeichnis – Vorbereitungen](#3-apiverzeichnis--vorbereitungen)
|
||||
4. [frontend/ Verzeichnis – Vorbereitungen](#4-frontend-verzeichnis--vorbereitungen)
|
||||
5. [Multi-Tenant Scoping – Infrastruktur-Ansatz](#6-multi-tenant-scoping--infrastruktur-ansatz)
|
||||
6. [OAuth (Vonova) – Infrastruktur](#7-oauth-vonova--konfiguration)
|
||||
7. [Lokaler Start](#8-lokaler-start)
|
||||
8. [Health Checks](#9-health-checks)
|
||||
9. [.env.example Konfigurationen](#10-envexample-konfigurationen)
|
||||
10. [Checkliste – Nächste Schritte](#11-checkliste--nächste-schritte-zur-implementierung)
|
||||
|
||||
---
|
||||
|
||||
## 1. docker-compose.yaml – Services
|
||||
|
||||
Sechs Services, alle über `vollversammlung_net` vernetzt:
|
||||
|
||||
| Service | Image | Externer Port | Internes Ziel | Rolle |
|
||||
|---------|-------|---------------|--------------|-------|
|
||||
| **postgres-db** | postgres:16-alpine | kein (intern) | :5432 | PostgreSQL-Datenbank, MandantID-gescoped |
|
||||
| **symfony-fpm** | php:8.3-fpm-alpine (custom) | kein (über nginx) | :9000 | PHP-FPM Backend-Runtime |
|
||||
| **nginx** | nginx:alpine | **8080** → :80 | Reverse Proxy, routet /api/* zu symfony-fpm, statisch zu frontend |
|
||||
| **mercure-hub** | dunglas/mercure | **3000** → :80 | Event-Streaming für Logging in Echtzeit |
|
||||
| **mailpit** | axllent/mailpit | **8025** (UI), intern :1025 (SMTP) | E-Mail Testing |
|
||||
| **vite-dev** | node:22-alpine | **5173** → :5173 | React Dev Server mit Hot Module Replacement |
|
||||
|
||||
---
|
||||
|
||||
## 2. Netzwerk & Volumes
|
||||
|
||||
### Netzwerk
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
vollversammlung_net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
Alle Services joined auf `vollversammlung_net`. Nur nginx, mercure-hub, vite-dev und mailpit haben externe Port-Mappings. postgres-db und symfony-fpm sind ausschließlich intern erreichbar.
|
||||
|
||||
### Volumes
|
||||
|
||||
**Named Volumes:**
|
||||
|
||||
| Name | Mount-Punkt (symfony-fpm) / Ziel | Zweck |
|
||||
|------|-----------------------------------|-------|
|
||||
| `pg_data` | `/var/lib/postgresql/data` (post-db) | Persistente PostgreSQL-Daten |
|
||||
| `symfony_var` | `/app/var/` | Symfony cache, logs |
|
||||
|
||||
**Bind-mounts (Development only):**
|
||||
|
||||
| Host-Pfad | Container | Mount-Pfad | Zweck |
|
||||
|-----------|-----------|-----------|-------|
|
||||
| `./api/src` | symfony-fpm | `/app/src` | Live-Coding PHP-Code |
|
||||
| `./frontend/src` | vite-dev | `/app/src` | Live-Coding React-Code |
|
||||
|
||||
---
|
||||
|
||||
## 3. api/ Verzeichnis – Vorbereitungen
|
||||
|
||||
### Dateistruktur
|
||||
|
||||
```
|
||||
api/
|
||||
├── .env.example (Commit-Sicherheit, keine Secrets)
|
||||
├── .env.local (gitignored - lokale Secrets)
|
||||
├── .dockerignore (Docker Build-Kontext filtering)
|
||||
├── composer.json (Symfony Flex setup)
|
||||
├── Dockerfile.dev (php:8.3-fpm-alpine Base)
|
||||
├── Dockerfile.prod (Multi-stage build für Produktion)
|
||||
├── docker-entrypoint.sh (Healthcheck + Init-Script)
|
||||
├── public/
|
||||
│ └── index.php (Symfony Entry Point über FPM)
|
||||
├── config/
|
||||
│ ├── packages/ (framework.yaml, mercure.yaml, doctrine.yaml etc.)
|
||||
│ └── routes/ (API Routes YAML)
|
||||
├── migrations/ (Doctrine Migration-Dateien)
|
||||
├── src/
|
||||
│ ├── Controller/ (Manuelle Controller – kein API Platform!)
|
||||
│ ├── Entity/ (Domain Entities mit MandantID-Eigenschaft)
|
||||
│ ├── Repository/ (Doctrine Repositories mit Tenant-Scoping)
|
||||
│ ├── Service/ (Business Logic Services)
|
||||
│ ├── Middleware/ (MandantId-Middleware + OAuth-Processor)
|
||||
│ └── Kernel.php
|
||||
├── templates/ (Twig Templates)
|
||||
├── var/ (cache, logs – via Volume gemountet)
|
||||
├── var/cache → symfony_var Volume
|
||||
├── var/log → symfony_var Volume
|
||||
└── bin/console (Symfony Command-Wrapper)
|
||||
```
|
||||
|
||||
### PHP-Erweiterungen (Dockerfile.dev)
|
||||
|
||||
- `pdo_pgsql` – Doctrine DBAL-Konnektivität
|
||||
- `gd` – Bildverarbeitung
|
||||
- `intl` – Internationalisierung
|
||||
- `mbregex` – Multibyte-Regex
|
||||
|
||||
---
|
||||
|
||||
## 4. frontend/ Verzeichnis – Vorbereitungen
|
||||
|
||||
### Dateistruktur
|
||||
|
||||
```
|
||||
frontend/
|
||||
├── .env.example (Commit-Sicherheit)
|
||||
├── .env.local (gitignored - lokale Secrets)
|
||||
├── .dockerignore (Build-Kontext filtering)
|
||||
├── package.json (React + Vite + TypeScript Dependencies)
|
||||
├── vite.config.ts (Dev Server + Proxy zu nginx/symfony-fpm)
|
||||
├── tsconfig.json (TypeScript Konfiguration)
|
||||
├── Dockerfile.dev (node:22-alpine Base)
|
||||
├── public/ (Statische Assets – favicon, manifest etc.)
|
||||
└── src/
|
||||
├── components/ (UI-Komponenten – z.B. Anwesenheitsliste, Statistiken)
|
||||
├── pages/ (Seiten – Dashboard, Veranstaltungsdetail etc.)
|
||||
├── stores/ (Zustandsmanagement – KEINE OAuth-Tokens!)
|
||||
├── utils/ (HTTP-Client, Auth-Helfer etc.)
|
||||
├── App.tsx (Root-Komponente)
|
||||
└── main.tsx (Entry Point)
|
||||
```
|
||||
|
||||
### Vite Proxy-Konfiguration (vite.config.ts)
|
||||
|
||||
- `/api/*` → `http://nginx:80/api/*` (Reverse-Proxy auf Symfony)
|
||||
- `/.well-known/mercure` → `http://mercure-hub:3000/.well-known/mercure`
|
||||
|
||||
Damit kommuniziert der Vite Dev Server (`localhost:5173`) nahtlos mit Backend-Services.
|
||||
|
||||
---
|
||||
|
||||
## 5. Multi-Tenant Scoping – Infrastruktur-Ansatz
|
||||
|
||||
**Kein Schema-per-Tenant.** Stattdessen Row-Level-Scoping über `mandant_id` in ALLEN Tabellen.
|
||||
|
||||
| Schicht | Mechanismus |
|
||||
|---------|-------------|
|
||||
| **Client** | MandantID per HTTP Header `X-Mandant-ID` an API senden. Token NUR in HttpOnly, Secure, SameSite=lax Cookies. |
|
||||
| **Nginx** | Forwarded `X-Mandant-ID` Header via `proxy_set_header` an symfony-fpm weiter. |
|
||||
| **Symfony Middleware** | Extrahiert MandantID aus Cookie/Header → setzt als RequestAttribute. |
|
||||
| **Doctrine Layer** | Alle Entities erben Base-Entity mit `mandant_id`. Repositories scopen automatisch `WHERE mandant_id = :mandantId`. |
|
||||
|
||||
### Security-Garantie
|
||||
|
||||
- Tenant-überschreitende Operationen technisch unmöglich ohne explizites `WithoutScope`-Attribut (standardmäßig nicht gewährt).
|
||||
- Keine email/benutzername-Felder in Personen-Entity – Identität stammt ausschließlich aus OAuth.
|
||||
|
||||
---
|
||||
|
||||
## 6. OAuth (Vonova) – Konfiguration
|
||||
|
||||
### Backend Environment Variables (.env.local api/)
|
||||
|
||||
```
|
||||
OAUTH_PROVIDER_NAME=vonova
|
||||
OAUTH_AUTHORIZATION_ENDPOINT=https://oauth.vonova.de/oauth/authorize
|
||||
OAUTH_TOKEN_ENDPOINT=https://oauth.vonova.de/oauth/token
|
||||
OAUTH_CLIENT_ID=<from Vonova admin>
|
||||
OAUTH_CLIENT_SECRET=<from Vonova admin>
|
||||
OAUTH_REDIRECT_URI=http://localhost:8080/api/oauth/callback
|
||||
OAUTH_SCOPES=read profile mandant_id
|
||||
```
|
||||
|
||||
### Frontend Environment Variables (frontend/.env.example)
|
||||
|
||||
```
|
||||
VITE_OAUTH_AUTHORIZATION_ENDPOINT=https://oauth.vonova.de/oauth/authorize
|
||||
VITE_OAUTH_TOKEN_ENDPOINT=https://oauth.vonova.de/oauth/token
|
||||
```
|
||||
|
||||
### OAuth-Flow (Kurzbeschreibung)
|
||||
|
||||
1. Frontend leitet User zu Vonova Authorization Endpoint weiter.
|
||||
2. Vonova authentifiziert User, gibt Authorisierungscode an `OAUTH_REDIRECT_URI` zurück.
|
||||
3. Backend tauscht Code gegen Access-Token am Token Endpoint ein.
|
||||
4. Backend extrahiert MandantID und Profil-Informationen aus dem Token-Payload.
|
||||
5. Backend generiert Session-Cookie (HttpOnly, Secure, SameSite=lax).
|
||||
6. Folge-Requests enthalten Cookie automatisch → authentifizierte Api-Zugriffe.
|
||||
|
||||
**Wichtig:** Tokens werden NIEMALS auf dem Client gespeichert (kein localStorage/sessionStorage).
|
||||
|
||||
---
|
||||
|
||||
## 7. Lokaler Start
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
# Projekt rootVerzeichnis:
|
||||
|
||||
# Env-Templates kopieren (keine Secrets generieren – Werte aus .env.example übernehmen):
|
||||
cp api/.env.example api/.env.local
|
||||
cp frontend/.env.example frontend/.env.local
|
||||
|
||||
# APP_SECRET und JWT-Keys in .env.local ergänzen:
|
||||
docker compose exec symfony-fpm php bin/console security:encode-password
|
||||
# → Output als APP_SECRET eintragen
|
||||
|
||||
# Mercure-JWT-Keys manuell generieren (Mindestlänge 32 Zeichen, kryptografisch sicher):
|
||||
# z.B.: openssl rand -base64 64
|
||||
```
|
||||
|
||||
### Services starten
|
||||
|
||||
```bash
|
||||
# Alle Services im Hintergrund starten:
|
||||
docker compose up -d
|
||||
|
||||
# Database-Migrations ausführen (erster Start):
|
||||
docker compose exec symfony-fpm php bin/console doctrine:migrations:migrate --no-interaction
|
||||
```
|
||||
|
||||
### Verfügbare Endpunkte
|
||||
|
||||
| URL | Service |
|
||||
|-----|---------|
|
||||
| `http://localhost:8080/` | Frontend + API (via nginx) |
|
||||
| `http://localhost:3000/` | Mercure Hub Debug Interface |
|
||||
| `http://localhost:5173/` | Vite Dev Server (Hot Reload) |
|
||||
| `http://localhost:8025/` | Mailpit E-Mail Testing UI |
|
||||
|
||||
---
|
||||
|
||||
## 8. Health Checks
|
||||
|
||||
Jeder kritische Service verfügt über einen `healthcheck` in docker-compose.yaml:
|
||||
|
||||
| Service | Check-Methode | Command |
|
||||
|---------|---------------|---------|
|
||||
| **postgres-db** | `pg_isready` | `pg_isready -U vv_admin -d vollversammlung` |
|
||||
| **mercure-hub** | HTTP-Well-Known-Path | `curl -sf http://localhost/.well-known/mercure` |
|
||||
| **symfony-fpm** | API Health Endpoint *(vom Backend-Coder zu implementieren)* | `curl -sf http://localhost:8000/api/health` |
|
||||
| **nginx** | Proxy-Pass zu symfony-fpm health | `curl -sf http://localhost:8080/api/health` |
|
||||
|
||||
---
|
||||
|
||||
## 9. .env.example Konfigurationen
|
||||
|
||||
### api/.env.example
|
||||
|
||||
```ini
|
||||
# =========================================
|
||||
# Vollversammlung – Backend Environment
|
||||
# Kopieren nach .env.local und anpassen!
|
||||
# =========================================
|
||||
|
||||
APP_ENV=dev
|
||||
APP_DEBUG=1
|
||||
APP_SECRET=<symfony secret:generate oder security:encode-password>
|
||||
|
||||
DATABASE_URL="postgresql://vv_admin:<password>@postgres-db:5432/vollversammlung?serverVersion=16&charset=utf8mb4"
|
||||
|
||||
MERCURE_PUBLISHER_JWT_KEY=<openssl rand -base64 64>
|
||||
MERCURE_SUBSCRIBER_JWT_KEY=<openssl rand -base64 64>
|
||||
MERCURE_URL=http://mercure-hub/.well-known/mercure
|
||||
MERCURE_PUBLIC_URL=http://localhost:3000/.well-known/mercure
|
||||
|
||||
MAILER_DSN=smtp://mailpit:1025
|
||||
|
||||
# =========================================
|
||||
# Vonova OAuth
|
||||
# =========================================
|
||||
OAUTH_PROVIDER_NAME=vonova
|
||||
OAUTH_AUTHORIZATION_ENDPOINT=https://oauth.vonova.de/oauth/authorize
|
||||
OAUTH_TOKEN_ENDPOINT=https://oauth.vonova.de/oauth/token
|
||||
OAUTH_CLIENT_ID=<from vonova admin>
|
||||
OAUTH_CLIENT_SECRET=<from vonova admin>
|
||||
OAUTH_REDIRECT_URI=http://localhost:8080/api/oauth/callback
|
||||
OAUTH_SCOPES=read profile mandant_id
|
||||
```
|
||||
|
||||
### frontend/.env.example
|
||||
|
||||
```ini
|
||||
# =========================================
|
||||
# Vollversammlung – Frontend Environment
|
||||
# Kopieren nach .env.local und anpassen!
|
||||
# =========================================
|
||||
|
||||
VITE_API_URL=http://localhost:8080/api
|
||||
VITE_MERCURE_URL=http://localhost:3000/.well-known/mercure
|
||||
VITE_OAUTH_AUTHORIZATION_ENDPOINT=https://oauth.vonova.de/oauth/authorize
|
||||
VITE_OAUTH_TOKEN_ENDPOINT=https://oauth.vonova.de/oauth/token
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Multi-Environment Konfiguration
|
||||
|
||||
| Variable | dev (.env.local) | uat/staging (.env.staging) | prod (.env.prod) |
|
||||
|----------|------------------|----------------------------|-------------------|
|
||||
| `APP_ENV` | `dev` | `uat` | `prod` |
|
||||
| `APP_DEBUG` | `1` | `0` | `0` |
|
||||
| `CORS_ALLOW_ORIGIN` | `http://localhost:5173` | `https://uat.company.com` | `https://www.company.com` |
|
||||
| `MAILER_DSN` | `smtp://mailpit:1025` | prod SMTP credentials | prod SMTP credentials |
|
||||
| `DATABASE_URL` | localhost via docker | externe PG-Instanz | externe PG-Instanz |
|
||||
| `MERCURE_PUBLISHER_JWT_KEY` | dev-key (openssl rand) | Vault-sekret | Vault/AWS Secrets Manager |
|
||||
| `TRUSTED_HOSTS` | `^localhost$` | `^uat\.example\.com$` | `^www\.example\.com$` |
|
||||
| `TRUSTED_PROXIES` | – | `127.0.0.1,10.0.0.0/8` | Load Balancer IPs |
|
||||
|
||||
---
|
||||
|
||||
## 11. Checkliste — Nächste Schritte zur Implementierung
|
||||
|
||||
### Infrastruktur (DevOps-Coder)
|
||||
- [ ] `docker-compose.yaml` mit allen 6 Services schreiben
|
||||
- [ ] Networks & Volumes definieren
|
||||
- [ ] Health-Checks pro Service implementieren
|
||||
- [ ] nginx Konfiguration für Proxy-Routing erstellen
|
||||
- [ ] `.env.example` in api/ und frontend/ anlegen
|
||||
- [ ] Dockerfiles (dev + prod) pro Service erstellen
|
||||
|
||||
### Backend (Backend-Coder)
|
||||
- [ ] Symfony-Projektstruktur in `api/` aufsetzen
|
||||
- [ ] `composer.json` mit Symfony Flex konfigurieren
|
||||
- [ ] Entity-Base für Multi-Tenant Scoping erstellen (`mandant_id` column)
|
||||
- [ ] Doctrine Repositories mit automatischem Tenant-Scoping implementieren
|
||||
- [ ] MandantId-Middleware schreiben (Cookie/Header → RequestAttribute)
|
||||
- [ ] Vonova OAuth-Flow implementieren (Authorization Code Grant + PKCE)
|
||||
- [ ] Session-Cookie Generation nach OAuth-Flow (HttpOnly, Secure, SameSite=lax)
|
||||
- [ ] `/api/health` Endpoint erstellen
|
||||
- [ ] Migrationen für alle Templates schreiben
|
||||
|
||||
### Frontend (Frontend-Coder)
|
||||
- [ ] React/Vite/TypeScript Setup in `frontend/`
|
||||
- [ ] OAuth Login-Flow im Browser implementieren (Authorization Code + PKCE mit redirect)
|
||||
- [ ] Auth-Stores ohne token storage (nur Cookie-basiert)
|
||||
- [ ] HTTP-Client mit MandantID-Header-Injection schreiben
|
||||
- [ ] Mercure-Client für Event-Subscription einrichten
|
||||
- [ ] Key-Pages: Dashboard, Veranstaltungsdetail, Anwesenheitsübersicht
|
||||
|
||||
---
|
||||
|
||||
*Stand: Juni 2026 — Infrastruktur-Planung Vollversammlung*
|
||||
@@ -0,0 +1,57 @@
|
||||
# Veranstaltungs-Tool – Planungsdokumentation
|
||||
|
||||
## Ziel
|
||||
Mandantenfähiges Tool zur Verwaltung von Veranstaltungen mit Anwesenheitsverwaltung und Statistik.
|
||||
|
||||
## Tech Stack
|
||||
- Backend: Symfony (manuelle Controller, keine API Platform)
|
||||
- Frontend: React
|
||||
- Datenbank: PostgreSQL
|
||||
- Logging: Mercure
|
||||
- Deployment: Docker / docker-compose
|
||||
- Auth: OAuth (extern, kein lokaler Login)
|
||||
|
||||
## Mandantenfähigkeit
|
||||
- Daten werden pro MandantID gescoped
|
||||
- Personen sind mandant-isoliert (keine Überschneidung)
|
||||
|
||||
## Veranstaltungen (CRUD via API)
|
||||
- Titel
|
||||
- Datum
|
||||
- Beschreibung
|
||||
- max_teilnehmer
|
||||
|
||||
Anlegen über: UI oder Import-API
|
||||
|
||||
## Personenverwaltung (Admin)
|
||||
- Anlegen / Entfernen über UI oder Import-API
|
||||
- Felder: vorname, nachname, geschlecht
|
||||
- Kein lokaler Login (OAuth extern)
|
||||
- Keine email / benutzername-Felder
|
||||
|
||||
## Anwesenheit
|
||||
- Manuelle Markierung im UI
|
||||
- Status: anwesend / abwesend
|
||||
- Alle Änderungen werden geloggt (wer, wann, was)
|
||||
|
||||
## Statistikseite
|
||||
- Anwesenheitszahlen pro Veranstaltung
|
||||
- Anwesenheitsquote
|
||||
- Geschlechterquote
|
||||
- Dashboard-Ansicht als separate Statistik-Seite
|
||||
|
||||
## Projektstruktur
|
||||
```
|
||||
vollversammlung/
|
||||
├── docker-compose.yaml
|
||||
├── api/ (Symfony Backend Repo)
|
||||
└── frontend/ (React Frontend Repo)
|
||||
|
||||
## Nächste Schritte
|
||||
1. Boilerplate symfony erstellen
|
||||
2. Boilerplate react erstellen
|
||||
3. Docker compose konfigurieren
|
||||
4. Datenmodelle implementieren
|
||||
5. CRUD-Endpoints entwickeln
|
||||
6. Frontend-Seiten aufbauen
|
||||
7. Statistikseite implementieren
|
||||
Reference in New Issue
Block a user