System Architecture & Flows
The platform is organised into four logical planes. Each maps onto a set of serverless components defined in src/main/serverless/.
Plane | Responsibility | Key components |
|---|---|---|
Management (admin) plane | Authenticated authoring, configuration and workflow | Admin_Tool (React UI), CMS_API, cms-functions |
Delivery (public) plane | Serving content to visitors | Public_API, public-functions, per-site CloudFront + Publish_Store |
Rendering plane | Turning page data into static HTML | publisher-function, shared-renderer, Component_Store |
Data & platform services | Durable state and shared services | Content_Store (DynamoDB), S3 stores, Auth_Service, Email_Service, SMS_Service |
High-level diagram
The management plane
- Admin_Tool — a React 18 + TypeScript single-page application built with Vite and Tailwind, deployed as a website component onto S3 + CloudFront at admin.<rootDomain>. It talks only to the CMS API.
- CMS_API — an API Gateway (cms-api.<rootDomain>) with ~90 routes. CORS is restricted to the admin origin, access logging is on, and a pre-process authorizer (cms-pre-process) runs before routes to validate the caller.
- cms-functions — the control-plane Lambda group (Node.js 22). Each API route maps to a dedicated handler exported from handler.js, which delegates to a module under handlers/ with shared helpers in lib/.
The delivery plane
- Each site is served from its own CloudFront distribution over the static objects in the shared Publish_Store (S3). This is provisioned automatically when a site is created.
- Public_API (api.<rootDomain>) + public-functions provide dynamic read endpoints for published content, navigation, metadata, on-site search, and form submissions — without exposing the admin API.
- The delivery plane is unauthenticated and read-optimised; it reads from Publish_Store and Content_Store only.
The rendering plane
- publisher-function is a dedicated Lambda (1024 MB) that composes a page's component tree into a single static HTML document and writes it to Publish_Store. It is invoked asynchronously by the publish-page, unpublish-page, rebuild-site and bulk-publish handlers.
- shared-renderer is a pure, dependency-light rendering library shared by the publisher and the live preview handler, guaranteeing preview and published output match. See Rendering & publishing.
- Component_Store (S3) holds the HTML/CSS/JS bundles for every component the renderer can use.
Data & platform services
- Content_Store — a single DynamoDB table (with two GSIs) holding all authoring state for every site and the platform. See the Data model.
- S3 stores — Asset_Store (media & fonts), Component_Store (component bundles), Publish_Store (rendered sites), Backup_Store (backup archives), and deploy-artifacts (Lambda zips).
- Auth_Service — Amazon Cognito user pool (email login, optional MFA, strong password policy, groups).
- Email_Service / SMS_Service — transactional email (SES) and SMS (SNS), wired into Cognito for notifications and MFA.
Request flow: editing a page
- The author works in Admin_Tool; the SPA calls CMS_API with a Cognito JWT access token.
- cms-pre-process validates the token and resolves the caller's permissions, attaching them to the request context.
- The route's handler in cms-functions authorises the action, then reads or writes items in Content_Store.
- Draft changes are persisted immediately; a prior version snapshot is kept for history.
Request flow: publishing a page
- The author triggers Publish; publish-page validates permissions and marks the page published in Content_Store.
- publish-page invokes publisher-function (async).
- The publisher loads the page, its template and referenced component bundles, renders the full component tree to static HTML, and writes the object(s) to Publish_Store. It also regenerates the site's sitemap and robots.txt as needed.
- The site's CloudFront cache is invalidated so the new HTML is served.
Request flow: serving a visitor
- A visitor requests a page on the site's domain.
- CloudFront serves the pre-rendered HTML from Publish_Store (cache hit for most requests).
- For dynamic reads (navigation, search, metadata) or form posts, the page calls Public_API, which runs a public-functions handler against the published data.
Request flow: provisioning a site
- sites-create writes the site record and invokes provision-site.
- provision-site creates the DNS records, requests/validates a TLS certificate, creates the CloudFront distribution and configures storage — polling to completion across retries.
- Deleting a site runs delete-site-step to reverse each of these.
Continue to Serverless component inventory »