Setup Hub
Début: 16 Jan 2026
Application web full-stack — Symfony 8 / Vue.js 3
Projet personnel — en production
Projet personnel — en production
Introduction
SetupHub est une plateforme web complète dédiée au partage de fichiers de réglages (« setups ») pour les simulateurs de course automobile : Le Mans Ultimate, Assetto Corsa Competizione et Assetto Corsa Evo.
Dans le sim racing d’endurance, une équipe partage ses réglages de voiture (fichiers .svm, .json, archives .zip) entre pilotes et ingénieurs. En pratique, cela se fait souvent via Discord : les fichiers se perdent, les versions se mélangent, et personne ne sait quel setup correspond à quelle version du jeu. SetupHub résout ce problème en centralisant les setups par jeu, circuit, voiture et version du jeu, avec un accès restreint aux membres invités de chaque équipe.
L’application repose sur une architecture Symfony 8 (PHP 8.4) côté serveur, avec un front hybride combinant Twig, des composants Vue.js 3 pour les interfaces riches et des contrôleurs Stimulus pour les interactions légères, le tout orchestré par Turbo pour une navigation fluide de type SPA.
Fonctionnalités clés
1. Gestion des setups
- Upload de fichiers de réglages (.svm, .zip) associés à un jeu, un circuit, une voiture et une version du jeu (via VichUploaderBundle).
- Téléchargement unitaire ou téléchargement groupé en archive ZIP de tous les setups d’un contexte.
- Tags personnalisés (Qualif, Course, Endurance, Safe…) et catégorisation fine.
- Tableaux de bord interactifs en Vue.js : liste filtrable, tri, accès rapide aux derniers setups.
2. Équipes et partage sécurisé
- Création d’équipes avec gestion des membres et pseudos personnalisés.
- Quatre canaux d’invitation : code à 6 chiffres à durée de vie limitée, lien sécurisé signé, QR code généré à la volée, invitation par email.
- Permissions métier gérées par des Voters Symfony : chaque action (voir, télécharger, supprimer) est validée en fonction de l’appartenance à l’équipe.
3. Demandes de setups et notifications
- Un pilote peut demander un setup pour un couple circuit/voiture ; la demande est visible par toute l’équipe.
- Auto-fulfillment : lorsqu’un membre uploade un setup correspondant, la demande est automatiquement clôturée et le demandeur notifié.
- Cloche de notifications temps réel dans la navbar (badge Stimulus + endpoint JSON), notifications email via Brevo avec opt-out par utilisateur, traitement asynchrone par Symfony Messenger.
4. Suivi de performance
- Enregistrement des temps au tour par pilote, circuit, voiture et setup.
- Composant Vue dédié (LapTimeManager) pour saisir et comparer les chronos de l’équipe.
5. Espace public et SEO
- Pages publiques par jeu optimisées pour le référencement : meta tags dynamiques, robots.txt et sitemap.xml générés par contrôleurs dédiés.
- Pages légales, FAQ, guide d’utilisation et formulaire de contact.
6. Administration
- Back-office complet avec EasyAdmin 4 : gestion des jeux, circuits, voitures, versions, utilisateurs et messages de contact.
- Rôles hiérarchiques (ROLE_USER < ROLE_ADMIN < ROLE_SUPER_ADMIN) et vérification d’email obligatoire avant connexion (UserChecker + VerifyEmailBundle).
Architecture
Le projet suit une architecture en couches stricte, documentée et appliquée par tooling :
CoucheRôleController | final class à méthode __invoke() unique — une route = un contrôleur, zéro logique métier
Service | final readonly class — logique métier pure, injection par constructeur
Repository | Requêtes DQL uniquement
DTO | Transport et validation des données entrantes (#[MapRequestPayload], #[Assert\...])
Voter | Autorisations complexes sur les entités (équipe, propriété)
Event / Listener | Side-effects découplés (#[AsEventListener]) : emails, notifications, auto-fulfillment
Service | final readonly class — logique métier pure, injection par constructeur
Repository | Requêtes DQL uniquement
DTO | Transport et validation des données entrantes (#[MapRequestPayload], #[Assert\...])
Voter | Autorisations complexes sur les entités (équipe, propriété)
Event / Listener | Side-effects découplés (#[AsEventListener]) : emails, notifications, auto-fulfillment
Quelques choix structurants :
- UUID comme identifiants pour toutes les entités principales (les entités de type « log » restent en auto-increment).
- Doctrine Extensions (Gedmo) : timestampable, blameable et soft-delete via traits.
- Séparation claire entre contrôleurs HTML (App\Controller\*, rendu Twig) et contrôleurs API (App\Controller\Api\*, JSON) consommés par les composants Vue.
- Côté front, une règle simple : interaction légère → Stimulus, composant réactif → Vue 3. Les mutations passent systématiquement par un token CSRF (X-CSRF-Token) et l’en-tête X-Requested-With.
Stack technique
Backend
- PHP 8.4 avec strict_types et typage strict généralisé
- Symfony 8.0 (Messenger, Mailer/Brevo, Scheduler, Security)
- Doctrine ORM 3 + MySQL 8 (Docker)
- VichUploaderBundle (upload de fichiers), EasyAdmin 4 (back-office)
- SymfonyCasts VerifyEmailBundle (vérification d’email)
Frontend
- Vue.js 3 (Composition API) pour les composants riches : upload, tableaux de setups, gestion des temps au tour, modale de partage
- Stimulus 3 + Turbo 8 (Hotwired) pour les interactions légères et la navigation
- Tailwind CSS 4 + DaisyUI 5 avec thèmes custom clair/sombre en oklch()
- Vite + vite-plugin-symfony (HMR en développement)
Qualité & outillage
- PHPStan niveau 6, PHP CS Fixer (PSR-12 + Symfony), Rector (sets PHP 8.3 / Symfony 8)
- PHPUnit 12 avec base de données de test dédiée
- GrumPHP en hook pre-commit : la qualité est vérifiée avant chaque commit
- Docker Compose + Makefile pour un environnement reproductible
Défis techniques relevés
- Partage multi-canaux sécurisé — concevoir un système d’invitation combinant codes courts expirables, liens signés et QR codes, sans jamais exposer les setups d’une équipe à un non-membre. Chaque point d’entrée est protégé par CSRF et validé par Voter.
- Auto-fulfillment des demandes — relier le flux d’upload au cycle de vie des demandes de setups via des événements métier, avec contrôle d’appartenance à l’équipe pour empêcher la clôture d’une demande par un tiers.
- Front hybride cohérent — faire cohabiter Twig, Turbo, Stimulus et Vue 3 dans une même application sans conflit de cycle de vie, en assignant à chaque outil un périmètre précis.
- Discipline architecturale — maintenir des règles strictes (un contrôleur = une route, services readonly, aucun SQL hors repository) grâce à l’analyse statique et aux hooks pre-commit, plutôt que par convention orale.
Roadmap
Le projet évolue selon une roadmap en quatre phases : notations et commentaires sur les setups, rôles d’équipe avancés (ingénieur/pilote) avec validation des setups « officiels », parsing automatique des fichiers .svm/.json pour afficher les réglages sans ouvrir le jeu, module de télémétrie, et à terme un modèle freemium avec espace coach.
Conclusion
Ce projet m’a permis d’approfondir l’écosystème Symfony moderne (Messenger, Scheduler, Voters, événements métier) sur un cas d’usage réel, avec de vrais utilisateurs : mon équipe de sim racing. Au-delà des fonctionnalités, l’accent a été mis sur la rigueur architecturale — typage strict, couches étanches, analyse statique — et sur la sécurité (CSRF, permissions par Voter, vérification d’email, liens signés). C’est une base saine qui continue d’évoluer, notamment vers le parsing automatique des fichiers de réglages et l’analyse de télémétrie.
Technologies Utilisées
Docker
MySQL
PHP
Vue.js