JG—26← All workContact ↗

01 / Project

Platform evolution · Next.js + headless CMS

Morae

Rebuilding and progressively evolving an established headless platform without discarding the knowledge embedded in its history.

My role
Frontend development / CMS integration
Duration
Approximately 2–3 years
Collaboration
I worked with a project manager, designer and lead developer, with backend support when needed.
Areas
Platform evolution / Page building / Editorial workflows / Preview and revalidation / UX and interaction
Morae legal intelligence platform homepage
Morae legal intelligence platform.

01 / Architecture evolution

A platform with history.

I had worked on Morae when it was still a monolithic WordPress site. Another company later made it headless. When our team took over, we substantially rebuilt the frontend and then began introducing Craft without forcing the whole platform through one release.

  1. 01 / OriginalExternal headless migration ↓
    WordPressCMS + frontend
  2. 02 / Headless v1Project taken over ↓
    WordPress → Next.jsGraphQL / Apollo
  3. 03 / Rebuild + migrationProgressive evolution ↓
    Craft + WordPress → Next.jsWordPress remains as fallback
  4. 04 / Direction
    Craft → GraphQL → Next.jsContent moves area by area

My earlier involvement did not make our team responsible for the original headless migration. It gave me context for deciding which legacy structures expressed real editorial requirements and which could be reconsidered.

02 / Ownership

Working across the CMS/frontend boundary.

My work was not divided neatly into CMS and frontend tickets. Owning an area such as Insights could mean investigating a broad requirement, proposing and testing an approach, discussing it with the team and carrying the implementation through the complete platform.

A Lead Developer retained primary responsibility for major technical decisions. Architecture and implementation choices were frequently collaborative, while I made decisions independently within the areas I owned.

  1. 01Requirements / investigation
  2. 02Craft content modelling
  3. 03Sections, Entry Types, fields and relationships
  4. 04GraphQL queries and fragments
  5. 05Generated TypeScript types
  6. 06Next.js routing and pages
  7. 07React components
  8. 08Filtering and behaviour
  9. 09Preview and production integration

03 / Content architecture

Rethinking Insights.

The migration was an opportunity to model the editorial domain, not reproduce the old database structure one-to-one.

Previous WordPress modelInsights CPTInsight Type taxonomy

Articles · Webinars · Podcasts · White Papers · Checklists

Craft content model
ArticlesWebinarsPodcastsWhite PapersChecklists
Aggregated by Next.js/insights

Each type can have fields and editorial structure suited to its content, while Next.js brings them back together as one public Insights experience.

04 / Migration

Evolving without a big-bang rewrite.

Craft became the preferred source for migrated areas while WordPress remained available for content that had not yet moved. This allowed individual areas to evolve without requiring every content type and record to migrate together.

IncomingRequest
Preferred sourceCraft CMS
FoundRender with Next.js
Not found
WordPress
Found → RenderNot found → 404

WordPress has not yet been removed from every area.

05 / Editorial system

Controlled flexibility for editors.

Editors can choose from approximately 20–30 configurable components, configure them and reorder them freely. Each Entry Type limits which components are valid, keeping composition flexible without creating an unrestricted page builder.

Component previews inside Craft help editors understand what they are adding.

Craft → React architecture
  1. Craft component
  2. GraphQL
  3. typeHandle
  4. Component Renderer
  5. React component

Two renderers cover general and editorial content. Reusable lower-level components and variants prevent the CMS model from forcing one-to-one UI duplication.

Editorial system

Flexible composition inside controlled boundaries.

Editors can compose and reorder pages from an established component set, while each content type controls which modules are valid in that context.

Morae page-building system across several page and module configurations

06 / Redirects

Keeping redirects editorial.

I restored CMS-managed redirects without querying the CMS on every request, then migrated the source from WordPress/Yoast to Craft/Retour while preserving the runtime architecture and adding regex support.

Write / update

Craft / Retour → Webhook → Vercel storage

Runtime

Request → Next.js middleware → Storage → Redirect or continue

07 / Platform details

GraphQL and types

Fragments, query-specific files and Codegen connect the Craft schema to generated TypeScript types and expose incompatibilities during development and builds.

Preview and drafts

I adapted an existing preview approach across additional channels. Draft mode uses authenticated GraphQL, and components tolerate temporarily incomplete editor data.

Cache revalidation

Craft events trigger semantic tag and path invalidation so the next request uses fresh GraphQL data. Disabled and deleted content must invalidate its previous state, not only content that remains enabled.

Read technical case →

Project view

Responsive delivery

The same content system had to remain coherent across screen sizes.

Desktop and mobile versions of the same Morae experience

08 / Outcome

Evolution rather than replacement.

The frontend was substantially rebuilt, Craft could be introduced area by area, and editors retained control over workflows including redirects and previews—all while the live platform continued to operate with WordPress where it was still needed.

01

Understand before replacing

Legacy structure can contain editorial knowledge that is not visible from the schema alone.

02

Redesign the model

A CMS migration can reconsider whether old structures still represent the content domain.

03

Evolve incrementally

Old and new systems can coexist while a production platform changes area by area.

04

State transitions matter

Caching must react when content becomes disabled, deleted or otherwise stops being visible.

Next project
Core One →