Olympus/ARCHITECTURE.md
2026-07-02 23:37:46 +02:00

477 lines
12 KiB
Markdown

# Olympus CRM Architektur
## Projektueberblick
Olympus CRM ist als mehrschichtige CRM-Anwendung aufgebaut. Die Architektur trennt klar zwischen Browser, Frontend/BFF, Backend-API und Datenbank.
Die zentrale Regel lautet:
**Der Browser kommuniziert ausschliesslich mit Athena. Athena kommuniziert serverseitig mit Hermes. Hermes kommuniziert mit PostgreSQL.**
Diese Trennung ist verbindlich, besonders fuer Authentifizierung, API-Zugriffe und spaetere Modul-Erweiterungen wie Kunden, Projekte, Lieferanten, Kontakte und Mitarbeiter.
## Systemkomponenten
### Athena: Next.js 16 Frontend
Athena liegt unter `frontend/athena` und ist das Frontend sowie die BFF-Schicht des Systems.
Aufgaben:
- rendert die Benutzeroberflaeche mit Next.js 16 App Router
- stellt eigene API-Routes unter `/api/...` bereit
- setzt und loescht das HttpOnly-Auth-Cookie
- ruft Hermes serverseitig auf
- schuetzt Seiten ueber `proxy.ts`
Der Browser darf keine Hermes-URLs direkt aufrufen.
### Hermes: FastAPI Backend
Hermes liegt unter `backend/hermes` und stellt die interne Backend-API bereit.
Aufgaben:
- validiert Requests mit Pydantic v2
- verarbeitet Fachlogik und Persistenz
- prueft JWT Bearer Tokens
- stellt REST-Endpunkte bereit
- nutzt SQLAlchemy 2.x fuer Datenbankzugriffe
- setzt keine Browser-Cookies
Hermes bleibt Cookie-frei. Authentifizierte Hermes-Endpunkte erwarten `Authorization: Bearer <jwt>`.
### PostgreSQL Datenbank
PostgreSQL ist die relationale Datenbank fuer Olympus CRM. Hermes greift ueber SQLAlchemy darauf zu.
Schemaaenderungen erfolgen ueber Alembic-Migrationen. Manuelle Datenbankeingriffe sind nur in Notfaellen zulaessig und muessen nachvollziehbar dokumentiert werden.
### Docker Compose
Die gemeinsame Docker-Compose-Konfiguration liegt im Projektroot in `docker-compose.yml`.
Sie verbindet:
- `hermes`
- `athena`
- das konfigurierte Docker-Netzwerk
- die notwendigen Runtime-Umgebungsvariablen
## BFF-Architektur
Olympus nutzt eine Backend-for-Frontend-Architektur.
Regeln:
- Browser spricht ausschliesslich mit Athena.
- Athena spricht serverseitig mit Hermes.
- Hermes setzt keine Browser-Cookies.
- Cross-Origin-Cookies werden nicht verwendet.
- Frontend-API-Zugriffe laufen ueber relative Athena-Routen wie `/api/users`.
Der Datenfluss bleibt dadurch kontrolliert, sicher und leichter hinter Reverse Proxies betreibbar.
## Authentifizierungsfluss
### Login
1. Der Browser sendet Benutzername und Passwort an Athena: `POST /api/login`.
2. Athena ruft serverseitig Hermes auf: `POST /auth/login`.
3. Hermes validiert die Zugangsdaten.
4. Hermes gibt JWT, Ablaufzeit und Benutzerdaten als JSON zurueck.
5. Athena setzt das JWT in einem HttpOnly-Cookie.
6. Der Browser wird auf eine geschuetzte Seite weitergeleitet.
Hermes setzt kein Cookie.
### Logout
1. Der Browser sendet `POST /api/logout` an Athena.
2. Athena loescht das HttpOnly-Cookie.
3. Der Benutzer wird zur Login-Seite gefuehrt.
### HttpOnly Cookie
Das Auth-Cookie wird von Athena gesetzt.
Eigenschaften:
- `HttpOnly`
- `SameSite=Lax`
- `Path=/`
- `Secure` in Produktion
- Ablaufzeit orientiert sich an der JWT-Ablaufzeit
Tokens duerfen nicht in `localStorage` oder `sessionStorage` gespeichert werden.
### JWT
Hermes erzeugt JWT Access Tokens.
Wichtige Claims:
- `sub`: Benutzername
- `exp`: Ablaufzeit
- `iat`: Ausstellungszeitpunkt
- `iss`: konfigurierter Issuer
- `type`: Token-Typ, aktuell `access`
### Issuer
Der Issuer wird ueber `JWT_ISSUER` konfiguriert. Hermes prueft den Issuer bei der Token-Validierung.
### Ablaufzeit
Die Ablaufzeit wird ueber `ACCESS_TOKEN_EXPIRE_MINUTES` konfiguriert. Athena nutzt die von Hermes gelieferte Ablaufzeit fuer das Cookie.
### `proxy.ts`
Athena schuetzt Routen ueber `frontend/athena/proxy.ts`.
Aufgaben:
- geschuetzte Bereiche ohne Cookie auf `/login` umleiten
- eingeloggte Benutzer von `/login` auf `/dashboard` umleiten
## API-Datenfluss
Standardfluss:
```text
Browser -> Athena /api/... -> Hermes -> PostgreSQL
```
Beispiel Benutzerliste:
```text
Browser
GET /api/users
Athena
GET {HERMES_INTERNAL_URL}/users
Authorization: Bearer <jwt aus HttpOnly Cookie>
Hermes
SQLAlchemy Query gegen PostgreSQL
```
Athena ist die einzige API-Oberflaeche fuer den Browser.
## Dashboard
Das Dashboard liegt in Athena unter `/dashboard` und bezieht seine Daten ueber die BFF-Route `GET /api/dashboard/summary`.
Hermes stellt dafuer `GET /dashboard/summary` bereit. Der Endpunkt ist mit `dashboard.read` geschuetzt und liefert nur Datenbloecke, fuer die der aktuelle Benutzer weitere Berechtigungen besitzt.
Beispiele:
- Kundenstatistiken nur mit `customers.read`
- Benutzerstatistiken nur mit `users.read`
- Rollenstatus nur mit `roles.read`
Nicht vorhandene Module wie Aufgaben, Tickets oder Projekte werden nicht mit Fake-Daten gefuellt. Stattdessen liefert das Dashboard leere Widgets mit klarer Meldung.
## RBAC: Rollen und Berechtigungen
Olympus verwendet ein serverseitiges RBAC-System als Grundlage fuer alle CRM-Module.
Konzepte:
- Benutzer besitzen genau eine primaere Rolle.
- Rollen besitzen mehrere Berechtigungen.
- Berechtigungen sind stabile String-Keys wie `users.read`.
- Hermes prueft Berechtigungen serverseitig ueber Dependencies.
- Athena darf Permissions fuer UI-Sichtbarkeit nutzen, aber niemals als Auth-Quelle.
Tabellen:
- `roles`
- `permissions`
- `role_permissions`
- `users.role_id`
Das alte `users.role`-Feld bleibt vorerst als Legacy-Kompatibilitaet erhalten. Neue Logik verwendet `users.role_id` und die `roles`-Beziehung.
### Standardrollen
- `administrator`
- `management`
- `sales`
- `technician`
- `support`
- `warehouse`
- `guest`
`administrator` erhaelt alle Berechtigungen. `management` erhaelt mindestens Lesezugriff auf Dashboard, Benutzer, Kunden, Projekte und Tickets. `guest` erhaelt minimal `dashboard.read`.
### Standardberechtigungen
Benutzer:
- `users.read`
- `users.create`
- `users.update`
- `users.delete`
- `users.password.update`
Rollen:
- `roles.read`
- `roles.create`
- `roles.update`
- `roles.delete`
- `roles.assign`
Kunden:
- `customers.read`
- `customers.create`
- `customers.update`
- `customers.delete`
Projekte:
- `projects.read`
- `projects.create`
- `projects.update`
- `projects.delete`
Tickets:
- `tickets.read`
- `tickets.create`
- `tickets.update`
- `tickets.delete`
Dashboard und System:
- `dashboard.read`
- `system.settings.read`
- `system.settings.update`
### Berechtigungspruefung
Zentrale Hermes-Dependencies:
- `get_current_user`
- `get_current_active_user`
- `require_permission("permission.name")`
- `require_any_permission([...])`
- `require_all_permissions([...])`
Backend-Endpunkte muessen immer selbst pruefen. Frontend-Helfer wie `hasPermission` dienen nur dazu, Buttons oder Navigation auszublenden.
### Rollen-API
Hermes:
- `GET /roles`
- `GET /roles/{id}`
- `POST /roles`
- `PUT /roles/{id}`
- `DELETE /roles/{id}`
- `PUT /roles/{id}/permissions`
- `GET /permissions`
Athena stellt entsprechende BFF-Routen unter `/api/roles`, `/api/permissions` und `/api/me` bereit.
## Benutzerverwaltung
Die Benutzerverwaltung ist das erste Enterprise-Modul und dient als Vorlage fuer weitere Module.
Funktionen:
- Benutzerliste
- Detailseite
- Erstellen
- Bearbeiten
- Loeschen
- Passwort separat aendern
- Suche, Filter, Sortierung und Pagination im Frontend
Backend-Endpunkte in Hermes:
- `GET /users`
- `GET /users/{id}`
- `POST /users`
- `PUT /users/{id}`
- `PUT /users/{id}/password`
- `DELETE /users/{id}`
Athena stellt die passenden BFF-Routen unter `/api/users` und `/api/users/[id]` bereit.
Diese Endpunkte sind per RBAC geschuetzt:
- `GET /users` und `GET /users/{id}`: `users.read`
- `POST /users`: `users.create` und fuer Rollenzuweisung `roles.assign`
- `PUT /users/{id}`: `users.update`; Rollenwechsel benoetigt `roles.assign`
- `PUT /users/{id}/password`: `users.password.update`
- `DELETE /users/{id}`: `users.delete`
### Passwortaenderung
Wenn beim Bearbeiten kein Passwort uebergeben wird, bleibt das bestehende Passwort unveraendert.
Wenn ein Passwort gesetzt wird, wird es in Hermes mit `pwdlib` neu gehasht.
### Self-Delete-Schutz
Der aktuell angemeldete Benutzer darf sich nicht selbst loeschen. Hermes verhindert dies serverseitig.
### Rollenmodell
Benutzer besitzen eine primaere RBAC-Rolle ueber `role_id`. Die Rolle bestimmt die serverseitigen Berechtigungen.
## Kundenmodul
Das Kundenmodul ist das zweite Enterprise-Modul und folgt den gleichen Grundsaetzen wie die Benutzerverwaltung:
- Hermes stellt REST-Endpunkte bereit.
- Athena proxyt diese Endpunkte ueber `/api/customers`.
- Der Browser spricht nicht direkt mit Hermes.
- Berechtigungen werden serverseitig in Hermes geprueft.
- Die UI nutzt Permissions nur fuer Sichtbarkeit und Bedienkomfort.
Hermes-Endpunkte:
- `GET /customers`
- `GET /customers/{id}`
- `POST /customers`
- `PUT /customers/{id}`
- `DELETE /customers/{id}`
- `GET /customers/{id}/contacts`
- `POST /customers/{id}/contacts`
- `PUT /customers/{id}/contacts/{contact_id}`
- `DELETE /customers/{id}/contacts/{contact_id}`
Athena-BFF-Routen:
- `GET /api/customers`
- `POST /api/customers`
- `GET /api/customers/[id]`
- `PUT /api/customers/[id]`
- `DELETE /api/customers/[id]`
- `GET /api/customers/[id]/contacts`
- `POST /api/customers/[id]/contacts`
- `PUT /api/customers/[id]/contacts/[contactId]`
- `DELETE /api/customers/[id]/contacts/[contactId]`
Tabellen:
- `customers`
- `customer_addresses`
- `customer_contacts`
Kunden-Permissions:
- `customers.read`
- `customers.create`
- `customers.update`
- `customers.delete`
Kontakte und Adressen gehoeren fachlich zum Kunden und werden aktuell ueber `customers.read` beziehungsweise `customers.update` gesteuert.
Ein Kunden-Delete entfernt aktuell den Kunden inklusive Adressen und Ansprechpartnern. Fuer spaetere Projekte oder Tickets ist ein fachlicher Loeschschutz vorzubereiten, sobald diese Module existieren.
## Verzeichnisstruktur
```text
backend/hermes
app/
api/
core/
db/
models/
repositories/
schemas/
alembic/
alembic.ini
dockerfile
pyproject.toml
frontend/athena
app/
api/
customers/
roles/
users/
components/
lib/
types/
proxy.ts
Dockerfile
package.json
docker-compose.yml
```
## Umgebungsvariablen
### Hermes
`DATABASE_URL`
: PostgreSQL-Verbindungsstring.
`SECRET_KEY`
: Signierschluessel fuer JWTs. Muss geheim bleiben.
`JWT_ISSUER`
: Erwarteter JWT-Issuer, z. B. `hermes`.
`ACCESS_TOKEN_EXPIRE_MINUTES`
: Ablaufzeit fuer Access Tokens in Minuten.
### Athena
`HERMES_INTERNAL_URL`
: Serverseitige URL, ueber die Athena Hermes erreicht.
`AUTH_COOKIE_SECURE`
: Steuert das `Secure`-Flag des Cookies. In Produktion `true`.
## Datenbankmigrationen
Olympus verwendet Alembic fuer Datenbankmigrationen.
Regeln:
- Schemaaenderungen immer ueber Alembic.
- Migrationen muessen ins Repository aufgenommen werden.
- Vor Deployment `alembic upgrade head` testen.
- Keine manuellen DB-Aenderungen ausser in Notfaellen.
Typischer Ablauf:
```bash
cd backend/hermes
alembic upgrade head
```
## Sicherheitsprinzipien
Verbindliche Regeln:
- Keine Tokens im `localStorage`.
- Keine Tokens im `sessionStorage`.
- Keine Browserzugriffe auf Hermes.
- Keine Cross-Origin-Cookies.
- Hermes bleibt Cookie-frei.
- Athena setzt HttpOnly Cookies.
- Mutierende Athena-API-Routes pruefen Same-Origin.
- Hermes prueft JWTs serverseitig.
- Hermes prueft RBAC-Berechtigungen serverseitig.
- Secrets gehoeren in Umgebungsvariablen, nicht in den Code.
## Produktionshinweise
Fuer Produktion gilt:
- HTTPS ist erforderlich.
- `AUTH_COOKIE_SECURE=true` setzen.
- Reverse Proxy ist moeglich und soll Forwarded Header korrekt setzen.
- `HERMES_INTERNAL_URL` muss serverseitig erreichbar sein.
- `SECRET_KEY` muss stark, geheim und stabil sein.
- Datenbankmigrationen vor App-Rollout ausfuehren.
Lokaler HTTP-Betrieb ist nur fuer Entwicklung gedacht. In Produktion duerfen keine unsicheren Cookie-Einstellungen verwendet werden.