Zum Hauptinhalt springen

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

SchichtTechnologieZweck
BackendLaravel 12 (PHP 8.4+)Anwendungs-Framework, Routing, ORM, Queue
DatenbankMySQL 8.0+ / MariaDB 10.6+Persistente Datenspeicherung
FrontendBlade + Alpine.js + Tailwind CSSServer-gerendertes UI mit reaktiven Komponenten
ZahlungenStripe PHP SDK + PayPal REST APIAbonnement-Abrechnung
KIOpenAI GPT APIStimmungsanalyse, Auto-Tagging, Antwortvorschläge
AuthLaravel SocialiteGoogle & GitHub OAuth
E-MailLaravel Mail (SMTP)Transaktions-E-Mails, Digests, Berichte
EchtzeitServer-Sent Events (SSE)Live-Einreichungs-Streaming
AufgabenplanungLaravel 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üllt tenant_id bei 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:

  1. Subdomainacme.yourdomain.com → sucht den Mandanten mit der Subdomain "acme"
  2. Benutzerdefinierte Domainfeedback.acmecorp.com → sucht die verifizierte Domain in der Tabelle tenant_domains
  3. Authentifizierter Benutzer — fällt auf die tenant_id des 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:

RolleZugriffLogin-URL
superadminVollständige Plattformkontrolle (/admin/*)/login
tenant_adminVollständige Mandantenkontrolle (/dashboard, /settings/*)/login
tenant_staffEingeschränkter Mandantenzugriff (kein Billing, kein Löschen)/login
customerNur 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

TabelleZeilen proZweck
tenantsPlattformMulti-Tenant-Konten
usersPlattformAlle Benutzerkonten (alle Rollen)
plansPlattformAbonnementpläne
platform_settingsPlattformGlobale Schlüssel-Wert-Konfiguration
productsMandantFeedback-Produkte
feedback_campaignsMandantFeedback-Formularkonfigurationen
feedback_submissionsMandantEinzelne Feedback-Einträge
feedback_tagsMandantTags (Viele-zu-Viele mit Einreichungen)
roadmap_itemsMandantRoadmap-Kanban-Elemente
roadmap_votesMandantAnonyme Abstimmungen für Roadmap-Elemente
feature_requestsMandantCommunity-Feature-Vorschläge
changelog_entriesMandantProdukt-Release-Notes
team_membersMandantTeammitglieder-Datensätze
team_invitationsMandantAusstehende Einladungen
api_keysMandantAPI-Zugriffsschlüssel
audit_logsPlattformAktions-Auditprotokoll
notificationsPlattformIn-App-Benachrichtigungen
payment_eventsPlattformStripe/PayPal-Webhook-Ereignisse
webhook_logsMandantAusgehende Webhook-Zustellungsprotokolle
data_deletion_requestsMandantDSGVO-Löschanfragen
landing_pagesPlattformLanding-Page-Builder-Daten
tenant_domainsMandantBenutzerdefinierte Domain-Zuordnungen
referral_codesMandantEmpfehlungscodes
referral_conversionsPlattformTracking von Empfehlungskonversionen
cron_logsPlattformAusfü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

SchichtSchutz
TransportHTTPS erzwungen, HSTS-Header
AuthentifizierungBcrypt (12 Runden), optionale 2FA (TOTP)
AutorisierungRollenbasierte Middleware + Policy-Klassen
CSRFLaravel-CSRF-Tokens auf allen Formularen
XSSBlade Auto-Escaping ({{ }})
SQL-InjectionEloquent parametrisierte Abfragen
Rate-LimitingPro-Route-Drosselung (5–120 Req/Min)
API-SicherheitSHA256-gehashte API-Schlüssel, mandantenspezifische Rate-Limits
Webhook-SicherheitHMAC-Signaturverifizierung (Stripe), SSRF-Schutz
DatenSensible Einstellungen verschlüsselt gespeichert
SessionsVerschlüsselt, HTTP-only, sichere Cookies
HeaderCSP, X-Frame-Options, X-Content-Type-Options

Nächste Schritte