A self-hosted, API-first content platform for small organisations.
Built with Django · Wagtail · PostgreSQL · Django REST Framework · Grapple (GraphQL) · Docker · Terraform
What's novel
I've spent the last several years in charity technology, at Oxfam and now Make-A-Wish UK, and one pattern comes up again and again. Small organisations are offered two choices for their website and content: an expensive proprietary bundle they'll use a fraction of, or a bespoke build that works beautifully until the person who built it leaves.
Neither is a good answer when budgets are tight and continuity is a real risk. Wanating CMS Core is my attempt at a third: a content platform that runs cheaply on a single server, built so the same core can serve any sector without being rewritten for each one.
Wagtail manages the content, the same CMS I chose for Oxfam GB's website, for the same reasons: it's cheap to run, resilient, and well understood. Everything else (websites, apps, partner integrations) reads it through REST and GraphQL APIs.
The discipline that mattered was applying that to its own website too. The bundled frontend is a real, working site, and it would have been easier to let it reach straight into the database, since it's my code either way. It doesn't, though. It uses the same APIs as anything else would, so replacing it with a Next.js or Nuxt frontend later changes how the site looks, not how the platform works.
I hadn't expected it to be harder to respect an API I controlled than one I didn't, but it was.
It's built in four layers. The Core Platform does what every organisation needs: content, APIs, logins, logging. Capability packs add what one sector needs. Themes decide how it looks, and nothing else. A deployment picks which packs and which theme to switch on.
Anyone can draw that diagram. The hard part is keeping it true the first time someone's in a hurry. So the rules are enforced by automated tests: the core may never import from a pack, and a theme may never contain business logic. Break either one and the build fails.
Three complete packs, Charity, Personal and Corporate, exist to prove the point. A new sector should mean writing a new pack, not touching the core.
The easy mistake with a platform is building for the customer you imagine rather than the one you've got.
The later phases are designed: a cloud-hosted version with CRM and donation integrations, and a multi-tenant layer for larger organisations. None of it is in the code, and it won't be until a real deployment needs it. Building the impressive version first is tempting, and I've seen it go wrong often enough to resist.
Phase 1 runs as a single application on one Ubuntu server with Docker Compose: Postgres, the REST and GraphQL APIs, the sample site, health checks, structured logging, automated builds, and a hardened container that runs as a non-root user on a read-only filesystem. It's privately maintained, something I build on and reuse, rather than open source.
It's also why this website started out the way it did. I built Core to handle an organisation's content properly, then built my own site as the opposite argument: that a personal website doesn't need a platform like this behind it. That argument didn't entirely survive, but it was a good place to start.