Atos Portal

Ingeniero de software en prácticas — proyecto de fin de carrera · VOID Agency · February 2026 — July 2026

  • Drupal 10
  • PHP 8.2
  • JSON:API
  • Next.js
  • React
  • Tailwind CSS
  • Redis
  • MySQL
  • Docker
  • Nginx

Atos es un grupo de servicios tecnológicos presente en más de 70 países. Su web pública se había vuelto imposible de actualizar sin un desarrollador, así que la agencia a la que me incorporé la reconstruyó desde cero. Entregué tres de sus siete sistemas de contenido, y de paso corregí tres bugs en el propio framework de la agencia.

The Brief

Atos is an international technology services group operating in more than 70 countries with close to 100,000 employees — the worldwide IT partner of the Olympic and Paralympic Games. Its corporate portal is the public front door for clients, investors, partners and candidates. Atos handed the complete rebuild to VOID Agency, and I delivered part of it as my six-month graduation project inside an eight-person agile team.

Why the Old Portal Had to Go

The legacy platform was a WordPress monolith with four structural failures:

  • Editorial paralysis. Every layout change, every new section, every regional variation needed a developer. Editorial teams spread across several continents were blocked on tasks as small as publishing a press release.
  • A flat content model. Press releases, awards, event announcements and research reports all lived in one undifferentiated structure — no distinct fields, no semantics, so precise filtering and regional targeting were impossible.
  • Broken international SEO. The hreflang tags were consistently malformed: wrong region codes, missing x-default, non-canonical URLs. English-speaking visitors were being served Arabic pages. Across 70 markets the damage compounded.
  • Unreachable performance budgets. PHP rendering every page on demand made the Core Web Vitals thresholds unattainable.

The Decoupled Architecture

The answer was a headless architecture. Drupal 10 became a pure content repository, hidden behind a private network and reachable only through filtered JSON:API endpoints — which removes the public attack surface entirely. Next.js renders the public site, pre-generating pages statically (SSG) and refreshing them in the background on every content change (ISR), with Redis absorbing the read load. The whole stack runs containerised through Docker Compose locally, Easypanel for staging and AWS in production.

All of it sits on Vactory, VOID's proprietary enterprise framework built on the Software Product Line principle, so modules can be shared across the group's three portals — Atos Groupe (already live), Atos (this project) and Eviden (next).

What I Owned

The portal carries seven editorial content types across two families. Three were mine end to end — Case Studies, Research Reports, and Events & Webinars — from Drupal entity modelling and JSON:API normalizers through to the React components. I then audited and corrected the four modules built by the rest of the team before final delivery.

A second sprint delivered the Featured system: seven widgets letting webmasters hand-pick the priority content on any listing page, rendered as a hero card for the Insights family or an animated carousel for the Newsroom family.

Insights Engine

Three of the portal's seven content modules, owned end to end: Case Studies (cross-linked to reports and white papers), Research Reports (gated PDF downloads through Adobe Marketo) and Events & Webinars (dynamic Speakers built on Drupal's Paragraphs API, plus a registration CTA that renders only while the event is still upcoming).

Featured System

Seven widgets across two editorial families, all delegating to one shared rendering layer — a hero card for Insights, a 7-second auto-advancing carousel with progress indicators, hover-pause and swipe for Newsroom. An eighth widget would need only a config file.

Region & Language

Automatic regional filtering across 20 regions and full translation across 9 languages, applied to listings, detail pages and cross-content blocks so no article ever leaks outside its target market.

Team Module Audit

Audited the four modules built by teammates and fixed two classes of defect: regional filter parameters missing from JSON:API queries (content surfacing in the wrong markets) and WCAG 2.1 AA gaps in the interactive components — ARIA roles, semantic landmarks, translated slide labels, hover/touch pause on animation.

Contribuciones al framework Core

Three limitations in Vactory itself surfaced during the build. Each time the call was to fix the framework rather than work around it locally — so all three shipped into the agency's install profile and now benefit every VOID project, past and future.

  1. 01

    Rebuilding NodeQueueElement

    El problema
    The framework's article picker was a single text field where you typed article titles separated by commas. That held up on past projects with short titles. Atos titles run 150–200 characters, and the Newsroom carousel needs up to three of them in a controlled order — the field was unusable, and it blocked delivery of the whole Featured Newsroom module.
    Lo que hice
    A complete rewrite of the component: one autocomplete search field per slot, add and remove handled over AJAX without a page reload, a live counter, and a maximum read declaratively from the widget's own config file rather than hardcoded. The autocomplete respects the active region, so an editor cannot accidentally pick content from another market.
    Por qué importaba
    Carousel order is now guaranteed end to end — drag-and-drop ordering persists through a stable sort on save, and a reordering step on the Next.js side restores it after fetch, because JSON:API makes no promise about return order. Every future agency widget with an article picker inherits all of it for free.
  2. 02

    A PHP Array Union Bug

    El problema
    Widget settings would not stick. An editor picked an option in a dropdown, checkbox or radio, saved it, reopened the form — and got the config file's default back. Any lasting customisation of a widget was impossible.
    Lo que hice
    The cause was return $element_defaults + $element;. PHP's array union operator keeps the left value on a key collision, so the hardcoded #default_value from the YAML always beat the one loaded from the database. The fix unsets that key from the left-hand array — but only when a saved value actually exists, so genuinely new widgets still get their defaults.
    Por qué importaba
    A silent persistence regression affecting every non-text field in the page builder, resolved in a few lines and shared with every team on that framework version.
  3. 03

    Server-Side Date Localisation

    El problema
    Dates were formatted and translated in the Next.js frontend. On earlier three-language projects that was survivable, and bugs like a French date rendering as 05/17/2026 instead of 17 mai 2026 went unnoticed. At nine languages it was a maintenance problem that only grows.
    Lo que hice
    I built AtosaiDateEnhancer, a JSON:API Field Enhancer plugin that hooks into Drupal's serialization pipeline. It intercepts the raw timestamp and substitutes a string already formatted and translated by Drupal's own date and translation services, picked up from the request language. An admin form lists every date format declared in the back-office, so wiring a format to a field is one click and no hardcoding.
    Por qué importaba
    Date logic left the frontend entirely, taking date-handling libraries out of the JavaScript bundle with it, and multilingual dates became correct by construction across all nine languages.

Lo que aprendí

This was my first time building at genuine enterprise scale, and the lesson was that architecture is mostly about who has to live with it. Twenty regions across nine languages means every content-model decision multiplies before an editor ever sees it — and 300 people editing at once is a constraint you cannot retrofit. Working through a Product Owner rather than directly with the client taught me to argue technical choices in business terms.

The most durable takeaway came from the three framework contributions. Fixing Vactory instead of patching around it inside our own module meant reading code I had not written, finding the exact failure point, and writing something general enough for projects I will never see. That is a different discipline from making one site work, and it is the part of this project I would do again first.