Architecture du Système
Cette page présente une analyse approfondie de la façon dont FeedbackPulse SaaS est construit. Comprendre l'architecture vous aide à déboguer les problèmes, étendre la plateforme et prendre des décisions de déploiement éclairées.
Stack technique
| Couche | Technologie | Objectif |
|---|---|---|
| Backend | Laravel 12 (PHP 8.4+) | Framework applicatif, routage, ORM, file d'attente |
| Base de données | MySQL 8.0+ / MariaDB 10.6+ | Stockage persistant des données |
| Frontend | Blade + Alpine.js + Tailwind CSS | Interface rendue côté serveur avec composants réactifs |
| Paiements | Stripe PHP SDK + PayPal REST API | Facturation des abonnements |
| IA | OpenAI GPT API | Analyse de sentiment, auto-étiquetage, suggestions de réponses |
| Auth | Laravel Socialite | OAuth Google & GitHub |
| Laravel Mail (SMTP) | E-mails transactionnels, résumés, rapports | |
| Temps réel | Server-Sent Events (SSE) | Streaming en direct des soumissions |
| Planification des tâches | Laravel Scheduler (cron) | Résumés, expiration des essais, conservation des données |
Modèle multi-locataire
FeedbackPulse utilise un modèle multi-locataire à base de données unique et schéma partagé. Cela signifie :
- Une seule base de données sert tous les locataires
- Chaque table à portée locataire possède une colonne
tenant_id - Un scope global (
TenantScope) filtre automatiquement toutes les requêtes vers le locataire actuel - Un trait (
BelongsToTenant) remplit automatiquementtenant_idà la création et applique le scope
Comment fonctionne la résolution de locataire
Lorsqu'une requête arrive, le middleware ResolveTenant détermine le locataire actuel selon cette priorité :
- Sous-domaine —
acme.yourdomain.com→ recherche le locataire avec le sous-domaine "acme" - Domaine personnalisé —
feedback.acmecorp.com→ recherche le domaine vérifié dans la tabletenant_domains - Utilisateur authentifié — se replie sur le
tenant_idde l'utilisateur connecté
Pour les pages publiques (comme /wall/acme-corp), le locataire est résolu depuis le slug de l'URL directement dans le contrôleur (en contournant le middleware).
Isolation des données
+------------------------------------------+
| Base de données |
| |
| products (tenant_id = 1) -> Données Acme |
| products (tenant_id = 2) -> TechCorp |
| products (tenant_id = 3) -> E-Commerce |
| |
| TenantScope garantit qu'Acme ne voit |
| que les lignes où tenant_id = 1 |
+------------------------------------------+
Sécurité : Les contrôleurs publics utilisent
withoutGlobalScopes()pour contourner le scope locataire, puis filtrent manuellement par ID de locataire. C'est intentionnel — les pages publiques doivent afficher des données sans session authentifiée.
Structure des répertoires
feedbackpulse-saas/
+-- app/
| +-- Console/Commands/ # 7 commandes artisan (résumés, conservation, alertes)
| +-- Http/
| | +-- Controllers/
| | | +-- Admin/ # Contrôleurs du panneau super-admin
| | | +-- Auth/ # Connexion, inscription, 2FA, OAuth, usurpation
| | | +-- Customer/ # Portail client
| | | +-- Public/ # Pages publiques (mur, formulaire, feuille de route, journal, hub)
| | | +-- Tenant/ # Contrôleurs du tableau de bord locataire
| | | +-- Webhooks/ # Gestionnaires webhook Stripe & PayPal
| | +-- Middleware/ # 15 middlewares personnalisés
| +-- Mail/ # 7 classes mailable
| +-- Models/ # 28 modèles Eloquent
| +-- Scopes/ # TenantScope (scope de requête global)
| +-- Services/ # Logique métier (IA, paiements, webhooks, etc.)
| +-- Traits/ # Trait BelongsToTenant
| +-- Providers/ # Fournisseurs de services
+-- config/ # 11 fichiers de configuration Laravel
+-- database/
| +-- migrations/ # Plus de 35 fichiers de migration
| +-- seeders/ # Seeders de données de démonstration
+-- public/ # Racine web (index.php, ressources, lien symbolique de stockage)
+-- resources/views/ # 86 templates Blade
| +-- admin/ # Vues super-admin
| +-- auth/ # Vues d'authentification (connexion, inscription, 2FA)
| +-- tenant/ # Vues du tableau de bord locataire
| +-- public/ # Vues des pages publiques
| +-- emails/ # Templates d'e-mails
| +-- layouts/ # Templates de mise en page (admin, locataire, invité, install)
| +-- partials/ # Composants partagés (nav, meta, palette de commandes)
| +-- install/ # Vues de l'installateur web
| +-- legal/ # Pages confidentialité, CGU, cookies
| +-- errors/ # Pages d'erreur (403, 404, 419, 429, 500)
| +-- landing/ # Parties de la page d'accueil
+-- routes/
| +-- web.php # 416 lignes de routes web
| +-- api.php # Routes API v2
+-- storage/ # Téléversements, cache, sessions, journaux
+-- bootstrap/ # Fichiers de démarrage du framework
Rôles utilisateur
FeedbackPulse dispose de quatre rôles utilisateur, stockés dans la colonne users.role :
| Rôle | Accès | URL de connexion |
|---|---|---|
superadmin | Contrôle complet de la plateforme (/admin/*) | /login |
tenant_admin | Contrôle complet du locataire (/dashboard, /settings/*) | /login |
tenant_staff | Accès locataire limité (sans facturation, sans suppression) | /login |
customer | Portail client uniquement (/customer/dashboard) | /customer/login |
Hiérarchie des rôles
superadmin
+-- Peut usurper l'identité de tout tenant_admin
+-- tenant_admin
+-- Peut inviter des tenant_staff
+-- Peut gérer la facturation, les paramètres, l'équipe
+-- tenant_staff
+-- Peut gérer les soumissions, les campagnes
+-- customer
+-- Peut voir ses propres retours
Cycle de vie des requêtes
Voici ce qui se passe lorsqu'une requête arrive dans FeedbackPulse :
Requête du navigateur
|
v
public/index.php
|
v
Kernel Laravel (pile de middlewares)
|
+-- EnsureInstalled -> Redirection vers /install si non configuré
+-- SecurityHeaders -> Ajout HSTS, CSP, X-Frame-Options
+-- VerifyCsrfToken -> Vérification du jeton CSRF (sauf webhooks)
+-- ResolveTenant -> Détermination du locataire actuel
+-- Authenticate -> Vérification de la connexion de l'utilisateur
+-- EnsureTenantAccess -> Vérification que l'utilisateur appartient au locataire
+-- EnsureTwoFactorVerified -> Vérification 2FA si activé
+-- CheckPlanLimit -> Application des limites du plan
|
v
Contrôleur (traite la requête)
|
v
Vue Blade (génère le HTML)
|
v
Réponse -> Navigateur
Architecture de la base de données
Tables principales
| Table | Portée | Objectif |
|---|---|---|
tenants | Plateforme | Comptes multi-locataires |
users | Plateforme | Tous les comptes utilisateur (tous rôles) |
plans | Plateforme | Plans d'abonnement |
platform_settings | Plateforme | Configuration clé-valeur globale |
products | Locataire | Produits de retours |
feedback_campaigns | Locataire | Configurations des formulaires de retours |
feedback_submissions | Locataire | Entrées de retours individuelles |
feedback_tags | Locataire | Étiquettes (many-to-many avec les soumissions) |
roadmap_items | Locataire | Éléments kanban de la feuille de route |
roadmap_votes | Locataire | Votes anonymes sur les éléments de la feuille de route |
feature_requests | Locataire | Suggestions de fonctionnalités de la communauté |
changelog_entries | Locataire | Notes de version des produits |
team_members | Locataire | Enregistrements des membres de l'équipe |
team_invitations | Locataire | Invitations en attente |
api_keys | Locataire | Clés d'accès API |
audit_logs | Plateforme | Piste d'audit des actions |
notifications | Plateforme | Notifications in-app |
payment_events | Plateforme | Événements webhook Stripe/PayPal |
webhook_logs | Locataire | Journaux de livraison des webhooks sortants |
data_deletion_requests | Locataire | Demandes de suppression RGPD |
landing_pages | Plateforme | Données du constructeur de page d'accueil |
tenant_domains | Locataire | Mappages de domaines personnalisés |
referral_codes | Locataire | Codes de parrainage |
referral_conversions | Plateforme | Suivi des conversions de parrainage |
cron_logs | Plateforme | Journaux d'exécution des tâches planifiées |
Index clés
Toutes les tables à portée locataire sont indexées sur (tenant_id, created_at) pour des performances de requête optimales. La table feedback_submissions possède des index supplémentaires sur status, product_id, campaign_id et sentiment_label.
Architecture de sécurité
| Couche | Protection |
|---|---|
| Transport | HTTPS imposé, en-têtes HSTS |
| Authentification | Bcrypt (12 rounds), 2FA optionnel (TOTP) |
| Autorisation | Middlewares basés sur les rôles + classes de politiques |
| CSRF | Jetons CSRF Laravel sur tous les formulaires |
| XSS | Auto-échappement Blade ({{ }}) |
| Injection SQL | Requêtes paramétrées Eloquent |
| Limitation de débit | Throttling par route (5-120 req/min) |
| Sécurité API | Clés API hachées SHA256, limites de débit par locataire |
| Sécurité webhook | Vérification de signature HMAC (Stripe), protection SSRF |
| Données | Paramètres sensibles chiffrés au repos |
| Sessions | Cookies chiffrés, HTTP-only, sécurisés |
| En-têtes | CSP, X-Frame-Options, X-Content-Type-Options |
Étapes suivantes
- Glossaire des termes — comprendre la terminologie
- Guide d'installation — configurer votre serveur
- Schéma de la base de données — structures détaillées des tables