The CWA is in heavy development
The CWA is still in alpha and not ready for production - some code and implementations are likely to change. If you would like to try out the CWA, please enjoy what we have provided and feel free to provide feedback, or get involved on GitHub.
DraftCore Concepts

How It All Works

A high-level map of the CWA — what you get out of the box, what you write yourself, and how the three layers fit together.

The CWA is a framework for building content-managed websites where the content structure is managed through an API and the front-end renders whatever structure the API describes.

The key idea: you never write routing logic, CMS code, or admin UI. You only write the UI components — what they look like on the front end, and the form fields an admin uses to edit them. Everything else is handled for you.

The Three Layers

Your ProjectBackendYour entities & PageData+ API Components Bundle+ API Platform / SymfonyREST + MercureFrontendYour Vue UI templates+ @cwa/nuxt module+ Nuxt / Vue / Pinia

The API Bundle

Built on Symfony and API Platform. You get: a pre-built content data model, REST endpoints for all resources, JWT auth, file uploads, Mercure real-time, and a user system.

You write: custom component entities and dynamic page data entities.

The Nuxt Module

Handles routing (URL → API → Page → Layout → Components), server-side rendering, the inline admin CMS, all admin pages, and auth pages.

You write: layout Vue components, page template Vue components, and component Vue components (display + admin tabs).

The Template App

A starter project wiring both together with Docker Compose. The playground at components-web-app in the CWA repos demonstrates a complete working site with Title, HtmlContent, Image, NavigationLink, Collection, blog articles, and nested page data.

The Request Lifecycle

When a user visits /about-us:

  1. Nuxt middleware calls the API: GET /_/routes//about-us
  2. The Route points to a Page (static) or PageData record (dynamic)
  3. The Page declares a Layout (CwaLayoutPrimary) and a page template (PrimaryPageTemplate)
  4. Your layout Vue file renders — it shows the header, footer, and a <slot /> for the page
  5. Your page template renders inside the slot — it places <CwaComponentGroup> regions
  6. Each region fetches its ComponentPositions → Components from the API
  7. Each Component renders via the matching CwaComponent* Vue file

The whole tree fetches concurrently. The Pinia store updates reactively as data arrives.

What You Never Write

  • URL routing — routes are owned by the API, not defined in Vue files
  • CMS admin UI (built into the module)
  • Auth pages (provided automatically, and overridable with your own styles)
  • Sitemap generation
  • Real-time update handling