GraphQL and types
Fragments, query-specific files and Codegen connect the Craft schema to generated TypeScript types and expose incompatibilities during development and builds.
01 / Project
Platform evolution · Next.js + headless CMS
Rebuilding and progressively evolving an established headless platform without discarding the knowledge embedded in its history.

01 / Architecture evolution
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.
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
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.
03 / Content architecture
The migration was an opportunity to model the editorial domain, not reproduce the old database structure one-to-one.
Articles · Webinars · Podcasts · White Papers · Checklists
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
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.
WordPress has not yet been removed from every area.
05 / Editorial system
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.
Two renderers cover general and editorial content. Reusable lower-level components and variants prevent the CMS model from forcing one-to-one UI duplication.
Editors can compose and reorder pages from an established component set, while each content type controls which modules are valid in that context.

06 / Redirects
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.
Craft / Retour → Webhook → Vercel storage
Request → Next.js middleware → Storage → Redirect or continue
07 / Platform details
Fragments, query-specific files and Codegen connect the Craft schema to generated TypeScript types and expose incompatibilities during development and builds.
I adapted an existing preview approach across additional channels. Draft mode uses authenticated GraphQL, and components tolerate temporarily incomplete editor data.
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

08 / Outcome
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.
Legacy structure can contain editorial knowledge that is not visible from the schema alone.
A CMS migration can reconsider whether old structures still represent the content domain.
Old and new systems can coexist while a production platform changes area by area.
Caching must react when content becomes disabled, deleted or otherwise stops being visible.