Aller au contenu principal

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

CoucheTechnologieObjectif
BackendLaravel 12 (PHP 8.4+)Framework applicatif, routage, ORM, file d'attente
Base de donnéesMySQL 8.0+ / MariaDB 10.6+Stockage persistant des données
FrontendBlade + Alpine.js + Tailwind CSSInterface rendue côté serveur avec composants réactifs
PaiementsStripe PHP SDK + PayPal REST APIFacturation des abonnements
IAOpenAI GPT APIAnalyse de sentiment, auto-étiquetage, suggestions de réponses
AuthLaravel SocialiteOAuth Google & GitHub
E-mailLaravel Mail (SMTP)E-mails transactionnels, résumés, rapports
Temps réelServer-Sent Events (SSE)Streaming en direct des soumissions
Planification des tâchesLaravel 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 automatiquement tenant_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é :

  1. Sous-domaineacme.yourdomain.com → recherche le locataire avec le sous-domaine "acme"
  2. Domaine personnaliséfeedback.acmecorp.com → recherche le domaine vérifié dans la table tenant_domains
  3. Utilisateur authentifié — se replie sur le tenant_id de 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ôleAccèsURL de connexion
superadminContrôle complet de la plateforme (/admin/*)/login
tenant_adminContrôle complet du locataire (/dashboard, /settings/*)/login
tenant_staffAccès locataire limité (sans facturation, sans suppression)/login
customerPortail 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

TablePortéeObjectif
tenantsPlateformeComptes multi-locataires
usersPlateformeTous les comptes utilisateur (tous rôles)
plansPlateformePlans d'abonnement
platform_settingsPlateformeConfiguration clé-valeur globale
productsLocataireProduits de retours
feedback_campaignsLocataireConfigurations des formulaires de retours
feedback_submissionsLocataireEntrées de retours individuelles
feedback_tagsLocataireÉtiquettes (many-to-many avec les soumissions)
roadmap_itemsLocataireÉléments kanban de la feuille de route
roadmap_votesLocataireVotes anonymes sur les éléments de la feuille de route
feature_requestsLocataireSuggestions de fonctionnalités de la communauté
changelog_entriesLocataireNotes de version des produits
team_membersLocataireEnregistrements des membres de l'équipe
team_invitationsLocataireInvitations en attente
api_keysLocataireClés d'accès API
audit_logsPlateformePiste d'audit des actions
notificationsPlateformeNotifications in-app
payment_eventsPlateformeÉvénements webhook Stripe/PayPal
webhook_logsLocataireJournaux de livraison des webhooks sortants
data_deletion_requestsLocataireDemandes de suppression RGPD
landing_pagesPlateformeDonnées du constructeur de page d'accueil
tenant_domainsLocataireMappages de domaines personnalisés
referral_codesLocataireCodes de parrainage
referral_conversionsPlateformeSuivi des conversions de parrainage
cron_logsPlateformeJournaux 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é

CoucheProtection
TransportHTTPS imposé, en-têtes HSTS
AuthentificationBcrypt (12 rounds), 2FA optionnel (TOTP)
AutorisationMiddlewares basés sur les rôles + classes de politiques
CSRFJetons CSRF Laravel sur tous les formulaires
XSSAuto-échappement Blade ({{ }})
Injection SQLRequêtes paramétrées Eloquent
Limitation de débitThrottling par route (5-120 req/min)
Sécurité APIClés API hachées SHA256, limites de débit par locataire
Sécurité webhookVérification de signature HMAC (Stripe), protection SSRF
DonnéesParamètres sensibles chiffrés au repos
SessionsCookies chiffrés, HTTP-only, sécurisés
En-têtesCSP, X-Frame-Options, X-Content-Type-Options

Étapes suivantes