Skip to main content
Work

Case 003 / Work

Orient-Express.com

Front-end developer, acting lead · 2024 — 2025

4 min read

Years
2024 — 2025
Scope
Joined August 2024 · 3 front-end developers led · technical ownership of the project
Stack
Next.js · headless Drupal · TypeScript · JSON Schema · Storybook
Live site
orient-express.com
Orient-Express.com — hero

I joined Orient Express in August 2024, while the lead developer was away. I set the architecture and started on my own. When they came back, they were busy on other projects and left me the seat. I was never lead on paper; I was lead in practice until I left in 2025, with three front-end developers whose work I allocated and whose code I reviewed.

Carrying the architecture over

The platform brings three worlds together under one system: trains, hotels, yachts. Each has its own identity and its own booking journeys, and all of it runs on a single component base.

The Trains world on orient-express.com, La Dolce Vita
Frame 01 Trains. La Dolce Vita.
The Hotels world on orient-express.com, La Minerva in Rome
Frame 02 Hotels. La Minerva.
The Yachts world on orient-express.com, the Corinthian
Frame 03 Yachts. The Corinthian.

To build it, we carried over the Louvre architecture. A headless front end, an API returning a tree of components, templates composable at authoring time. I had just spent four years inside it. I knew what worked, and more importantly I knew what was expensive.

  • Next.js
  • headless Drupal
  • TypeScript
  • JSON Schema
  • Storybook

What I removed

On the Louvre, nesting was unlimited. A dropdown inside a drawer, a drawer inside a dropdown, as deep as the editors wanted. That was the feature, and it was powerful. It was also a considerable mental load for the team holding it all in their heads.

On Orient Express, I capped composition at a single level. A child inside a child, no further.

Contract component.schema.json

{ "properties": {  "type": { "enum": ["page", "section", "card", "dropdown"] },  "children": { "type": "array", "items": { "$ref": "#/$defs/leaf" } }a leaf. It has no children of its own.} }

API

{ "type": "page", "children": [{ "type": "section", "children": [{ "type": "card", "children": [{ "type": "dropdown" }refused]}]}]}

Front

The same schema as before, with one reference changed. Children point at a definition that cannot nest again, so the fourth level is not a bug the team has to catch — it never validates. Point at any node.

It is the decision I am happiest with, and it is a decision to take something away. Rebuilding the unlimited system was within reach; I chose not to.Flexibility has a price. It is paid by the people who maintain the thing, and it never shows up in a demo.

What I automated

I had written a component generation script. On Orient Express it was in place from day one. Every new component is therefore born compliant: schema, Storybook story, structure. Nobody has to remember the convention, the tooling produces it.

We also reworked layouts and forms, properly typed this time. A data-driven front end always has the same weak point, and it is the form.

My place in the team

The team had two back-end developers, two project managers, the lead developer and me, then three front-end developers. I spent as much time with the back end and with project management as with the front, because the decisions that get expensive are taken at the boundary between layers, rarely inside one.

It was not a role and nobody assigned it to me. It was where I was useful.

What it proves

The site kept evolving for a year after I left. That is the only test that matters for an architecture: whether it survives the person who set it up.

I was never lead on paper. The architecture, the cap on composition, the tooling that makes every new component compliant by default: none of it needed my title, and in the end none of it needed me.

Next projectCase 001 / Work

Spliz

Founder, product engineer · 2026 →

spliz.app7 min read