Alle Dokumente

FleetFlow — Projektdokumentation

Requirements Engineering · Architektur- und Datenmodell · Sicherheitskonzept · Modelle

ProjektFleetFlow — Flottenmanagement für Autovermietungen
AutorenFelix, Marvin, Pit, Simon
Repositoryhttps://github.com/GartmannPit/FleetFlow
Live-Systemhttps://fsse-fleetflow.de/
Stand30.07.2026 (main, inkl. Versicherungsmodul PR #57)

Die zugehörige Testdokumentation liegt als eigenes Dokument vor: Testdokumentation.md. Eine vollständige API-Referenz aller Endpunkte: API-Referenz.md. Das technische Detailkonzept zur Zwei-Faktor-Authentifizierung: 2fa-technisches-konzept.md.


1. Projektübersicht

FleetFlow ist ein webbasiertes Flottenmanagementsystem für eine Autovermietung. Ziel des Projekts ist die Digitalisierung der bislang manuellen Prozesse rund um Fahrzeugverwaltung, Kundenverwaltung, Buchungsabwicklung, Fahrzeugübergabe, Werkstattabwicklung, Versicherungsverwaltung und Abrechnung — einschließlich einer KI-gestützten Erkennung von Fahrzeugschäden anhand von Fotos und einer dynamischen, auslastungsabhängigen Preisberechnung.

Zentrale konzeptionelle Bestandteile des Projekts sind darüber hinaus:

  • ein dynamisches Rollen- und Berechtigungssystem, das über die drei ursprünglich vorgesehenen Rollen (Admin, Mitarbeiter, Kunde) hinaus beliebige weitere Rollen mit granular einstellbaren Rechten erlaubt — konkret umgesetzt am Beispiel einer eigenen Werkstatt-Rolle mit echtem Übergabe-Workflow zwischen Mitarbeiter und Werkstatt,
  • eine verpflichtende Zwei-Faktor-Authentifizierung (TOTP) für alle Konten, durchgesetzt in der Middleware vor jedem Request,
  • ein Versicherungsmodul mit Policen-Historie (PDF-Upload), Ablauf-Warnungen und Schadensfall-Verwaltung.

FleetFlow ist bewusst ein reines Mitarbeiter-System (staff-only): Es gibt keine kundenseitigen Zugänge (siehe Abschnitt 2.5).

2. Requirements Engineering

2.1 Vorgehen

Die Anforderungen wurden modulweise erhoben und als GitHub-Issues verwaltet; jedes Issue durchlief den Zyklus Anforderung → Implementierung auf Feature-Branch → Pull Request → Review → Merge. Größere bzw. zunächst unklare Anforderungen (z. B. Fahrzeugaufbereitung, #29) wurden vor der Umsetzung in einer kurzen Klärungsrunde präzisiert (Trigger, Durchsetzung, Rücksetz-Verhalten). Der Anforderungsstand wurde iterativ um im Projektverlauf entstandene Zusatzanforderungen erweitert (dynamisches Rechtesystem #38–#41, Werkstatt-Workflow #42, 2FA #44, Versicherungsmodul #55). Entscheidungen und Begründungen sind pro Feature im FEATURE_LOG.md nachvollziehbar dokumentiert.

2.2 Stakeholder und Rollen

StakeholderInteresse / Aufgaben
AdminFirmendaten, Preis- und Aufbereitungseinstellungen, Benutzerverwaltung, Definition von Rollen und Berechtigungen
MitarbeiterOperatives Tagesgeschäft: Fahrzeuge, Kunden, Buchungen, Übergaben, Rechnungen, Versicherungen
WerkstattBearbeitet ausschließlich die ihr übergebenen Reparatur-/Wartungsaufträge; kein Zugriff auf Kunden-, Buchungs- oder die vollständige Fahrzeugliste
KundeIm Erstentwurf als eigene Rolle vorgesehen; im RE-Prozess wurde entschieden, dass FleetFlow keine kundenseitigen Zugänge anbietet (Abschnitt 2.5). Die Rolle existiert aus historischen Gründen im Datenmodell weiter, wird aber nicht mit Konten befüllt

2.3 Funktionale Anforderungen (je Modul)

Fahrzeugverwaltung

  • Anlegen, Bearbeiten und Löschen von Fahrzeugen mit Stammdaten, Versicherung, HU/TÜV- und Service-Terminen.
  • Statusverwaltung (verfügbar, vermietet, in Wartung, ausgemustert) inkl. automatischer Statusübergänge durch Buchungen und Werkstattaufträge.
  • Fälligkeitswarnungen für HU/TÜV, Service, Fahrzeugaufbereitung und Versicherungsablauf — als reiner Hinweis, ohne Buchungen zu blockieren.
  • Freitextsuche, Filter nach Status/Typ, serverseitige Pagination (50 Zeilen/Seite).

Kundenverwaltung

  • Verwaltung von Privat- und Firmenkunden mit jeweils passenden Pflichtfeldern (Privat: Vor-/Nachname, Führerschein; Firma: Firmenname, Ansprechpartner, USt-IdNr.).
  • Anzeige der vollständigen Buchungshistorie je Kunde.

Buchungsverwaltung

  • Status-Workflow Anfrage → Angebot → Bestätigt → Aktiv → Zurückgegeben → Abgeschlossen (+ Storniert jederzeit).
  • Verfügbarkeitsprüfung gegen bestehende, blockierende Buchungen desselben Fahrzeugs — doppelt abgesichert (Anwendungsprüfung + Datenbank-Constraint, Abschnitt 3.6).
  • Dynamische Preisberechnung anhand von Saison, Wochentag, Flottenauslastung und Buchungsdauer, mit vom Admin konfigurierbaren Faktoren.
  • Automatisierte Extraktion von Buchungsdaten aus Kunden-E-Mails per KI (Gemini) mit Vorbefüllung des Formulars.
  • Generierung und Versand von Angebot und Auftragsbestätigung als PDF per E-Mail.

Fahrzeugübergabe

  • Protokollierung von Ausgabe und Rückgabe je Buchung inkl. Kilometerstand, Tankstand, Fahrzeugzustand innen/außen und mitgegebenen Gegenständen (Checkliste).
  • Foto-Upload mit automatischer KI-Schadenserkennung; mehrere Fotos parallel wählbar, jedes wird unabhängig hochgeladen und analysiert (Batch-Upload mit Hintergrund-Analyse).
  • Druckbares Übergabeprotokoll.
  • Eigenständige, buchungsunabhängige Schadensmeldungen direkt am Fahrzeug.

Rechnungswesen

  • Rechnungserstellung aus abgeschlossenen Buchungen mit automatischer, fortlaufender Rechnungsnummer und Netto-/MwSt.-/Brutto-Berechnung (Standard 19 %, Bruttopreis als Ausgangswert).
  • Statuspflege Entwurf → Versendet → Bezahlt (oder Storniert) mit gültigen Statusübergängen und Überfälligkeits-Erkennung.
  • PDF-Erzeugung (mit Caching im Storage) und E-Mail-Versand.

Berichte

  • Monatlicher Umsatzverlauf (realisiert vs. offene Forderungen), Flottenauslastung je Fahrzeug (30-/90-Tage-Fenster), Top-Fahrzeuge/-Kunden nach Umsatz, Buchungs-Trichter nach Status, Kennzahlen-Karten (u. a. Stornoquote).

Rollen- und Berechtigungssystem

  • Ablösung des festen Rollen-Enums durch ein dynamisches Modell: Admins können eigene Rollen anlegen, umbenennen und löschen (außer den drei geschützten Grundrollen).
  • Pro Rolle und Funktionsbereich (11 Ressourcen) einzeln einstellbare Rechte: Sehen, Bearbeiten, Löschen.
  • Durchsetzung auf zwei Ebenen: Datenbank (Row-Level-Security) und Anwendung (serverseitige Prüfung vor jeder schreibenden Aktion) — Rechte lassen sich nicht über direkte API-Aufrufe umgehen.
  • Rollenabhängige Navigation: nicht zugängliche Bereiche werden in der Seitenleiste ausgeblendet.
  • Benutzerverwaltung inkl. nachträglicher Rollenzuweisung zu bestehenden Konten.

Werkstatt-Workflow

  • Eigene, vordefinierte (aber anpassbare) Rolle „Werkstatt" mit minimalem Zugriff — nur eigene Aufträge und Schadensfotos.
  • Echter Übergabe-Workflow mit Zustandsautomat Offen → In Bearbeitung → Abgeschlossen.
  • Automatische Synchronisation des Fahrzeugstatus mit dem Werkstattauftrag (Übergabe → „in Wartung", Abschluss → „verfügbar") über einen Datenbank-Trigger.
  • Eigenes Werkstatt-Dashboard als Startseite für diese Rolle.

Versicherungsmodul

  • Verwaltung mehrerer Versicherungspolicen je Fahrzeug (Haftpflicht/Teilkasko/Vollkasko) mit Gültigkeitszeitraum und PDF-Upload in einen privaten Storage-Bucket; abgelaufene Policen bleiben als Historie erhalten.
  • Ablauf-Warnung bei bald ablaufender oder abgelaufener Police (Fahrzeugdetail + Dashboard).
  • Schadensfall-Verwaltung mit Status Offen → In Bearbeitung → Abgeschlossen; Schadensfotos (aus Übergabe oder Schadensmeldung) können zusätzlich einem Schadensfall zugeordnet werden.

Authentifizierung & Onboarding

  • Verpflichtende Zwei-Faktor-Authentifizierung (TOTP) für jedes Konto: Zwangs-Einrichtung beim ersten Login, Code-Abfrage bei jedem weiteren Login, Faktor-Reset in den Sicherheitseinstellungen.
  • Einzelmandanten-Onboarding: Die Firma registriert sich genau einmal (Firmendaten + Admin-Konto in einem Schritt); danach ist die öffentliche Registrierung gesperrt. Mitarbeiterkonten legt ausschließlich der Admin über die Benutzerverwaltung an.

2.4 Nicht-funktionale Anforderungen

KategorieAnforderung
SicherheitZugriffskontrolle auf zwei Ebenen (RLS + Anwendungslogik); verpflichtende 2FA; Service-Role-Schlüssel ausschließlich serverseitig; Schutz vor Selbst-Rechteausweitung per DB-Trigger
NachvollziehbarkeitSicherheitsrelevante Änderungen (z. B. Rollenwechsel) nur mit entsprechendem Recht; Feature-Entscheidungen im FEATURE_LOG dokumentiert
ErweiterbarkeitNeue Funktionsbereiche lassen sich in die Berechtigungsmatrix aufnehmen, ohne bestehende Rollen anzufassen; Dokument-Pipeline (PDF + E-Mail) als wiederverwendbares Muster
Ausfalltoleranz der KI/E-Mail-IntegrationSchadenserkennung, E-Mail-Extraktion und E-Mail-Versand funktionieren ohne konfigurierte API-Schlüssel über deterministische Ersatzmechanismen (Mock/Simulation) weiter
BenutzbarkeitRollenabhängige, aufgeräumte Oberfläche; Erfolgs-Toasts; Warnungen statt Blockaden; Deep-Links vom Dashboard in vorgefilterte Listen
PerformanceServerseitige Pagination und Suche; Server Components für Datenzugriffe; Realtime-Updates nur wo fachlich sinnvoll (Buchungsliste)

2.5 Im RE-Prozess verworfene Anforderung: Kundenportal

Ein Kundenportal (eigener Log-in für Kunden mit Einblick in die eigenen Buchungen, Issue #14) wurde vollständig implementiert, in der Verifikation jedoch wieder verworfen — aus zwei Gründen:

  1. Ein End-to-End-Test mit einem Wegwerf-Testkonto deckte eine Sicherheitslücke in den RLS-Policies auf: Das Kundenkonto war zwar korrekt auf die eigenen Buchungen beschränkt, konnte aber sämtliche Kunden- und Fahrzeugdaten lesen.
  2. Parallel wurde im Projektverlauf die Produktentscheidung getroffen, dass FleetFlow grundsätzlich keine kundenseitigen Konten vorsieht.

Die Funktion wurde daraufhin vollständig zurückgebaut (Datenbankänderungen, Oberfläche, Weiterleitungslogik) und das Issue als „won't do" geschlossen. Der Vorgang ist im FEATURE_LOG.md (#14) vollständig dokumentiert — bewusst auch als Absicherung dagegen, dass die Anforderung später unbeabsichtigt erneut umgesetzt wird.

3. Architektur- und Datenmodell

3.1 Technologiestack

SchichtTechnologie
FrameworkNext.js 14 (App Router), React 18, TypeScript (strict)
OberflächeTailwind CSS 3, shadcn/ui (Radix-Primitives), lucide-react Icons
KarteLeaflet.js + react-leaflet + OpenStreetMap
DatenbankSupabase (PostgreSQL) mit Row-Level-Security
AuthentifizierungSupabase Auth (JWT, SSR-Cookies via @supabase/ssr) inkl. MFA/TOTP
StorageSupabase Storage (Buckets: damage-photos, Rechnungs-PDFs, insurance-policies)
RealtimeSupabase Realtime (Buchungs-/Fahrzeugtabellen)
KIGoogle Gemini (gemini-2.5-flash): Vision für Schadenserkennung, Textmodell für E-Mail-Extraktion — jeweils mit deterministischem Mock-Fallback
PDF@react-pdf/renderer (Rechnung, Angebot, Auftragsbestätigung)
E-MailResend-API mit Simulations-Fallback ohne API-Schlüssel
Diagrammerecharts (Berichte-Modul)
DeploymentVercel (App) + Supabase Cloud (Datenbank/Auth/Storage)

3.2 Architekturüberblick

Diagramm wird geladen …

Architekturprinzipien:

  • Lesen über Server Components, Schreiben über API-Routen. Seiten unter src/app/(app)/ sind asynchrone Server Components und lesen direkt über den serverseitigen Supabase-Client. Alle Mutationen (Anlegen/Ändern/Löschen) laufen über Next.js-API-Routen, die vor jeder Aktion die Berechtigung prüfen.
  • Middleware als Sicherheits-Chokepoint. src/middleware.ts läuft vor praktisch jedem Request: Session-Refresh plus 2FA-Durchsetzung (Abschnitt 4.3). Neue geschützte Bereiche sind damit automatisch abgesichert.
  • Graceful Degradation externer Dienste. Gemini und Resend sind optionale Abhängigkeiten; ohne Schlüssel greifen deterministische Fallbacks (Mock-Analyse, Regex-Extraktion, E-Mail-Simulation mit Log-Ausgabe).

3.3 Projektstruktur (Auszug)

src/
  app/
    (app)/            # geschützte Seiten (Dashboard, vehicles, customers, bookings,
                      #   invoices, reports, werkstatt, team, settings)
    api/              # REST-Routen (siehe API-Referenz.md)
    login/            # Login + Firmen-Registrierung (Einzelmandant)
    mfa/              # 2FA: enroll (Ersteinrichtung), challenge (Code-Abfrage)
  components/         # Formulare, Tabellen, Karte, Rollen-/Team-Manager, UI-Primitives
  lib/
    supabase/         # Browser-/Server-/Admin-/Middleware-Clients
    ai/               # Gemini-Integration (Vision + Text) mit Mock-Fallback
    pdf/              # Rechnung / Angebot / Auftragsbestätigung
    email/            # Resend-Wrapper mit Simulations-Fallback
    pricing.ts        # Dynamic Pricing (konfigurierbare Faktoren)
    availability.ts   # Verfügbarkeits-/Kollisionsprüfung
    bookings.ts       # Status-Workflow + Fahrzeugstatus-Mapping
    invoices.ts       # Rechnungsbeträge, Statusübergänge, Überfälligkeit
    warnings.ts       # HU/Service/Führerschein/Aufbereitung/Versicherungs-Warnungen
    reports.ts        # Aggregationen für das Berichte-Modul
supabase/migrations/  # 21 SQL-Migrationen (Schema, RLS, Trigger, Seed)
docs/                 # diese Dokumentation

3.4 Datenmodell

Diagramm wird geladen …
TabelleZweck
profilesVerknüpft ein Auth-Konto mit Rolle und Firma; automatisch per Trigger beim Anlegen eines Users erzeugt
rolesFrei definierbare Rollen; die drei Grundrollen (admin, mitarbeiter, kunde) sind als Systemrollen geschützt (nicht lösch-/umbenennbar)
permissionsBerechtigungsmatrix: je Rolle × Ressource ein Datensatz mit can_read / can_write / can_delete
companiesFirmendaten der Vermietung (Absenderdaten auf allen PDF-Dokumenten); Fundament des Einzelmandanten-Onboardings
settingsSingleton-Zeile (per Check-Constraint garantiert genau eine Zeile) mit globalen Einstellungen: Aufbereitungsintervall, Preisfaktoren
vehiclesFahrzeugstammdaten, Status, HU/Service-Termine, GPS-Position, Tagespreis, letzte Aufbereitung
customersPrivat-/Firmenkunden inkl. Führerschein- bzw. USt-IdNr.-/Ansprechpartner-Feldern
bookingsVerknüpft Fahrzeug + Kunde, Zeitraum (inklusiv), Status, Gesamtpreis
handoversÜbergabe-/Rückgabeprotokoll je Buchung: km, Tankstand, Zustand innen/außen, Gegenstände-Checkliste
damage_photosSchadensfotos mit KI-Analysetext; per Check-Constraint entweder einer Übergabe oder direkt einem Fahrzeug zugeordnet (nie beidem), optional zusätzlich einem Versicherungsfall
invoicesRechnung zu einer abgeschlossenen Buchung: fortlaufende Nummer, Netto/MwSt./Brutto, Status, Fälligkeit
werkstattauftraegeWerkstatt-Übergabeaufträge je Fahrzeug mit Status offen / in_bearbeitung / abgeschlossen
versicherungspolicenPolicen-Historie je Fahrzeug (Anbieter, Police-Nr., Typ, Gültigkeitszeitraum, PDF im Storage)
versicherungsfaelleVersicherungs-Schadensfälle je Fahrzeug mit Status-Workflow

Das vollständige UML-Klassendiagramm des Datenmodells:

UML-Klassendiagramm des FleetFlow-Datenmodells

Ergänzend liegt im Repository ein Use-Case-Diagramm (use-case-diagram.drawio, draw.io-Quelldatei) vor.

3.5 Rollen- und Berechtigungsmodell

Anstelle eines starren, im Code festgelegten Rollen-Enums verwendet FleetFlow ein datengetriebenes Modell: Jede Rolle ist eine Zeile in roles, jede Berechtigung eine Zeile in permissions mit drei booleschen Feldern (Sehen/Bearbeiten/Löschen) je Funktionsbereich. Die Matrix umfasst elf Ressourcen:

vehicles, customers, bookings, handovers, damage_photos, invoices, settings, companies, users, werkstatt, insurance

Eine zentrale Datenbankfunktion has_permission(resource, action) prüft für den angemeldeten Benutzer, ob das jeweilige Recht vorliegt. Sie wird an zwei Stellen verwendet:

  1. in den RLS-Policies jeder betroffenen Tabelle (und der Storage-Buckets) — als letzte, nicht umgehbare Kontrollinstanz,
  2. in der Anwendungslogik vor jeder schreibenden Aktion — damit fehlende Rechte sofort mit einer klaren Fehlermeldung (HTTP 403) beantwortet werden statt mit einem unspezifischen Datenbankfehler.

Zusätzlich verhindert eine Datenbank-Triggerfunktion, dass ein Benutzer ohne das entsprechende Recht die eigene Rolle oder Firmenzuordnung ändert — auch bei direktem Zugriff auf die Datenbank-API unter Umgehung der Oberfläche (Anti-Privilege-Escalation, Migrationen 0014/0018).

Die Navigation blendet Bereiche ohne Leserecht aus; Änderungen an der Berechtigungsmatrix wirken sofort — sowohl sichtbar (Navigation, deaktivierte Buttons mit Tooltip) als auch tatsächlich (RLS + API).

3.6 Buchungs-Statusmodell und Verfügbarkeitsprüfung

Diagramm wird geladen …

Nur Bestätigt und Aktiv blockieren das Fahrzeug für den gebuchten Zeitraum. Der Wechsel nach Aktiv setzt den Fahrzeugstatus automatisch auf „vermietet", der Wechsel zu Zurückgegeben zurück auf „verfügbar" (Mapping in src/lib/bookings.ts).

Die Verfügbarkeit wird doppelt abgesichert:

  1. Anwendungsebene: checkAvailability() prüft vor dem Speichern gegen bestehende blockierende Buchungen und liefert eine verständliche Fehlermeldung.
  2. Datenbankebene: Ein btree_gist-Exclusion-Constraint verhindert überlappende Zeiträume (daterange-Überschneidung) für dasselbe Fahrzeug bei blockierendem Status — als Sicherheitsnetz auch gegen Race-Conditions bei gleichzeitigen Anfragen.

3.7 Dynamische Preisberechnung

calculatePrice() berechnet Tagespreis × Tage und wendet multiplikative Faktoren an. Alle Faktoren sind vom Admin unter Einstellungen konfigurierbar (Migration 0014_dynamic_pricing_settings); die Standardwerte:

FaktorAuslöserMultiplikator (Standard)
Hochsaison SommerStartmonat Juni–August× 1,15
Feiertage DezemberStartmonat Dezember× 1,10
Nebensaison WinterStartmonat Januar–Februar× 0,90
Wochenend-ZuschlagZeitraum enthält Sa/So× 1,05
Hohe AuslastungFlotte > 80 % vermietet× 1,20
Mittlere AuslastungFlotte > 60 % vermietet× 1,10
Wochenrabatt≥ 7 Tage× 0,90
Langzeitrabatt≥ 28 Tage× 0,80

Das Buchungsformular zeigt eine Live-Vorschau der Preisaufschlüsselung (POST /api/pricing/quote).

3.8 Werkstatt-Übergabe-Workflow

Diagramm wird geladen …

Der Workflow bildet einen echten zweiseitigen Austausch zwischen Mitarbeiter und Werkstatt ab. Der Fahrzeugstatus wird ausschließlich über eine security definer-Triggerfunktion synchronisiert: Die Werkstatt-Rolle benötigt dadurch kein allgemeines Schreibrecht auf die Fahrzeugtabelle (und könnte somit auch keine Stammdaten ändern). Sie besitzt nur Rechte auf Werkstattaufträge und Schadensfotos — bewusst kein allgemeines Leserecht auf Fahrzeuge; die für einen Auftrag nötigen Fahrzeugdaten werden serverseitig gezielt nur für das zugeordnete Fahrzeug nachgeladen. Für die Werkstatt-Rolle ist ein eigenes Dashboard (neue, laufende, kürzlich abgeschlossene Aufträge) die Startseite.

3.9 KI-Integration

Beide KI-Funktionen liegen in src/lib/ai/index.ts und folgen demselben Muster — echter API-Aufruf mit deterministischem Fallback:

FunktionModellFallback ohne GEMINI_API_KEY
analyzeDamage(image) — Schadenserkennung aus FotoGemini Vision (gemini-2.5-flash), mit Konfidenz-Schwellwerten gegen übersehene leichte Kratzer (#30)Statische Mock-Analyse
extractBookingFromEmail(text) — Buchungsdaten aus E-Mail-TextGemini Textmodell mit strukturiertem JSON-OutputRegex-/Heuristik-Extraktion

Der Foto-Upload ist als Batch-Verarbeitung implementiert (use-photo-upload.ts): Jedes Foto hat einen eigenen Upload-/Analyse-Status, läuft unabhängig im Hintergrund, und das Formular bleibt währenddessen voll bedienbar; abgesendet werden nur vollständig verarbeitete Fotos.

3.10 Dokumenten-Pipeline (PDF + E-Mail)

Rechnung, Angebot und Auftragsbestätigung teilen sich eine gemeinsame Render-Pipeline (@react-pdf/renderer) mit gemeinsamen Absenderdaten aus der companies-Tabelle. Unterschiede im Lebenszyklus sind bewusst modelliert: Rechnungs-PDFs werden im Storage gecacht (eine Rechnung ist nach Erstellung faktisch eingefroren), Angebots-/Auftragsbestätigungs-PDFs werden bei jedem Abruf frisch gerendert (Buchungsdaten können sich in diesen Status noch ändern). Der E-Mail-Versand läuft über einen generischen Resend-Wrapper, der ohne API-Schlüssel transparent in eine geloggte Simulation ausweicht.

4. Sicherheitskonzept

4.1 Zwei Verteidigungsebenen

Jeder Zugriff wird zweistufig kontrolliert:

  1. Row-Level-Security (Datenbank) — letzte, nicht umgehbare Instanz. Alle Tabellen und Storage-Buckets haben Policies auf Basis von has_permission(). Selbst ein direkter Zugriff mit dem öffentlichen Anon-Key kann nur, was die Rolle des angemeldeten Benutzers erlaubt.
  2. Anwendungsebene (API-Routen) — identische Prüfung vor jeder schreibenden Aktion, damit Fehler sofort und verständlich (HTTP 403 mit Meldung) statt als generischer DB-Fehler auftreten.

4.2 Härtung gegen Rechteausweitung

Im Projektverlauf wurden zwei reale RLS-Lücken gefunden und geschlossen (Issue #36, Migrationen 0014/0018): Eine profiles-Update-Policy ohne WITH CHECK hätte es erlaubt, per Anon-Key die eigene Rolle zu ändern. Heute verhindert ein Datenbank-Trigger jede Änderung der eigenen Rolle/Firmenzuordnung ohne entsprechendes Recht — unabhängig vom Zugriffsweg. Zusätzlich wurden die Warnungen des Supabase Security Advisors abgearbeitet (Migration 0020), u. a. Entfernung altlastiger, zu permissiver Policies.

4.3 Verpflichtende Zwei-Faktor-Authentifizierung

2FA (TOTP nach RFC 6238, kompatibel mit Google Authenticator, 1Password, Authy, …) ist für jedes Konto verpflichtend — es gibt keinen Codepfad, der eine Session ohne bestandenen zweiten Faktor zu geschützten Seiten durchlässt. Die Durchsetzung sitzt in der Middleware und basiert auf dem Authenticator Assurance Level (AAL) des Session-JWT:

  • kein Faktor eingerichtet → Zwangs-Enrollment (/mfa/enroll, QR-Code),
  • Faktor vorhanden, Session noch nicht verifiziert → Code-Abfrage (/mfa/challenge),
  • vollständig authentifiziert (aal2) → Zugriff.

2FA lässt sich nicht deaktivieren, nur zurücksetzen (z. B. bei Geräteverlust); danach erzwingt die Middleware automatisch die Neueinrichtung. Details, Architekturentscheidungen und zwei in der Implementierung gefundene Fallstricke: 2fa-technisches-konzept.md.

4.4 Weitere Maßnahmen

  • Einzelmandanten-Registrierung: /api/register legt Firma + Admin-Konto in einem Schritt an und ist gesperrt, sobald eine Firma existiert. Kein öffentliches Mitarbeiter-Signup; Konten legt der Admin an.
  • Schlüsseltrennung: Der Service-Role-Key wird ausschließlich serverseitig (Admin-Client) verwendet und nie an den Browser ausgeliefert; clientseitig kommt nur der RLS-geschützte Anon-Key zum Einsatz.
  • Gezielte, schmale Ausnahmen: Wo erhöhte Rechte nötig sind (Fahrzeugstatus-Sync im Werkstatt-Workflow), werden eng umrissene security definer-Funktionen eingesetzt statt pauschal weitreichender Rollenrechte.

5. Test- und Qualitätssicherung (Zusammenfassung)

Für jedes Feature wurden mehrere Prüfebenen kombiniert: statische Prüfung (TypeScript strict, ESLint), Build-Prüfung (fehlerfreier Produktionsbuild als Definition-of-Done), direkte Datenverifikation nach jeder Migration, isolierte Funktionstests der Kernlogik (Preisberechnung, Verfügbarkeit, Auslastung) mit konkreten Beispieldaten sowie ein ausführlicher manueller Testplan je Modul inkl. Rollen-/Rechte- und Sicherheits-Testfällen (u. a. direkter API-Aufruf ohne Recht → 403).

Der vollständige Testplan mit allen Testfällen, Vorbedingungen und Sollergebnissen ist ausgelagert: Testdokumentation.md.

6. Bekannte Einschränkungen

  • Kundenportal: bewusst nicht (mehr) umgesetzt — Produktentscheidung, siehe Abschnitt 2.5.
  • E-Mail-Versand läuft ohne konfigurierten RESEND_API_KEY im Simulationsmodus (Inhalt + Anhang werden serverseitig geloggt, nicht versendet) — für den Prototyp-Betrieb ausreichend, für den Produktivbetrieb ist ein Schlüssel zu hinterlegen.
  • Buchungs-Freitextsuche filtert (anders als bei Fahrzeugen/Kunden) clientseitig auf der aktuellen Seite, da die Suchfelder auf verknüpften Tabellen liegen; die Statusfilterung und Pagination laufen serverseitig.
  • Die Typen in src/lib/types.ts werden von Hand parallel zum SQL-Schema gepflegt; in einem Produktiv-Setup würde supabase gen types typescript verwendet.

7. Glossar

BegriffBedeutung
AAL (Authenticator Assurance Level)Vertrauensstufe einer Session: aal1 = nur Passwort, aal2 = Passwort + TOTP-Code bestätigt. Grundlage der 2FA-Durchsetzung in der Middleware
Anon-KeyÖffentlicher Supabase-API-Schlüssel des Browsers; jede damit ausgeführte Abfrage unterliegt der Row-Level-Security
App RouterRouting-Modell von Next.js 14: Seiten als Server Components, Layouts und Route-Gruppen unter src/app/
Exclusion-ConstraintPostgreSQL-Constraint, das überlappende Buchungszeiträume desselben Fahrzeugs auf Datenbankebene verhindert (btree_gist)
HandoverÜbergabe- bzw. Rückgabeprotokoll einer Buchung (km, Tankstand, Zustand, Gegenstände, Fotos)
MiddlewareNext.js-Code, der vor jedem Request läuft — in FleetFlow: Session-Refresh und 2FA-Durchsetzung
RLS (Row-Level-Security)Zugriffsregeln direkt auf Datenbankzeilen-Ebene; letzte, nicht umgehbare Kontrollinstanz
RealtimeSupabase-Mechanismus, der Datenbankänderungen live in den Browser überträgt (z. B. Buchungsliste)
security definerPostgreSQL-Funktionsattribut: Funktion läuft mit den Rechten ihres Erstellers — genutzt für eng umrissene, kontrollierte Ausnahmen (Fahrzeugstatus-Sync im Werkstatt-Workflow)
Server ComponentReact-Komponente, die ausschließlich auf dem Server rendert und dort direkt Daten laden kann
Service-Role-KeySupabase-Schlüssel mit Vollzugriff (umgeht RLS); ausschließlich serverseitig für Admin-Aufgaben (Registrierung, Kontoanlage) verwendet
TOTP (Time-based One-Time Password)Zeitbasierter Einmalcode nach RFC 6238, erzeugt von einer Authenticator-App; zweiter Faktor der Anmeldung