Rendering & Publishing Pipeline

This is where page data becomes a fast, static website. The same rendering library powers both the live preview in the editor and the published output, so what an author sees is what visitors get.

Building blocks

Components

A component is a reusable UI element packaged as a bundle in Component_Store. Its source lives under components/default/<id>/:

<component>/

├── details.json (required) — metadata (name, description, category)

├── dialog.json (required) — configurable fields shown to authors

├── component.html (required) — HTML template with {{markers}}

├── component.css (required) — styles

├── component.js (optional) — server-side data function

├── editor.js (optional) — editor-only editorial controls

└── variables.json (optional) — design variable definitions

Built-in components include title, rich-text, image, button, container, site-navigation, page-list, teaser, table, tabs, percentage-bar and comments. Administrators can also upload custom component bundles. Component definitions (metadata) are stored in Content_Store (COMPONENT#{id}), while the HTML/CSS/JS assets live in Component_Store.

Templates, pages and zones

  • A template defines a layout of regions and default content.
  • A page references a template and fills its editable zones with a tree of component instances. Each instance carries its dialogValues (the author-configured field values) and, for containers, nested children.
  • Pages are hierarchical (addressed by slug) and support a designated homepage and a per-site error page.

Design variables, themes and breakpoints

  • Design variables (Variable Registry) are platform-level design tokens referenced by components.
  • Themes (per-site THEME record, plus theme entities) and breakpoints (site BREAKPOINTS overriding platform defaults) control visual styling and responsive behaviour. Platform breakpoint defaults are mobile: 0, tablet: 768, smallDesktop: 1024, desktop: 1280 (px).

The shared renderer

functions/shared-renderer/ is a pure, dependency-light library used by both the publisher and the preview handler. Its main parts:

  • componentRenderer / renderTemplate — merges a component's HTML template with its dialogValues. It supports a small, safe templating syntax:
    • {{field}} — HTML-escaped value substitution
    • {{{field}}} — raw (unescaped) value, for sanitised rich-text HTML
    • {{#if field}}…{{else}}…{{/if}} and {{#unless field}}…{{/unless}}
    • {{#ifEquals field "value"}}…{{/ifEquals}}
    • {{#each field}}…{{else}}…{{/each}} (repeatable fields, nestable)
  • layout-renderer (renderLayoutTree) — walks a page's zone/component tree, rendering containers side-by-side and stacking other components, applying per-breakpoint widths and background styling.
  • dialog-defaults — applies a component's declared default field values before rendering.
  • nav-items — normalises site-navigation menus (manual items and page-derived trees) identically for preview and publish.
  • function-registry / resolveFunctionFields — resolves dynamic "function fields" (e.g. a navigation component's page listing) at render time.

Because preview and publish call the same functions with the same inputs, the two outputs are guaranteed to match.

Publishing a page

The publisher-function (1024 MB, 60 s) is the single source of truth for rendered output. Triggered by publish-page, unpublish-page, rebuild-site or the bulk-publish worker, it:

  1. Loads the page and its template from Content_Store.
  2. Applies template defaults and merges the template's regions with the page's zones (mergeTemplateIntoPage).
  3. Resolves function fields and dialog defaults for each component instance.
  4. Loads component assets (HTML/CSS/JS) from Component_Store and renders the component tree to a single HTML document via the shared renderer, injecting theme/breakpoint styles and referenced assets from Asset_Store.
  5. Writes the static HTML (and any companion objects) to Publish_Store under the site's prefix, and regenerates the site's sitemap and robots.txt (honouring AI-crawler access settings).
  6. Invalidates the site's CloudFront cache so the new HTML is served.

Unpublishing removes the object(s) from Publish_Store and re-invalidates the cache. A rebuild re-renders an entire site.

Governance around publishing

  • Draft vs published state per page.
  • Version history — a VERSION#{n} snapshot is written on save/publish so any prior version can be listed and restored.
  • Page locks (LOCK#{pageId}) prevent concurrent edits.
  • Publish requests (PUBLISHREQ#{id}) let authors submit changes for approval before they go live.
  • Bulk publish processes many pages in a background worker (512 MB, 300 s); publish-tree publishes a page and its descendants.
  • Activity log records who did what (ACTIVITY#{ts}#{uuid}).

Site provisioning & teardown

  • provision-site (512 MB, 120 s) runs when a site is created: it creates DNS records, requests and validates a TLS certificate, creates the CloudFront distribution, and configures storage — polling to completion with retries. It holds explicit dns:*, certificate:*, website:* and storage:* permissions.
  • delete-site-step (256 MB, 30 s) reverses provisioning on deletion (DNS, certificate, distribution, storage, Cognito cleanup).

Backup & restore

Backups and restores run as stepwise pipelines so they scale to any site size and stay within Lambda limits:

  • backup-create / backup-create-platform start a backup; backup-process-step (512 MB, 60 s) walks the steps gatherTemplates → gatherPages → gatherSettings → gatherAssets → assembleZip. Each gather step stages its slice as JSON in Backup_Store (S3) rather than on the DynamoDB backup record — this keeps the record small (DynamoDB's 400 KB item limit) and lets backups handle sites of any size. assembleZip reads the staged slices, downloads the referenced assets, builds the zip and uploads it, then cleans up staging.
  • backup-restore / restore-process-step (512 MB, 120 s) reverse the process, walking validateZip → clearTemplates → clearPages → restoreTemplates → restorePages → restoreAssets → restoreSettings to recreate templates, pages, assets and settings (including component styles and theme) from a zip. Each restore step re-reads its content from the uploaded zip in Backup_Store rather than from the DynamoDB record, so large backups restore without hitting the 400 KB item limit. restoreAssets writes every assets/<path> entry to Asset_Store at assets/<siteId>/<path> (created if missing, overwritten if present; Content-Type derived from the file extension) and mirrors it to Publish_Store at <siteId>/assets/<path> so the live site serves it immediately.
  • backup-list / backup-list-all / backup-get / backup-delete manage the archive; a platform backup captures design variables, component definitions, page types and platform breakpoints only.