411 lines
9.6 KiB
Markdown
411 lines
9.6 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.
|
|
|
|
## 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.
|
|
|
|
## Verzeichnisstruktur
|
|
|
|
```text
|
|
backend/hermes
|
|
app/
|
|
api/
|
|
core/
|
|
db/
|
|
models/
|
|
repositories/
|
|
schemas/
|
|
alembic/
|
|
alembic.ini
|
|
dockerfile
|
|
pyproject.toml
|
|
|
|
frontend/athena
|
|
app/
|
|
api/
|
|
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.
|