The Louvre’s website is re-tendered every five years. It is a public contract: it can be won, and it can be lost. When I joined, the rebuild had been running for a year and the codebase was already clean. I was an apprentice. I stayed five years and left as lead, talking to the client directly.
Just before I left, the agency won the contract again for another five years.
The system
The front end is headless, decoupled from the CMS. The API does not return a page, it returns a tree of components that the front end renders recursively. Every template is composable: the museum’s editorial teams assemble their pages from the components they want, without going through a developer.

That architecture predates me. What I brought to it is the contract that makes it hold over time.
A single JSON Schema describes each component on both sides of the boundary: the one the CMS produces in PHP, and the one the Storybook story consumes in React. The schema ships as a Git submodule, so it is versioned and shared between both repositories. If the back end changes a component’s shape, the front end knows, and the tests say so.Without that contract, data-driven recursive rendering becomes unmanageable as soon as the team turns over. Over five years, the team turns over.
- Next.js
- headless Drupal
- JSON Schema
- Git submodule
- Storybook
- SCSS
The difficulty
You could put a dropdown inside an FAQ, a dropdown inside a drawer, a drawer inside a dropdown. The back end decided the order and the nesting, at authoring time. Apart from common components like image or text, every component accepted agnostic children: it knew neither what it contained nor what contained it.

That changes the job. You no longer assemble pages, you build a system that has to stay correct under any composition, including the ones nobody anticipated. A component that works in the mockup but breaks three levels deep is a broken component.
Accessibility under an unpredictable structure
The site meets the French public-sector accessibility standard at its highest level of conformance, externally audited by Temesis. And arbitrary nesting is the worst possible ground for accessibility: focus management, ARIA state, keyboard traps. Nobody can anticipate the combinations.
Contract component.schema.json
{ "properties": { "type": { "enum": ["faq", "drawer", "dropdown", "button"] }, "children": { "type": "array", "items": { "$ref": "#" } }any component, at any depth} }
API
{ "type": "faq", "children": [{ "type": "drawer", "children": [{ "type": "dropdown", "children": [{ "type": "button" }]}]}]}
Front
Two principles were enough.
Each component owns its focus and its own state. It never needs to know its children or its parent. A rule that is correct locally stays correct under any nesting.
And when an exception needs context, the back end decides. It knows the page, so it sends different JSON. Props are the JSON. No exception is hard-coded into a component.
Thousands of compositions are possible, and the front end knows none of them. It renders what it is sent.
The side effect
An architecture designed for editorial contribution produced a benefit nobody asked it for. Because everything composes from the same tested components, there is no one-off page that drifts. The site is coherent end to end, down to the pixel, and that coherence is structural rather than a matter of discipline.
Scale

Four languages: French, English, Spanish, Mandarin. At least a hundred components, all tested through Storybook and their JSON Schema. Two front-end developers whose work I led on the final phase. Five years.
What it proves
I did not design this system. I held it for five years, improved it without breaking it, and was the person the museum talked to, from apprentice to lead.
Then the contract was renewed. That signature is not mine, which is what makes it evidence.

