PageKiln
System Architecture

PageKiln Franchise Engine

A multi-tenant SaaS platform for building, publishing, and managing websites at franchise scale — powered entirely by Cloudflare's edge infrastructure.

Overview

What PageKiln Does

PageKiln is a franchise-ready website engine. HQ manages templates and the platform. Franchisees each get their own site with a custom domain, CMS, and inline editor — all on one shared infrastructure.

Platform Worker

The brain. Hono REST API handling auth, content management, domain provisioning, build orchestration, and static site serving — all in one Cloudflare Worker.

Cloudflare Workers

Dashboard

Next.js 16 operator UI deployed as a Cloudflare Worker via OpenNext. Manages domains, content, publishing, templates, and team members.

Next.js + OpenNext

Runner

Node.js process on a VPS. Polls for build jobs, runs the Astro site generator, uploads static files to R2 object storage. The only component not on Cloudflare.

VPS / Node.js

D1 Database

Cloudflare's serverless SQLite. Stores tenants, users, sessions, content blocks, domains, releases, audit logs, and the franchise org hierarchy.

Relational Data

KV Namespaces

HOSTMAP_KV maps hostnames to tenants — the routing table for "which domain is which site." FORM_RL_KV tracks rate limits for signups and form submissions.

Key-Value

R2 Storage

S3-compatible object storage holding all published site artifacts. Structure: sites/{tenantId}/{version}/**

Object Storage

Build Queue

Cloudflare Queues for async job dispatch. When a user clicks "Publish," a message is enqueued. The Runner picks it up, builds the site, and reports back.

Cloudflare Queues

Hyperdrive

Cloudflare's Postgres connection pooler + query cache. Connects to an external Neon database for tenant data connectors and collection schemas.

CF Hyperdrive + Neon

Custom Hostnames

Cloudflare API feature that provisions individual SSL certificates for every tenant's custom domain. Handles DNS verification, certificate issuance, and renewal automatically.

CF Custom Hostnames

Inline Editor

WYSIWYG overlay on the live published site. Activated via ?edit=1 URL param or Cmd+E. Uses short-lived editor tokens (max 24h).

On Published Site
Architecture

System Layers

Every request passes through these layers. The edge routing decides which Worker handles it, the Worker talks to the data layer, and the Runner builds sites asynchronously.

People
Super Admin (HQ) Manages templates, views all tenants, platform-wide config
Franchise Owner Owns franchise locations, manages businesses, invites team
Business Admin / Editor Manages site content, publishes, connects domains, uses inline editor
Site Visitor Browses published websites on custom domains, submits forms
↓ HTTPS
Cloudflare Edge — Routing
Custom Domains Highest priority. Exact hostname → specific Worker. platform.onepointcode.com → Platform app.onepointcode.com → Dashboard
Custom Hostnames Tenant domains. CF provisions SSL per domain. www.mybusiness.com → catch-all fallback: platform.onepointcode.com
Catch-All Route Route pattern */* on zone. Catches all unmatched traffic including custom hostname requests. */* → Platform Worker
↓ routed
Cloudflare Workers — Compute
Platform Worker Dual-mode: REST API (/api/*) for dashboard + runner, OR static site server (Host header → KV → R2). Also handles queue messages and 5-min cron for domain sync. pagekiln-platform-worker-staging
Dashboard Worker Next.js SSR via OpenNext. Proxies API calls to Platform Worker. pagekiln-dashboard-staging
↓ binds to
Cloudflare — Data & Storage
D1 (SQLite) Tenants, users, sessions, content, domains, releases, audit logs, forms, franchise hierarchy pagekiln-staging
KV — HOSTMAP Host → tenant routing table host:example.com → {tenantId, tz}
KV — Rate Limit Signup 5/hr, forms 10/hr per tenant+IP signup_rl:{ip}:{hour}
R2 (Objects) All published site files sites/{tenant}/{version}/**
Queues Async build jobs pagekiln-build-jobs
Hyperdrive Connection pooler → Neon Postgres for data connectors external DB
↓ polls API
External VPS — Runner
Astro Site Generator Polls /api/runner/jobs/claim every 5s. Claims build jobs, runs Astro with the selected template, generates static HTML/CSS/JS, uploads artifacts to R2. pnpm runner
Templates coming-soon (system), starter-modern, starter-classic, starter-bold, onepoint-ops (custom). Each defines Astro page components + scoped styles.
Publish Flow

What Happens When You Click "Publish"

The journey from clicking the button to a live website, in 7 steps.

1

Publish

User clicks "Publish" in the dashboard. POST to /admin/site/publish.

2

Enqueue

Worker creates a build job in D1 and pushes a message to the Build Queue.

3

Claim

Runner polls the API, claims the job. Status moves to "running."

4

Build

Astro generates the static site using the selected template + CMS content.

5

Upload

Static files pushed to R2 under sites/{tenant}/{version}/.

6

Activate

Worker creates a release, marks it active, updates HOSTMAP_KV.

7

Live

Next visitor request is served the new version from R2. Done.

Request Lifecycle

How a Visitor Reaches a Site

From the browser's address bar to a fully rendered page — every hop.

Browser
Visitor types https://www.mybusiness.com/about
Cloudflare DNS
CNAME resolves to platform.onepointcode.com. SSL cert issued via Custom Hostname.
Edge Routing
No Custom Domain match → catch-all route */* sends to Platform Worker.
Platform Worker
Host header = www.mybusiness.com. Not an API path, so enters static site serving mode.
KV Lookup
Reads host:www.mybusiness.com from HOSTMAP_KV → {"tenantId":"t_pizza1","timezone":"US/Eastern"}
Version Resolve
Looks up active version from D1/KV cache: 2026-03-11T15:30:00Z
R2 Fetch
Reads sites/t_pizza1/2026-03-11T15:30:00Z/about/index.html from R2 bucket.
Response
200 OK — HTML page with Cache-Control: max-age=60. Hashed assets are immutable.
Org Hierarchy

Franchise Model

The platform supports multi-level organizations. HQ at the top, franchise owners in the middle, individual business sites at the bottom.

HQ — Super Admin Manages templates, views all tenants, platform config
Franchise A Pizza chain — 3 locations
Store #1nyc.pizzaco.com
Store #2la.pizzaco.com
Store #3chi.pizzaco.com
Franchise B Salon brand — 2 locations
Downtownwww.salondt.com
Uptownwww.salonut.com
Franchise C Gym network — 1 location
Main Gymwww.fitnet.com
Glossary

Quick Reference

Every major component at a glance.

Platform Worker

Hono REST API. Auth, CMS, domains, publishing, site serving, queue handler, scheduled cron. The core of everything.

Dashboard

Next.js operator UI. Content editing, domain management, template selection, team management, audit logs.

Runner + Generator

VPS process that claims build jobs and runs the Astro static site generator. Uploads results to R2.

D1 (SQLite)

Relational database. Tenants, users, content blocks, domains, releases, forms, franchise hierarchy, audit trail.

KV (HOSTMAP)

Maps host:domain.com{tenantId, timezone}. The routing table that connects custom domains to sites.

R2 (Object Storage)

S3-compatible. Stores every version of every site: HTML, CSS, JS, images. Immutable versioned paths.

Build Queue

Cloudflare Queues. Dashboard enqueues build jobs, Runner dequeues them. Decouples the "publish" click from the actual build.

Hyperdrive

Cloudflare's Postgres connection pooler + edge cache. Accelerates queries to an external Neon database for data connectors.

Custom Hostnames

CF API that provisions SSL for tenant domains. Auto-renewing certs, DNS verification, domain lifecycle management.

Inline Editor

WYSIWYG overlay on the published site. Cmd+E or ?edit=1. Token-based auth, publishes directly from the live page.