Atos Portal
- Drupal 10
- PHP 8.2
- JSON:API
- Next.js
- React
- Tailwind CSS
- Redis
- MySQL
- Docker
- Nginx
Atos est un groupe de services technologiques présent dans plus de 70 pays. Son site public était devenu impossible à mettre à jour sans développeur : l'agence que j'ai rejointe l'a donc reconstruit intégralement. J'ai livré trois de ses sept systèmes de contenu — et corrigé au passage trois bugs dans le framework de l'agence.
- 20Régions desservies
- 9Langues
- 300+Webmasters simultanés
- 91 / 94 / 92Lighthouse perf / a11y / pratiques
- 179 msTTFB — budget de 800 ms
Le brief
Atos est un groupe international de services technologiques présent dans plus de 70 pays, avec près de 100 000 employés — partenaire informatique mondial des Jeux Olympiques et Paralympiques. Son portail corporate est la porte d'entrée publique pour les clients, les investisseurs, les partenaires et les candidats. Atos a confié la refonte complète à VOID Agency, et j'en ai livré une partie dans le cadre de mon projet de fin d'études de six mois, au sein d'une équipe agile de huit personnes.
Pourquoi l'ancien portail devait disparaître
La plateforme historique était un monolithe WordPress avec quatre défaillances structurelles :
- Paralysie éditoriale. Chaque changement de mise en page, chaque nouvelle section, chaque variation régionale nécessitait un développeur. Des équipes éditoriales réparties sur plusieurs continents étaient bloquées sur des tâches aussi simples que la publication d'un communiqué de presse.
- Un modèle de contenu plat. Communiqués de presse, distinctions, annonces d'événements et rapports de recherche vivaient tous dans une structure indifférenciée — aucun champ distinct, aucune sémantique, rendant impossibles un filtrage précis et un ciblage régional.
- Un SEO international cassé. Les balises
hreflangétaient systématiquement mal formées : mauvais codes régionaux,x-defaultmanquant, URLs non canoniques. Des visiteurs anglophones se voyaient servir des pages en arabe. Sur 70 marchés, les dégâts s'accumulaient. - Des budgets de performance hors de portée. Le rendu PHP à la demande de chaque page rendait les seuils des Core Web Vitals inatteignables.
L'architecture découplée
La réponse a été une architecture headless. Drupal 10 est devenu un pur référentiel de contenu, isolé derrière un réseau privé et accessible uniquement via des points d'accès JSON:API filtrés — ce qui supprime entièrement la surface d'attaque publique. Next.js génère le site public, pré-générant les pages statiquement (SSG) et les rafraîchissant en arrière-plan à chaque changement de contenu (ISR), avec Redis absorbant la charge de lecture. L'ensemble tourne conteneurisé via Docker Compose en local, Easypanel en recette et AWS en production.
Tout repose sur Vactory, le framework d'entreprise propriétaire de VOID construit sur le principe de Software Product Line, permettant de partager des modules entre les trois portails du groupe — Atos Groupe (déjà en ligne), Atos (ce projet) et Eviden (à venir).
Ce dont j'avais la responsabilité
Le portail compte sept types de contenu éditorial répartis en deux familles. Trois étaient entièrement les miens — Case Studies, Research Reports et Events & Webinars — depuis la modélisation des entités Drupal et les normalizers JSON:API jusqu'aux composants React. J'ai ensuite audité et corrigé les quatre modules construits par le reste de l'équipe avant la livraison finale.
Un second sprint a livré le système Featured : sept widgets permettant aux webmasters de choisir manuellement le contenu prioritaire sur n'importe quelle page de liste, rendu sous forme de carte héro pour la famille Insights ou de carrousel animé pour la famille Newsroom.
Moteur Insights
Trois des sept modules de contenu du portail, pris en charge de bout en bout : Case Studies (liées de manière croisée aux rapports et livres blancs), Research Reports (téléchargements de PDF verrouillés via Adobe Marketo) et Events & Webinars (intervenants dynamiques construits sur l'API Paragraphs de Drupal, avec un CTA d'inscription qui ne s'affiche que tant que l'événement est à venir).
Système Featured
Sept widgets répartis sur deux familles éditoriales, tous délégant à une même couche de rendu partagée — une carte héro pour Insights, un carrousel à défilement automatique de 7 secondes avec indicateurs de progression, pause au survol et swipe pour Newsroom. Un huitième widget ne nécessiterait qu'un fichier de configuration.
Région & langue
Filtrage régional automatique sur 20 régions et traduction complète en 9 langues, appliqués aux listes, aux pages de détail et aux blocs de contenu croisé, afin qu'aucun article ne fuite jamais hors de son marché cible.
Audit des modules de l'équipe
Audit des quatre modules construits par mes coéquipiers, avec correction de deux classes de défauts : des paramètres de filtre régional manquants dans les requêtes JSON:API (contenu apparaissant sur les mauvais marchés) et des écarts WCAG 2.1 AA dans les composants interactifs — rôles ARIA, repères sémantiques, libellés de slides traduits, pause au survol/tactile sur les animations.
Contributions au framework Core
Trois limites propres à Vactory sont apparues pendant la construction. À chaque fois, le choix a été de corriger le framework plutôt que de le contourner localement — les trois correctifs ont donc été intégrés au profil d'installation de l'agence et profitent désormais à tous les projets VOID, passés et futurs.
- 01
Refonte de NodeQueueElement
- Le problème
- Le sélecteur d'articles du framework était un simple champ texte où l'on saisissait des titres d'articles séparés par des virgules. Cela tenait sur d'anciens projets aux titres courts. Chez Atos, les titres font 150 à 200 caractères, et le carrousel Newsroom en a besoin de trois dans un ordre contrôlé — le champ était inutilisable, et cela bloquait la livraison de tout le module Featured Newsroom.
- Ce que j'ai fait
- Une réécriture complète du composant : un champ de recherche à autocomplétion par emplacement, ajout et suppression gérés en AJAX sans rechargement de page, un compteur en direct, et un maximum lu de manière déclarative depuis le fichier de configuration propre au widget plutôt que codé en dur. L'autocomplétion respecte la région active, empêchant un éditeur de choisir par erreur du contenu d'un autre marché.
- Pourquoi c'était important
- L'ordre du carrousel est désormais garanti de bout en bout — l'ordre du glisser-déposer persiste grâce à un tri stable à l'enregistrement, et une étape de réordonnancement côté Next.js le restaure après récupération, car JSON:API ne garantit aucun ordre de retour. Chaque futur widget de l'agence avec un sélecteur d'articles en hérite gratuitement.
- 02
Un bug d'union de tableaux en PHP
- Le problème
- Les réglages des widgets ne se conservaient pas. Un éditeur choisissait une option dans une liste déroulante, une case à cocher ou un bouton radio, l'enregistrait, rouvrait le formulaire — et retrouvait la valeur par défaut du fichier de configuration. Toute personnalisation durable d'un widget était impossible.
- Ce que j'ai fait
- La cause était
return $element_defaults + $element;. L'opérateur d'union de tableaux de PHP conserve la valeur de gauche en cas de collision de clé, si bien que la#default_valuecodée en dur dans le YAML l'emportait toujours sur celle chargée depuis la base de données. Le correctif supprime cette clé du tableau de gauche — mais uniquement lorsqu'une valeur enregistrée existe réellement, afin que les widgets réellement nouveaux conservent bien leurs valeurs par défaut. - Pourquoi c'était important
- Une régression silencieuse de persistance touchant tous les champs non textuels du page builder, résolue en quelques lignes et partagée avec toutes les équipes sur cette version du framework.
- 03
Localisation des dates côté serveur
- Le problème
- Les dates étaient formatées et traduites côté frontend Next.js. Sur les précédents projets à trois langues, c'était tenable, et des bugs comme une date française affichée 05/17/2026 au lieu de 17 mai 2026 passaient inaperçus. À neuf langues, c'était un problème de maintenance qui ne fait que grandir.
- Ce que j'ai fait
- J'ai construit AtosaiDateEnhancer, un plugin JSON:API Field Enhancer qui s'accroche au pipeline de sérialisation de Drupal. Il intercepte l'horodatage brut et le remplace par une chaîne déjà formatée et traduite par les services de date et de traduction propres à Drupal, déterminés à partir de la langue de la requête. Un formulaire d'administration liste chaque format de date déclaré dans le back-office, si bien qu'associer un format à un champ ne prend qu'un clic, sans rien coder en dur.
- Pourquoi c'était important
- La logique de date a entièrement quitté le frontend, retirant au passage les bibliothèques de gestion des dates du bundle JavaScript, et les dates multilingues sont devenues correctes par construction dans les neuf langues.
Ce que j'en ai retiré
C'était ma première expérience de construction à une échelle véritablement entreprise, et la leçon a été que l'architecture, c'est surtout une question de qui devra vivre avec elle. Vingt régions et neuf langues signifient que chaque décision de modèle de contenu se multiplie avant même qu'un éditeur ne la voie — et 300 personnes éditant en même temps est une contrainte qu'on ne peut pas ajouter après coup. Travailler via un Product Owner plutôt que directement avec le client m'a appris à défendre des choix techniques en termes métier.
L'enseignement le plus durable est venu des trois contributions au framework. Corriger Vactory plutôt que le contourner à l'intérieur de notre propre module signifiait lire du code que je n'avais pas écrit, trouver le point d'échec exact, et écrire quelque chose d'assez général pour des projets que je ne verrai jamais. C'est une discipline différente de celle qui consiste à faire fonctionner un seul site, et c'est la partie de ce projet que je referais en premier.