Files
drivetimeplaner/docs/fahrschuldesk/PLAN.md

19 KiB

fahrschuldesk — Projektplan

1. Überblick

fahrschuldesk ist eine SaaS-Plattform zur Verwaltung von Fahrschulen. Plattformbetreiber (Admin-Team) können Fahrschulen als Mandanten anlegen und verwalten. Jede Fahrschule erhält eine modulare Oberfläche mit Kundenverwaltung, Kalender, Messenger und optionaler Lernsoftware.

Status: Planungsphase (Initialsetup)


2. Architektur

2.1 Domains

Domain Zweck Pfad
fahrschuldesk.de WebUI (Frontend) www/fahrschuldesk.de/public/
api.fahrschuldesk.de REST API (Backend) www/api.fahrschuldesk.de/public/

2.2 Tech-Stack

  • Frontend: Vue 3 + Vite (SPA)
  • Backend: PHP (Laravel oder Slim Framework)
  • Datenbank: PostgreSQL (fahrschuldesk DB, Host: 10.255.30.11:5433)
  • WebSockets: Für Messenger (Socket.io oder native WebSockets)
  • Dateien: Lokaler Storage + S3-kompatibel (für Self-Hosted einfach lokaler Ordner)
  • Auth: JWT-basiert mit Refresh-Token
  • CI/CD: GitHub Actions / GitLab CI

2.3 Kalender-Integration

Der Kalender wird über die fahrschultermin.de API gesteuert (spätere Integration). Die fahrschuldesk-API dient als Schnittstelle.


3. Hierarchie & Datenmodell

Plattform-Admins (intern)
 └── Fahrschule (Mandant)
      └── Filialen
           └── Benutzer

3.1 Tabellen

Plattform-Admins (interne Verwaltung)

platform_admins
  - id (uuid)
  - email (unique)
  - password_hash
  - name
  - role (super_admin | support | sales)
  - created_at
  - updated_at
  - last_login_at

Fahrschulen (Mandanten)

tenants
  - id (uuid)
  - name
  - slug (unique, für Subdomain?)
  - email (Rechnungs-Kontakt)
  - phone
  - address
  - status (pending_approval | active | suspended | trial)
  - trial_ends_at
  - created_at
  - updated_at
  
  # Branding
  - logo_url
  - primary_color
  - secondary_color
  - custom_css (optional)
  
  # Self-Hosted
  - is_self_hosted (bool)
  - self_hosted_license_key

Filialen

branches
  - id (uuid)
  - tenant_id (FK)
  - name
  - address
  - phone
  - email
  - opening_hours (JSON)
  - is_headquarters (bool)
  - created_at
  - updated_at

Benutzer

users
  - id (uuid)
  - tenant_id (FK)
  - branch_id (FK, nullable)
  - email (unique pro Tenant)
  - password_hash
  - first_name
  - last_name
  - user_type (admin | office | instructor | lecturer | student)
  - status (active | inactive | pending)
  - avatar_url
  - phone
  - created_at
  - updated_at
  - last_login_at

Module (pro Fahrschule zuweisbar)

modules
  - id (uuid)
  - key (office | calendar | messenger | learning_blank | learning_premium)
  - name
  - description
  - monthly_price (cent)
  - is_active (Plattform-global)
  - created_at

tenant_modules
  - id (uuid)
  - tenant_id (FK)
  - module_id (FK)
  - status (enabled | disabled)
  - enabled_at
  - expires_at (nullable)
  - trial_ends_at (nullable)

Pakete (Preismodelle)

packages
  - id (uuid)
  - key (starter | professional | enterprise)
  - name
  - description
  - monthly_price (cent)
  - modules_included (JSON array von module_keys)
  - max_users
  - max_branches
  - created_at

tenant_packages
  - id (uuid)
  - tenant_id (FK)
  - package_id (FK)
  - started_at
  - expires_at

Lerninhalte (Premium-Modul)

learning_contents
  - id (uuid)
  - tenant_id (FK, nullable — null = Plattform-global)
  - category
  - title
  - description
  - content_type (video | document | quiz | exercise)
  - content_url
  - thumbnail_url
  - duration_minutes
  - is_premium
  - created_at
  - updated_at

Fahrschüler-Fortschritt

student_progress
  - id (uuid)
  - user_id (FK, student)
  - content_id (FK)
  - status (not_started | in_progress | completed)
  - completed_at
  - notes (Lehrer-Kommentare)
  - created_at
  - updated_at

Audit-Log

audit_logs
  - id (uuid)
  - tenant_id (FK, nullable — null für Plattform-Admin-Aktionen)
  - user_id (FK, nullable)
  - action (created | updated | deleted | login | logout | etc.)
  - entity_type (tenant | user | branch | module | etc.)
  - entity_id (UUID des betroffenen Datensatzes)
  - old_values (JSON, nullable)
  - new_values (JSON, nullable)
  - ip_address
  - user_agent
  - created_at
  
  # Index auf tenant_id + created_at für schnelle Abfragen
  # Index auf entity_type + entity_id

Rechnungen

invoices
  - id (uuid)
  - tenant_id (FK)
  - invoice_number (unique)
  - amount (cent)
  - vat_amount (cent)
  - total_amount (cent)
  - currency (EUR)
  - status (draft | pending | paid | overdue | cancelled)
  - billing_period_start
  - billing_period_end
  - due_date
  - paid_at (nullable)
  - created_at
  - updated_at

invoice_items
  - id (uuid)
  - invoice_id (FK)
  - description
  - quantity
  - unit_price (cent)
  - total_price (cent)

E-Mail / Notifications

notification_templates
  - id (uuid)
  - key (welcome | password_reset | invoice | trial_expiring | etc.)
  - subject
  - body_html
  - body_text
  - variables (JSON)
  - created_at
  - updated_at

notifications
  - id (uuid)
  - user_id (FK)
  - tenant_id (FK, nullable)
  - template_key
  - subject
  - body
  - status (pending | sent | failed)
  - sent_at
  - created_at

Dateien / Uploads / DKS (Dokumenten-Klasse-System)

files
  - id (uuid)
  - tenant_id (FK)
  - user_id (FK, nullable — wer hochgeladen hat)
  - entity_type (vehicle | student | instructor | branch | etc.)
  - entity_id (UUID)
  - file_type (insurance | tuv | logo | avatar | document | etc.)
  - original_filename
  - storage_path
  - mime_type
  - size_bytes
  - created_at
  
  # Dateien werden im Storage abgelegt:
  # SaaS: /storage/tenants/{tenant_id}/files/
  # Self-Hosted: /var/www/fahrschuldesk/storage/files/

Messenger (DSGVO-konform)

conversations
  - id (uuid)
  - tenant_id (FK)
  - type (direct | group)
  - name (nullable, nur für groups)
  - created_at
  - updated_at

conversation_participants
  - id (uuid)
  - conversation_id (FK)
  - user_id (FK)
  - joined_at
  - last_read_at

messages
  - id (uuid)
  - conversation_id (FK)
  - user_id (FK)
  - body (Verschlüsselt auf DB-Ebene)
  - is_edited (bool)
  - is_deleted (bool)
  - created_at
  - updated_at
  
  # Keine Ende-zu-Ende Verschlüsselung (Plattform hat Zugriff für Support/Audit)
  # DSGVO: Keine externen Dienste, alles auf eigenen Servern
  # Nachrichten können auf Anfrage exportiert/gelöscht werden (DSGVO-Compliance)

4. API-Struktur

4.1 Auth

POST   /api/auth/login                    (JWT Token)
POST   /api/auth/logout
POST   /api/auth/refresh                 (Refresh Token)
GET    /api/auth/me

POST   /api/auth/forgot-password
POST   /api/auth/reset-password

4.2 Registration (Self-Service)

POST   /api/auth/register                (Fahrschule registrieren)
GET    /api/auth/register/verify/:token  (E-Mail verifizieren)

4.3 Plattform-Admin (nur Admins)

GET    /api/admin/tenants
POST   /api/admin/tenants
GET    /api/admin/tenants/:id
PUT    /api/admin/tenants/:id
DELETE /api/admin/tenants/:id

POST   /api/admin/tenants/:id/approve     (Freigabe nach Registration)
POST   /api/admin/tenants/:id/suspend

GET    /api/admin/tenants/:id/modules
POST   /api/admin/tenants/:id/modules
DELETE /api/admin/tenants/:id/modules/:moduleId

GET    /api/admin/platform-modules
GET    /api/admin/platform-modules/:id

GET    /api/admin/invoices
GET    /api/admin/invoices/:id
PUT    /api/admin/invoices/:id/mark-paid

GET    /api/admin/audit-logs             (Plattform-weit)
GET    /api/admin/audit-logs/:id

GET    /api/admin/platform-admins
POST   /api/admin/platform-admins
PUT    /api/admin/platform-admins/:id
DELETE /api/admin/platform-admins/:id

4.4 Tenant-Admin (Fahrschule)

GET    /api/branches
POST   /api/branches
PUT    /api/branches/:id
DELETE /api/branches/:id

GET    /api/users
POST   /api/users
GET    /api/users/:id
PUT    /api/users/:id
DELETE /api/users/:id

GET    /api/my-modules
GET    /api/my-profile
PUT    /api/my-profile

GET    /api/audit-logs                   (Tenant-spezifisch)
GET    /api/audit-logs/:id

# Branding
PUT    /api/tenant/branding
GET    /api/tenant/branding

# Pakete
GET    /api/my-package
PUT    /api/tenant/logo

4.5 Kalender (Integration fahrschultermin.de)

GET    /api/calendar/events              (weiterleiten an fahrschultermin.de API)
POST   /api/calendar/events
PUT    /api/calendar/events/:id
DELETE /api/calendar/events/:id
GET    /api/calendar/availability        (Abfrage freier Slots)

4.6 Messenger

GET    /api/messenger/conversations
POST   /api/messenger/conversations
GET    /api/messenger/conversations/:id
POST   /api/messenger/conversations/:id/messages
GET    /api/messenger/conversations/:id/messages
PUT    /api/messenger/messages/:id       (editieren)
DELETE /api/messenger/messages/:id       (soft delete)

4.7 Lernsoftware

GET    /api/learning/contents
GET    /api/learning/contents/:id
GET    /api/learning/my-progress
POST   /api/learning/my-progress
PUT    /api/learning/my-progress/:contentId

# Nur für Admin / Dozenten
POST   /api/learning/contents           (Blanko: eigene Inhalte erstellen)
PUT    /api/learning/contents/:id
DELETE /api/learning/contents/:id

4.8 Dateien / DKS

GET    /api/files                        (Liste, gefiltert nach entity)
POST   /api/files                        (Upload)
GET    /api/files/:id
DELETE /api/files/:id
GET    /api/files/:id/download

4.9 Rechnungen (Tenant)

GET    /api/billing/invoices
GET    /api/billing/invoices/:id
GET    /api/billing/current-package

5. Rollen & Rechte

Plattform-Admins (intern)

Rolle Rechte
super_admin Alles: Tenants, Admins, Module, Settings, Invoices, Audit
support Tenants einsehen/verwalten, keine Admins ändern, keine Settings
sales Tenants anlegen, keine Settings, keine Admin-Verwaltung

Fahrschul-Benutzer

Typ Beschreibung
admin Voller Zugriff auf eigene Fahrschule
office Büromitarbeiter: Kunden, Kalender, Berichte
instructor Fahrlehrer: Kalender, eigene Fahrschüler, DKS
lecturer Dozent: Kalender, eigene Unterrichtseinheiten
student Fahrschüler: Lernsoftware, eigener Fortschritt, Messenger

Rechte-Matrix (pro Modul)

user_types:
  admin:     [office:rw, calendar:rw, messenger:rw, learning:rw, files:rw]
  office:    [office:rw, calendar:r, messenger:rw, learning:r, files:r]
  instructor:[office:r, calendar:rw, messenger:rw, learning:r, files:rw]
  lecturer:  [calendar:rw, messenger:rw, learning:rw, files:r]
  student:   [calendar:r, messenger:rw, learning:rw, files:r]

6. Modul-System

6.1 Verfügbare Module

Key Name Beschreibung
office Office Kundenverwaltung, Fahrzeugverwaltung, Berichte
calendar Kalender Terminplanung (Integration fahrschultermin.de)
messenger Messenger WhatsApp-ähnlich, DSGVO-konform
learning_blank Lernsoftware (Blanko) Eigene Inhalte erstellen
learning_premium Lernsoftware (Premium) Inkl. vorgefertigter Lerninhalte

6.2 Modul-Zuordnung

  • Jede Fahrschule kann Module einzeln aktivieren/deaktivieren
  • Preise werden pro Modul hinterlegt
  • learning_blank und learning_premium schließen sich gegenseitig aus

7. Billing & Pakete

7.1 Pakete (Beispiel)

Paket Preis/Monat Module Max Users Max Filialen
Starter 49€ Office + Kalender + Messenger 5 1
Professional 99€ Alle Module (Blanko) 20 3
Premium 149€ Alle Module (Premium) Unlimited Unlimited

7.2 Trial

  • 14 Tage kostenlos testen
  • Danach: Admin-Freigabe nötig
  • Trial-End: E-Mail-Erinnerung 3 Tage vorher

7.3 Bezahlung

  • PayPal (monatlich/jährlich)
  • Rechnung (auf Anfrage für Enterprise)
  • Automatische Mahnung bei Überfälligkeit

7.4 Self-Hosted

  • License-Key nötig
  • Keine weiteren Mandanten anlegbar (nur Filialen)
  • Update-Management via License-Key

8. Registration & Freigabe

8.1 Self-Service Flow

1. Fahrschule registriert sich (Name, E-Mail, Password)
2. E-Mail-Verifizierung (Token)
3. Status: "pending_approval"
4. Admin erhält E-Mail: "Neue Registrierung"
5. Admin prüft und genehmigt (oder ablehnen)
6. Status: "active" → Fahrschule kann Login

8.2 Multi-Admin pro Fahrschule

  • Erster Admin = der Registrierer
  • Weitere Admin-Accounts können durch den ersten Admin angelegt werden

9. Branding & Design

9.1 Plattform-Defaults

  • Logo, Farben, Fonts werden durch Plattform vorgegeben
  • Template: Default-Theme für alle neuen Fahrschulen

9.2 Tenant-Branding

Jede Fahrschule kann anpassen:

  • Logo (Header, E-Mails, Rechnungen)
  • Primärfarbe (Buttons, Links, Akzente)
  • Sekundärfarbe
  • Custom CSS (optional, für fortgeschrittene Nutzer)

9.3 E-Mail-Branding

  • Rechnungs-E-Mails mit Logo der Fahrschule
  • E-Mail-Templates pro Tenant individuell

10. Audit-Log

10.1 Plattform-Admin Audit

  • Alle Aktionen aller Tenants einsehbar
  • Filterbar nach Tenant, Aktionstyp, Zeitraum

10.2 Tenant-Admin Audit

  • Nur eigene Fahrschule
  • Alle User-Aktionen geloggt
  • Erfüllt DSGVO-Anforderungen

10.3 Was geloggt wird

  • Login / Logout
  • CRUD-Operationen auf alle Entitäten
  • Änderungen an Benutzern, Modulen, Rechten

11. Messenger (WhatsApp-like)

11.1 Features

  • 1:1 Chat
  • Gruppen-Chat
  • Nachrichten editieren/löschen
  • Timestamps, Read-Receipts
  • Online-Status

11.2 DSGVO

  • Alle Daten auf eigenen Servern
  • Keine externen Dienste (kein Twilio, keine Cloud-Dienste)
  • Export aller Daten möglich (DSGVO-Art. 15)
  • Löschen auf Anfrage (DSGVO-Art. 17)

11.3 Technisch

  • WebSockets für Echtzeit
  • Polling-Fallback wenn WebSockets nicht verfügbar
  • Messages in DB verschlüsselt (für Backend-Zugriff)

12. DKS (Dokumenten-Klasse-System)

12.1 Dateitypen

  • Fahrzeug: Versicherungsunterlagen, TÜV-Berichte, Kennzeichen
  • Fahrschüler: Personalausweis, Sehtest, Erste-Hilfe-Nachweis
  • Fahrlehrer: Führerschein, Lehrberechtigung
  • Filiale: Mietverträge, Gewerbeanmeldung

12.2 Features

  • Upload mit Drag & Drop
  • Dateityp-Kategorisierung
  • Ablage nach Entity (Fahrzeug, Student, etc.)
  • Download
  • Versionierung (neue Datei ersetzt alte, alte bleibt)
  • Ablaufdatum-Erinnerungen (z.B. TÜV)

13. Self-Hosted Option

13.1 Anforderungen

  • PHP 8.2+
  • PostgreSQL 15+
  • 4GB RAM minimum
  • Ubuntu/Debian/CentOS

13.2 Einschränkungen

  • Keine Mandanten anlegbar (nur die eigene Fahrschule)
  • Filialen: Ja (unbegrenzt)
  • User: Ja (gemäß Paket)
  • Updates: Manuell via License-Key

13.3 Installation

  • Docker-Compose für einfache Installation
  • Oder klassisch via Composer + Migration

14. Frontend-Struktur (fahrschuldesk.de)

src/
├── views/
│   ├── auth/
│   │   ├── Login.vue
│   │   ├── Register.vue
│   │   ├── ForgotPassword.vue
│   │   └── VerifyEmail.vue
│   ├── admin/                    (Plattform-Admin)
│   │   ├── Dashboard.vue
│   │   ├── Tenants.vue
│   │   ├── TenantEdit.vue
│   │   ├── Modules.vue
│   │   ├── Invoices.vue
│   │   ├── AuditLog.vue
│   │   └── PlatformAdmins.vue
│   ├── tenant/                   (Fahrschule)
│   │   ├── Dashboard.vue
│   │   ├── Users.vue
│   │   ├── Branches.vue
│   │   ├── Office.vue           (Kunden, Fahrzeuge)
│   │   ├── Calendar.vue         (→ fahrschultermin.de)
│   │   ├── Messenger.vue
│   │   ├── Learning.vue
│   │   ├── Files.vue            (DKS)
│   │   ├── Branding.vue
│   │   └── Billing.vue
│   └── student/                  (Fahrschüler)
│       ├── Dashboard.vue
│       ├── Learning.vue
│       └── Messenger.vue
├── components/
│   ├── common/
│   │   ├── AppHeader.vue
│   │   ├── AppSidebar.vue
│   │   └── ModuleCard.vue
│   ├── messenger/
│   │   ├── ChatWindow.vue
│   │   ├── ConversationList.vue
│   │   └── MessageBubble.vue
│   ├── files/
│   │   ├── FileUploader.vue
│   │   └── FileList.vue
│   └── branding/
│       └── ColorPicker.vue
├── stores/                       (Pinia)
│   ├── auth.js
│   ├── tenant.js
│   ├── modules.js
│   └── messenger.js
├── router/
│   └── index.js
├── api/                          (Axios Client)
│   ├── client.js
│   ├── auth.js
│   ├── admin.js
│   └── tenant.js
└── styles/
    ├── variables.css
    └── theme.css

15. CI/CD Pipeline

# .github/workflows/deploy.yml

name: Deploy

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: PHP Setup
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
          extensions: pgsql, curl
      - name: Run Tests
        run: composer test

  deploy-api:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Sync to Server
        uses: appleboy/scp-action@master
        with:
          host: fahrschuldesk.de
          port: 2225
          username: fahrschuldesk
          key: ${{ secrets.SSH_KEY }}
          source: "api/*"
          target: "/srv/web/fahrschuldesk/domains/api.fahrschuldesk.de/public/"

  deploy-frontend:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Build Vue
        run: |
          npm ci
          npm run build
      - name: Sync to Server
        uses: appleboy/scp-action@master
        with:
          host: fahrschuldesk.de
          port: 2225
          username: fahrschuldesk
          key: ${{ secrets.SSH_KEY }}
          source: "dist/*"
          target: "/srv/web/fahrschuldesk/domains/fahrschuldesk.de/public/"

16. Offene Fragen / Next Steps

  • Tech-Stack final abstimmen (Laravel vs. Slim vs. anderes?)
  • PayPal Integration: API Keys besorgen
  • Design-System erstellen (Default-Theme)
  • OpenAPI Spec schreiben
  • Erste Migration: Alle Tabellen
  • Auth-Flow: Login + Registration + E-Mail-Verifizierung
  • Messenger: WebSocket-Integration planen
  • Self-Hosted: Docker-Compose vorbereiten

17. Phase 1 — Erste Schritte

Ziel: Grundgerüst stehen

  1. DB-Schema: Migrationen schreiben für alle Tabellen
  2. API-Skelett: Auth + Tenant-Registration + Admin-CRUD + Module-CRUD
  3. Frontend-Skelett: Vue 3 + Vite + Router + Pinia + TailwindCSS
  4. Login-Seite: Plattform-Admin Login
  5. Registration: Self-Service + Admin-Freigabe
  6. Admin-Dashboard: Tenants auflisten, anlegen, Module zuweisen
  7. Branding: Logo-Upload, Farben wählen
  8. Audit-Log: Basis-Implementierung

18. Datei-Ablage (Storage)

SaaS

/srv/web/fahrschuldesk/storage/
├── tenants/{tenant_id}/
│   ├── files/
│   │   ├── vehicles/
│   │   ├── students/
│   │   └── ...
│   ├── avatars/
│   └── logos/
└── backups/

Self-Hosted

/var/www/fahrschuldesk/storage/
├── files/
├── avatars/
├── logos/
└── backups/