cat ~/production/multi-tenant-cms-and-billing-platform/REPORT.md

Multi-tenant CMS and Billing Platform

One backend serving many client websites, each defining its own content types, its own team permissions and its own subscription.

role Tech Lead, Backend Architecturetimeline 2024 - 2025category saasclient A web agency managing multiple client sites

Problem

An agency running websites for many clients was maintaining a separate backend per site. Every client wanted different content types, their own editors with their own permissions, and their own billing. A codebase per client means every fix has to be applied everywhere.

Approach

One centralised backend where content structure is data rather than code. A client defines a collection with its own fields from the dashboard and starts storing rows immediately, with no migration and no deploy. Each site is a tenant with its own users, per-resource permission grants, trilingual content, and an independent subscription with invoicing and gateway payment.

Outcome

A new client site onboards without touching the codebase. One deployment serves all of them, so a fix ships once instead of per site.

15Domain models
99Route declarations
3 + 5Permission model · roles plus per-resource grants
3Architecture rewrites · each narrower and more capable
architecture --explain

How it's built

Schema as data: collections declare their fields, items store shapes against them. Three roles plus five per-resource grant lists, so permissions are per-collection rather than global. Full subscription lifecycle with invoice generation and gateway integration.

Dynamic collections over a fixed schema per client

The product premise is that clients define their own content types. Storing field definitions as data is what allows onboarding without a deploy.

Content fields cannot be indexed because names are not known ahead of time, and validation against declared types has to be rebuilt at the application layer rather than inherited from the database.

Compensating rollback around payment initialisation

Subscription and invoice are created before the gateway call, so a gateway failure has to unwind both rather than leaving an orphaned pending subscription.

Two writes to undo instead of one transaction, the cost of an external system that has no concept of your transaction.

Explicit timeout on the gateway call

A payment gateway that stops responding must fail fast rather than hold a request open, because the retry path is safe and the hung path is not.

A slow but successful response can be abandoned, which webhook reconciliation resolves.

related --by-stack

Adjacent systems

REL-001 / saas

Multi-tenant Restaurant Platform

A complete restaurant operating system on one multi-tenant backend: customer ordering, driver dispatch, owner dashboard and point of sale.

REL-002 / platform

Vehicle Rental Platform

Rent a scooter or e-bike from an app: scan the QR, the physical lock opens over cellular, ride, park in a permitted zone, pay by the minute from a prepaid wallet.

REL-003 / platform

Freelance Marketplace with Escrow

Two-sided marketplace for architecture and design work: the platform holds the money until delivery is confirmed, with bidding happening in real-time chat.