14 KiB
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:
hermesathena- das konfigurierte Docker-Netzwerk
- die notwendigen Runtime-Umgebungsvariablen
Im gemeinsamen Compose-Stack wird Athena am Host veroeffentlicht. Hermes wird nur intern im Docker-Netzwerk exponiert und von Athena ueber HERMES_INTERNAL_URL erreicht.
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
- Der Browser sendet Benutzername und Passwort an Athena:
POST /api/login. - Athena ruft serverseitig Hermes auf:
POST /auth/login. - Hermes validiert die Zugangsdaten.
- Hermes gibt JWT, Ablaufzeit und Benutzerdaten als JSON zurueck.
- Athena setzt das JWT in einem HttpOnly-Cookie.
- Der Browser wird auf eine geschuetzte Seite weitergeleitet.
Hermes setzt kein Cookie.
Logout
- Der Browser sendet
POST /api/logoutan Athena. - Athena loescht das HttpOnly-Cookie.
- Der Benutzer wird zur Login-Seite gefuehrt.
HttpOnly Cookie
Das Auth-Cookie wird von Athena gesetzt.
Eigenschaften:
HttpOnlySameSite=LaxPath=/Securein 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: Benutzernameexp: Ablaufzeitiat: Ausstellungszeitpunktiss: konfigurierter Issuertype: Token-Typ, aktuellaccess
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
/loginumleiten - eingeloggte Benutzer von
/loginauf/dashboardumleiten
API-Datenfluss
Standardfluss:
Browser -> Athena /api/... -> Hermes -> PostgreSQL
Beispiel Benutzerliste:
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.
Activity Feed
Der Activity Feed ist Teil der v0.5.0-Qualitaetsplattform.
Athena ruft GET /api/activity-feed auf. Die BFF-Route ruft serverseitig Hermes GET /activity-feed auf.
Der Feed basiert auf persistenten Audit Logs und zeigt die letzten relevanten Aktivitaeten. Hermes filtert die Eintraege anhand der Berechtigungen des aktuellen Benutzers. Ein Benutzer sieht dadurch nur Aktivitaeten zu Bereichen, fuer die er Leserechte besitzt.
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:
rolespermissionsrole_permissionsusers.role_id
Das alte users.role-Feld bleibt vorerst als Legacy-Kompatibilitaet erhalten. Neue Logik verwendet users.role_id und die roles-Beziehung.
Standardrollen
administratormanagementsalestechniciansupportwarehouseguest
administrator erhaelt alle Berechtigungen. management erhaelt mindestens Lesezugriff auf Dashboard, Benutzer, Kunden, Projekte und Tickets. guest erhaelt minimal dashboard.read.
Standardberechtigungen
Benutzer:
users.readusers.createusers.updateusers.deleteusers.password.update
Rollen:
roles.readroles.createroles.updateroles.deleteroles.assign
Kunden:
customers.readcustomers.createcustomers.updatecustomers.delete
Projekte:
projects.readprojects.createprojects.updateprojects.delete
Tickets:
tickets.readtickets.createtickets.updatetickets.delete
Dashboard und System:
dashboard.readsystem.settings.readsystem.settings.update
Audit:
audit_logs.read
Berechtigungspruefung
Zentrale Hermes-Dependencies:
get_current_userget_current_active_userrequire_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 /rolesGET /roles/{id}POST /rolesPUT /roles/{id}DELETE /roles/{id}PUT /roles/{id}/permissionsGET /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 /usersGET /users/{id}POST /usersPUT /users/{id}PUT /users/{id}/passwordDELETE /users/{id}
Athena stellt die passenden BFF-Routen unter /api/users und /api/users/[id] bereit.
Diese Endpunkte sind per RBAC geschuetzt:
GET /usersundGET /users/{id}:users.readPOST /users:users.createund fuer Rollenzuweisungroles.assignPUT /users/{id}:users.update; Rollenwechsel benoetigtroles.assignPUT /users/{id}/password:users.password.updateDELETE /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 /customersGET /customers/{id}POST /customersPUT /customers/{id}DELETE /customers/{id}GET /customers/{id}/contactsPOST /customers/{id}/contactsPUT /customers/{id}/contacts/{contact_id}DELETE /customers/{id}/contacts/{contact_id}
Athena-BFF-Routen:
GET /api/customersPOST /api/customersGET /api/customers/[id]PUT /api/customers/[id]DELETE /api/customers/[id]GET /api/customers/[id]/contactsPOST /api/customers/[id]/contactsPUT /api/customers/[id]/contacts/[contactId]DELETE /api/customers/[id]/contacts/[contactId]
Tabellen:
customerscustomer_addressescustomer_contacts
Kunden-Permissions:
customers.readcustomers.createcustomers.updatecustomers.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.
Audit Logs
Audit Logs sind die zentrale Nachvollziehbarkeitsschicht fuer v0.5.0.
Hermes persistiert relevante Ereignisse in der Tabelle audit_logs.
Erfasste Informationen:
- handelnder Benutzer
- Aktion, z. B.
users.updateodercustomers.delete - Objekttyp und Objekt-ID
- lesbares Objektlabel
- IP-Adresse und User-Agent
- Vorher-/Nachher-Daten fuer Aenderungen
- Metadaten fuer Kontextinformationen
- Erstellungszeitpunkt
Sensible Felder wie Passwoerter, Tokens und Secrets werden vor dem Schreiben maskiert.
Audit Logs werden aktuell fuer diese Bereiche geschrieben:
- Login erfolgreich/fehlgeschlagen
- Benutzer erstellen, bearbeiten, loeschen, Passwort aendern
- Rollen erstellen, bearbeiten, loeschen, Berechtigungen aendern
- Kunden erstellen, bearbeiten, loeschen
- Ansprechpartner erstellen, bearbeiten, loeschen
Hermes-Endpunkte:
GET /audit-logsGET /activity-feed
Athena-BFF-Routen:
GET /api/audit-logsGET /api/activity-feed
Die Audit-Log-UI liegt unter frontend/athena/app/audit-logs und ist ueber audit_logs.read sichtbar.
API-Response-Standard
Neue Plattform-Endpunkte verwenden eine einheitliche Response-Huelle:
{
"success": true,
"data": {},
"message": "Daten geladen"
}
Fehlerantworten aus Hermes verwenden ein konsistentes Format mit success, message, error_code und details. Fuer bestehende Athena-Fehlerbehandlung bleibt detail zusaetzlich erhalten.
Logging
Hermes konfiguriert Logging zentral ueber backend/hermes/app/core/logging.py.
HTTP-Requests werden strukturiert mit Methode, Pfad, Statuscode und Dauer geloggt. Fachliche Ereignisse bleiben in den API-Modulen als strukturierte Logeintraege erhalten.
Das Runtime-Loglevel wird ueber LOG_LEVEL gesteuert.
Frontend-Feedback
Athena nutzt einen globalen Toast-Provider fuer konsistente Erfolgs- und Fehlermeldungen.
Aktuell werden Toasts in den CRUD-Flows fuer Benutzer, Rollen, Kunden und Ansprechpartner genutzt. Inline-Fehler bleiben dort erhalten, wo sie fuer Formulare und Dialoge hilfreich sind.
Verzeichnisstruktur
backend/hermes
app/
api/
audit/
core/
db/
models/
repositories/
schemas/
alembic/
alembic.ini
dockerfile
pyproject.toml
frontend/athena
app/
api/
audit-logs/
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.
LOG_LEVEL- Runtime-Loglevel fuer Hermes, z. B.
INFO,WARNINGoderERROR.
Athena
HERMES_INTERNAL_URL- Serverseitige URL, ueber die Athena Hermes erreicht.
AUTH_COOKIE_SECURE- Steuert das
Secure-Flag des Cookies. In Produktiontrue.
Datenbankmigrationen
Olympus verwendet Alembic fuer Datenbankmigrationen.
Regeln:
- Schemaaenderungen immer ueber Alembic.
- Migrationen muessen ins Repository aufgenommen werden.
- Vor Deployment
alembic upgrade headtesten. - Keine manuellen DB-Aenderungen ausser in Notfaellen.
Typischer Ablauf:
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=truesetzen.- Reverse Proxy ist moeglich und soll Forwarded Header korrekt setzen.
HERMES_INTERNAL_URLmuss serverseitig erreichbar sein.SECRET_KEYmuss 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.