Posts about Web Development, Java, Magnolia CMS and beyond

6/19/2026

Vibe Coding Magnolia: Creating a Page and Content App with Claude

6/19/2026 Posted by Edwin Guilbert , , , , , No comments
Everyone is talking about vibe coding these days — that loose process where you describe what you want and let an AI write most of the code while you steer. For backend or React devs, plenty of demos exist. But what does it look like when you are a Magnolia frontend developer whose day involves YAML definitions, FreeMarker scripts, and JCR properties?

In this post I want to share a recent experiment: building an FAQ page template and a matching content app in Magnolia 6.4 using Claude code. The output is a working module sitting next to travel-demo. The interesting part is how we got there — three techniques that turned a vague idea into a clean, testable light module without me typing a single line of YAML by hand: spec-driven development, loop engineering, and browser-driven validation with Playwright.


The big picture

The naive approach to AI-assisted coding is to type "build me an FAQ page" and pray. It almost works. But "almost" hides a lot of broken YAML, hallucinated field types, and template scripts that compile in your head but explode at render time. The trick is to give the AI more structure, not less.

The three moving parts that made this experiment work were:

The Superpowers plugin — a Claude Code plugin that wires up a brainstorming → spec → plan → execute workflow. Instead of jumping into code, you negotiate the design first, then a written plan, then bite-sized tasks.
Loop engineering — short, named iterations where each step has a single goal and you review the result before moving on. The opposite of "go off for an hour and bring me back 500 lines".
Playwright as the verifier — Claude opens a real browser, logs into Magnolia, clicks through the Pages app, and reads back the rendered HTML to confirm the goal. Not unit tests — actual end-to-end checks against the running instance.

Spec-driven with Superpowers

First of all, always provide a CLAUDE.md file in the root of your project, so Claude can know more about your project features and conventions.

The session started not with a prompt but with /superpowers:brainstorming. The skill walks the user through clarifying questions — one at a time, never a wall of text. Should the FAQ items be subnodes of the page, or a first-class content type? How should categories work? Accordion or expanded by default? Each answer narrowed the design.

Once we agreed, Claude wrote a spec to docs/superpowers/specs/2026-06-18-faq-page-template-design.md and waited for review. Only then did it produce an implementation plan with 12 tasks (light module module, define content type, register app, add page dialog, write FreeMarker, etc.). The plan was committed and reviewed before any code happened.

Why this matters for Magnolia? 

Mangolia's stack is configuration-heavy. A wrong field type in contentTypes yaml doesn't fail until the app loads. A wrong template path doesn't fail until you create a page. Putting the design in writing before the YAML eliminates a whole class of round-trips.

Loop engineering: small steps, big payoff

With the plan in hand, execution used Claude's subagent-driven development: each task is dispatched to a fresh agent that only sees what it needs. light module → review → commit. Define content type → review → commit. Add app → review. The main session never bloats with implementation noise, and a bad step is contained to one task.

In parallel, I was iterating on the surrounding skills. The repo has a .claude/skills/ folder with three light-module-specific skills: magnolia-content-apps, magnolia-dialogs, and magnolia-freemarker. Every time Claude got a convention wrong (legacy 5.x app structure, wrong i18n key shape, square vs. angle brackets in FTL), I updated the skill. The next iteration got it right, and so will the next session, and the one after that.

This is the loop: small change → run → observe → adjust the rule, not the code. Skills are how you teach the AI your project's actual conventions, not the ones it absorbed from the public internet.




Playwright: the AI's own QA

YAML and FTL fail in interesting ways the moment Magnolia reads them. This is when Playwright skill in Claude can come handy, let it drive the URL of Magnolia instance and it will navigate to perform any kind of test or validation you would normally do yourself, like creating content, rendering a page, etc.

A single test session — log in as superuser, open the new FAQs app, create a page under /travel with the FAQ template, fetch the rendered HTML — surfaced four real bugs in minutes:

• A ?then(...) ternary in the FreeMarker template that threw NonBooleanException at render time.
[@cms.page /] emitted literally in the response because the file used angle-bracket tag syntax instead of square brackets.
• The page properties dialog showing faq.pages.faqPage.label instead of a translated title — a missing i18n key.
• Rich-text content rendering as escaped HTML (<p>) because the template didn't call cmsfn.decode(content).

Every one of those was fixed inside the same session, with Claude reading its own Magnolia error log, finding the offending line, editing it, and re-rendering. No human-in-the-loop except to nod.

Tips if you want to try this

Write the skills first. A 50-line markdown file with your conventions ("always use cmsfn.decode for rich text", "node type must match the content type name", "i18n key pattern is <module>.<dialog-path>.<property>.label") saves you ten iterations later. Skills are project-local and version with the repo. The skills are use-case focused context you can reuse on any related project and are triggered automatically as related tasks are requested. The description of the skill is key for this autonomous match to work.
Don't ask for "the whole thing". Ask for the design first, then the plan, then one task. You will catch mistakes earlier and waste fewer tokens.
Keep Magnolia running. Hot reload + a Playwright-equipped Claude is a magical pairing — the AI can verify its own work end-to-end without you switching contexts.
Read the error log first. When something doesn't render, point Claude at logs/magnolia-error.log. It will diagnose faster than you can scroll.
Don't merge what you didn't read. Vibe coding is not no-review coding. Every commit went through a quick diff review — that's how the second-pass refactor stayed cheap.

Quick note about Worktrees and Superpowers

A git worktree is a second working copy of your repo, on a different branch, living in a different folder, but sharing the same .git history.

What Superpowers does with them?

The using-git-worktrees skill activates right after the design is approved, before any code gets written. The flow is:

  1. Brainstorming finishes → you have an approved design doc.
  2. Superpowers creates a new branch for the work.
  3. It creates a worktree for that branch in a sibling directory.
  4. All implementation happens in that worktree.
  5. When done, the finishing-a-development-branch skill offers to merge back, open a PR, or discard.
Your main checkout never gets touched. If the whole experiment goes sideways, you delete the worktree folder and it's like it never happened. A loop is only as good as its ability to recover from a bad step. Worktrees give you cheap recovery. Cheap recovery enables ambitious loops.

What are the benefits for a dev?

The honest answer is boilerplate disappears. Defining a content type, a content app, the admincentral decoration, two i18n bundles, a page dialog, a template definition, and the FTL — that's eight or nine files of mostly-mechanical YAML. Claude handles that in minutes, and once your skills are good, it handles it correctly.

What it does not do is replace your judgement. Picking the right boundary between page properties and content type properties, deciding whether categories deserve their own content type, understanding why anonymous read access on a workspace matters — that is still you. But you get to spend your time on those decisions instead of hunting a missing comma in apps/faqs.yaml.

Wrapping up

If you build templates and content apps in Magnolia for a living, give this workflow a serious try. Install Claude Code, pull the Superpowers plugin, write two or three project-specific skills based on your team's conventions, and brainstorm your next light module with the AI instead of starting from a blank YAML file. The first hour feels weird. The second hour you stop wanting to go back.

Happy vibe coding — This post was mainly AI-generated from a Claude session and human augmented by me ;)

6/11/2026

Content Delivery Network with Fastly on Magnolia

6/11/2026 Posted by Edwin Guilbert , , , , , No comments


If you are running Magnolia in production, sooner or later you will need a Content Delivery Network sitting in front of your public instances. A CDN takes care of caching static assets close to your end users, serving dynamic content from Magnolia public instances and, on top of that, protecting your site with a Web Application Firewall. In this post we will go through how a CDN like Fastly is set up in any Magnolia setup and the best practices around caching.

The big picture

Before going into the details, let's quickly review what sits between the end user and Magnolia:

End users hit the CDN, which either serves a cached response or forwards the request to the load balancer. The load balancer then routes traffic to the Magnolia Author and Magnolia Public instances. The CDN provided by Magnolia DX Cloud is Fastly but you can also bring your own if you already have one in place. In the case of Fastly, it also comes with WAF protection, but lets focus on the CDN for this post.

The goals are simple:

• Cache static content for faster delivery
• Serve dynamic content from Magnolia public instances
• Protect everything behind a WAF

CDN set-up

Setting up the CDN for a project is mostly a matter of wiring a few things together:

• A Fastly service is created together with a WAF site (optional).
• A certificate needs to be uploaded to the Fastly.
• The domain (or domains) needs to point to the Fastly servers.

But lets focus on the Magnolia side of things, what to take into consideration to get most out of the CDN.

Magnolia best practices

There is one thing to keep in mind when working with a CDN in front of Magnolia: caching happens in more than one place. Magnolia has its own backend cache, the browser has its cache, and the CDN has yet another one. The trick is to make them work together and not against each other.

A few rules of thumb we follow:

• Aim for a hit ratio and CDN coverage over 70%. Anything below that and your CDN is more decoration than acceleration.
• Define caching rules for images, REST endpoints and anything else that does not change very often.
• Use cache-control for both the browser and the CDN, and surrogate-control when you want a rule that only applies to the CDN.
• The default rule cache-control: private invalidates surrogate-control, which is something easy to forget when troubleshooting.
• Pages are not cached by default. If you do want to cache them, remove the dontCachePages rule.
• Every URL with different parameters creates a different entry in the CDN cache, so be mindful of query strings.
• Personalization (P18n) creates different cache entries per variation via the Vary header.

Cache config in Magnolia

In config:/modules/cache/config/contentCaching/defaultPageCache you can find cachePolicy and browserPolicy, first one is Magnolia internal caching at server level using Ehcache (not covered in this post) and second one is the one setting cache-control headers. 

Lets see an example:


This would set cache-control: max-age=3600, public header for js/css files under /.resources path.

If you want to set cachesurrogate-control headers you would need to add an AddHeaders filter.

More best practices

Once the basics are in place, there are a few extra goodies you can take advantage of:

• A static error page can be configured for 404, 503 or really any status you want.
Rate limiting and any other custom CDN rule can be added on top.
Segmented caching for videos can be activated when needed.

Watch out for cookies: any response that sets a cookie will not be cached. The usual suspects in Magnolia are:

• The country trait setting JSESSIONID
• The csrfTokenSecurity filter setting a csrf cookie
• The ingress sticky sessions
If you see your pages stubbornly missing the cache, this is the first place to look.

HTTP statuses cached by Fastly

Not every HTTP status is cacheable. Fastly will cache the following:

• 200 OK
• 203 Non-Authoritative Information
• 300 Multiple Choices
• 301 Moved Permanently
• 302 Moved Temporarily
• 404 Not Found
• 410 Gone

Everything else will go through to the origin.

REST caching

REST endpoints can be cached too, and in most projects they should be: the typical "give me the latest news" or "list of products" endpoint is a great candidate for a CDN cache. Apply the same headers as you would for any other resource and remember that, again, any Set-Cookie in the response will bypass the cache.

Debugging with Fastly

When things do not behave as expected, Fastly gives you a few tools to figure out what is going on.

Fastly cache status

Every cached request comes with a status in x-cache header that tells you what happened:

HIT → the response was served from the cache.
MISS → the response was not in the cache yet, but it will be next time.
PASS → the response is not cacheable and will never go into the cache (usually because of a Set-Cookie or a cache-control: private).

If you expect a HIT and you keep seeing PASS, that is your hint to go and review the response headers coming out of Magnolia.

Wrapping up

A CDN in front of Magnolia is a lot more than "free speed". It is a piece of your architecture that interacts with how you build pages, how you set headers, how you handle cookies and how you secure your site. Spending a bit of time on the caching rules and keeping an eye on the logs pays off very quickly — both in performance and in your end users' experience.

Happy caching!