Pattern — tableau de bord modulaire
Pattern réutilisable validé en prod sur le back-office
codexia(/admin, v0.5.0, 2026-06-01). À suivre par toute instance qui veut donner à un module une présence sur le tableau de bord sans coupler ce dernier aux données internes du module.
Problème
Un tableau de bord d'administration agrège des informations de plusieurs domaines (veille, RAG, conso API, comptes…). L'écueil classique : le contrôleur du dashboard interroge directement les repositories de chaque domaine, accumule la logique de tous les modules, et devient un point de couplage qui casse à chaque évolution d'un module.
Principe — chaque module expose sa propre carte
Le dashboard ne fait que composer ; chaque module rend sa carte.
- Chaque module expose une action
card()(protégéeROLE_ADMIN) sur son contrôleur d'admin. Elle rend un partial dédiétemplates/admin/dashboard/_<module>.html.twig: une synthèse (les chiffres essentiels) + les actions clés du module. - Le tableau de bord
/adminne fait que composer, via des sous-requĂŞtes (fragments Symfony) :{{ render(controller('App\\Controller\\Admin\\VeilleDashboardController::card')) }} {{ render(controller('App\\Controller\\Admin\\MetricsController::card')) }} {{ render(controller('App\\Controller\\Admin\\RagController::card')) }} {{ render(controller('App\\Controller\\Admin\\UserController::card')) }}
Le dashboard ignore ce que chaque carte contient : il n'a aucune connaissance des données internes des modules.
Bénéfices
- Modules autonomes, zéro couplage : la logique de présentation et de requête d'un module reste dans son contrôleur. Le dashboard ne référence jamais un repository de domaine.
- Ajouter un module au dashboard = une ligne
render(controller(...)). Le retirer = supprimer cette ligne. Aucune autre modification du dashboard. - Évolution isolée : changer les chiffres d'une carte ne touche que le module concerné.
Convention de carte
- Bloc Bootstrap
card:header= titre du module ·body= chiffres clés ·footer= boutons d'action. - Dégradation propre : si la donnée est indisponible (ex. RAG sans index, microservice down), la carte affiche un état dégradé clair (bannière/message) plutôt que de planter le dashboard entier. Une sous-requête qui échoue ne doit pas faire tomber la page.
- Accessibilité RGAA AA comme toute surface UI (cf.
accessibility.md) ; rendu serveur, pas de logique métier dans le Twig.
Conséquence observée
Sur codexia, la page dédiée /admin/veille a disparu : son contenu est devenu la carte Veille du dashboard (la route redirige). Quand une carte porte l'essentiel, la page séparée n'a plus de raison d'être — un clic en moins.
Quand NE pas l'appliquer
- Un seul module : pas de dashboard, pas de pattern — la page du module suffit.
- Une vue qui a besoin d'une corrélation entre modules (jointure de données de plusieurs domaines) : ce n'est plus une composition de cartes indépendantes, ça relève d'un service de reporting dédié. Le pattern vaut pour des cartes autonomes, pas pour de l'agrégation transverse.
Voir aussi
- Spec back-office :
specs/telaria-admin.md. - Style applicatif (Twig sans logique métier, sobriété) :
pilotage/telaria-style.md.