# 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 ```yaml # .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/ ```