Systemarchitektur
Diese Seite bietet einen tiefen Einblick in den Aufbau von FeedbackPulse SaaS. Das Verständnis der Architektur hilft Ihnen, Probleme zu beheben, die Plattform zu erweitern und fundierte Deployment-Entscheidungen zu treffen.
Technologie-Stack
| Schicht | Technologie | Zweck |
|---|---|---|
| Backend | Laravel 12 (PHP 8.4+) | Anwendungs-Framework, Routing, ORM, Queue |
| Datenbank | MySQL 8.0+ / MariaDB 10.6+ | Persistente Datenspeicherung |
| Frontend | Blade + Alpine.js + Tailwind CSS | Server-gerendertes UI mit reaktiven Komponenten |
| Zahlungen | Stripe PHP SDK + PayPal REST API | Abonnement-Abrechnung |
| KI | OpenAI GPT API | Stimmungsanalyse, Auto-Tagging, Antwortvorschläge |
| Auth | Laravel Socialite | Google & GitHub OAuth |
| Laravel Mail (SMTP) | Transaktions-E-Mails, Digests, Berichte | |
| Echtzeit | Server-Sent Events (SSE) | Live-Einreichungs-Streaming |
| Aufgabenplanung | Laravel Scheduler (Cron) | Digests, Testlaufablauf, Datenspeicherung |
Mandantenmodell
FeedbackPulse verwendet ein Single-Database, Shared-Schema Multi-Tenancy-Modell. Das bedeutet:
- Eine Datenbank bedient alle Mandanten
- Jede mandantenspezifische Tabelle hat eine
tenant_id-Spalte - Ein globaler Scope (
TenantScope) filtert alle Abfragen automatisch auf den aktuellen Mandanten - Ein Trait (
BelongsToTenant) füllttenant_idbei der Erstellung automatisch aus und wendet den Scope an
Wie die Mandantenauflösung funktioniert
Wenn eine Anfrage eingeht, bestimmt die ResolveTenant-Middleware den aktuellen Mandanten anhand dieser Priorität:
- Subdomain —
acme.yourdomain.com→ sucht den Mandanten mit der Subdomain "acme" - Benutzerdefinierte Domain —
feedback.acmecorp.com→ sucht die verifizierte Domain in der Tabelletenant_domains - Authentifizierter Benutzer — fällt auf die
tenant_iddes angemeldeten Benutzers zurück
Bei öffentlichen Seiten (wie /wall/acme-corp) wird der Mandant direkt im Controller aus dem URL-Slug aufgelöst (unter Umgehung der Middleware).
Datenisolation
+------------------------------------------+
| Datenbank |
| |
| products (tenant_id = 1) -> Acme-Daten |
| products (tenant_id = 2) -> TechCorp |
| products (tenant_id = 3) -> E-Commerce |
| |
| TenantScope stellt sicher, dass Acme |
| NUR Zeilen mit tenant_id = 1 sieht |
+------------------------------------------+
Sicherheit: Öffentlich zugängliche Controller verwenden
withoutGlobalScopes(), um den Tenant-Scope zu umgehen, und filtern dann manuell nach Mandanten-ID. Dies ist beabsichtigt — öffentliche Seiten müssen Daten ohne authentifizierte Session anzeigen.
Verzeichnisstruktur
feedbackpulse-saas/
+-- app/
| +-- Console/Commands/ # 7 Artisan-Befehle (Digests, Retention, Alerts)
| +-- Http/
| | +-- Controllers/
| | | +-- Admin/ # Superadmin-Panel-Controller
| | | +-- Auth/ # Login, Registrierung, 2FA, OAuth, Impersonation
| | | +-- Customer/ # Kundenportal
| | | +-- Public/ # Öffentliche Seiten (Wall, Form, Roadmap, Changelog, Hub)
| | | +-- Tenant/ # Tenant-Dashboard-Controller
| | | +-- Webhooks/ # Stripe & PayPal Webhook-Handler
| | +-- Middleware/ # 15 benutzerdefinierte Middleware
| +-- Mail/ # 7 Mailable-Klassen
| +-- Models/ # 28 Eloquent-Modelle
| +-- Scopes/ # TenantScope (globaler Abfrage-Scope)
| +-- Services/ # Geschäftslogik (KI, Zahlungen, Webhooks, etc.)
| +-- Traits/ # BelongsToTenant-Trait
| +-- Providers/ # Service-Provider
+-- config/ # 11 Laravel-Konfigurationsdateien
+-- database/
| +-- migrations/ # 35+ Migrationsdateien
| +-- seeders/ # Demo-Datenseeder
+-- public/ # Web-Root (index.php, Assets, Storage-Symlink)
+-- resources/views/ # 86 Blade-Templates
| +-- admin/ # Superadmin-Views
| +-- auth/ # Auth-Views (Login, Registrierung, 2FA)
| +-- tenant/ # Tenant-Dashboard-Views
| +-- public/ # Öffentliche Seiten-Views
| +-- emails/ # E-Mail-Templates
| +-- layouts/ # Layout-Templates (Admin, Tenant, Gast, Installation)
| +-- partials/ # Gemeinsame Komponenten (Nav, Meta, Befehlspalette)
| +-- install/ # Web-Installer-Views
| +-- legal/ # Datenschutz-, AGB-, Cookie-Seiten
| +-- errors/ # Fehlerseiten (403, 404, 419, 429, 500)
| +-- landing/ # Landing-Page-Partials
+-- routes/
| +-- web.php # 416 Zeilen Web-Routen
| +-- api.php # API v2-Routen
+-- storage/ # Uploads, Cache, Sessions, Logs
+-- bootstrap/ # Framework-Bootstrap-Dateien
Benutzerrollen
FeedbackPulse hat vier Benutzerrollen, die in der Spalte users.role gespeichert sind:
| Rolle | Zugriff | Login-URL |
|---|---|---|
superadmin | Vollständige Plattformkontrolle (/admin/*) | /login |
tenant_admin | Vollständige Mandantenkontrolle (/dashboard, /settings/*) | /login |
tenant_staff | Eingeschränkter Mandantenzugriff (kein Billing, kein Löschen) | /login |
customer | Nur Kundenportal (/customer/dashboard) | /customer/login |
Rollenhierarchie
superadmin
+-- Kann jeden tenant_admin imitieren
+-- tenant_admin
+-- Kann tenant_staff einladen
+-- Kann Billing, Einstellungen, Team verwalten
+-- tenant_staff
+-- Kann Einreichungen, Kampagnen verwalten
+-- customer
+-- Kann eigenes Feedback einsehen
Anfrage-Lebenszyklus
So läuft eine Anfrage durch FeedbackPulse ab:
Browser-Anfrage
|
v
public/index.php
|
v
Laravel-Kernel (Middleware-Stack)
|
+-- EnsureInstalled -> Weiterleitung zu /install, falls nicht eingerichtet
+-- SecurityHeaders -> HSTS, CSP, X-Frame-Options hinzufügen
+-- VerifyCsrfToken -> CSRF-Token prüfen (außer Webhooks)
+-- ResolveTenant -> Aktuellen Mandanten bestimmen
+-- Authenticate -> Prüfen ob Benutzer eingeloggt ist
+-- EnsureTenantAccess -> Prüfen ob Benutzer zum Mandanten gehört
+-- EnsureTwoFactorVerified -> 2FA prüfen, falls aktiviert
+-- CheckPlanLimit -> Plan-Featuregrenzen durchsetzen
|
v
Controller (verarbeitet Anfrage)
|
v
Blade-View (rendert HTML)
|
v
Antwort -> Browser
Datenbankarchitektur
Kerntabellen
| Tabelle | Zeilen pro | Zweck |
|---|---|---|
tenants | Plattform | Multi-Tenant-Konten |
users | Plattform | Alle Benutzerkonten (alle Rollen) |
plans | Plattform | Abonnementpläne |
platform_settings | Plattform | Globale Schlüssel-Wert-Konfiguration |
products | Mandant | Feedback-Produkte |
feedback_campaigns | Mandant | Feedback-Formularkonfigurationen |
feedback_submissions | Mandant | Einzelne Feedback-Einträge |
feedback_tags | Mandant | Tags (Viele-zu-Viele mit Einreichungen) |
roadmap_items | Mandant | Roadmap-Kanban-Elemente |
roadmap_votes | Mandant | Anonyme Abstimmungen für Roadmap-Elemente |
feature_requests | Mandant | Community-Feature-Vorschläge |
changelog_entries | Mandant | Produkt-Release-Notes |
team_members | Mandant | Teammitglieder-Datensätze |
team_invitations | Mandant | Ausstehende Einladungen |
api_keys | Mandant | API-Zugriffsschlüssel |
audit_logs | Plattform | Aktions-Auditprotokoll |
notifications | Plattform | In-App-Benachrichtigungen |
payment_events | Plattform | Stripe/PayPal-Webhook-Ereignisse |
webhook_logs | Mandant | Ausgehende Webhook-Zustellungsprotokolle |
data_deletion_requests | Mandant | DSGVO-Löschanfragen |
landing_pages | Plattform | Landing-Page-Builder-Daten |
tenant_domains | Mandant | Benutzerdefinierte Domain-Zuordnungen |
referral_codes | Mandant | Empfehlungscodes |
referral_conversions | Plattform | Tracking von Empfehlungskonversionen |
cron_logs | Plattform | Ausführungsprotokolle geplanter Aufgaben |
Wichtige Indizes
Alle mandantenspezifischen Tabellen sind auf (tenant_id, created_at) für optimale Abfrage-Performance indiziert. Die Tabelle feedback_submissions hat zusätzliche Indizes auf status, product_id, campaign_id und sentiment_label.
Sicherheitsarchitektur
| Schicht | Schutz |
|---|---|
| Transport | HTTPS erzwungen, HSTS-Header |
| Authentifizierung | Bcrypt (12 Runden), optionale 2FA (TOTP) |
| Autorisierung | Rollenbasierte Middleware + Policy-Klassen |
| CSRF | Laravel-CSRF-Tokens auf allen Formularen |
| XSS | Blade Auto-Escaping ({{ }}) |
| SQL-Injection | Eloquent parametrisierte Abfragen |
| Rate-Limiting | Pro-Route-Drosselung (5–120 Req/Min) |
| API-Sicherheit | SHA256-gehashte API-Schlüssel, mandantenspezifische Rate-Limits |
| Webhook-Sicherheit | HMAC-Signaturverifizierung (Stripe), SSRF-Schutz |
| Daten | Sensible Einstellungen verschlüsselt gespeichert |
| Sessions | Verschlüsselt, HTTP-only, sichere Cookies |
| Header | CSP, X-Frame-Options, X-Content-Type-Options |
Nächste Schritte
- Glossar der Begriffe — Terminologie verstehen
- Installationsanleitung — Server einrichten
- Datenbankschema — Detaillierte Tabellenstrukturen