Lumen Payload
sourceplane/lumen-payload — a multi-tenant SaaS on Cloudflare Workers
and Supabase Postgres, run as an Orun
component-native desired-state repo. Identity, organizations, projects, RBAC,
audit, metering, billing, webhooks and notifications are separate
bounded-context Workers behind one public edge API. The product opens in its
Payload CMS admin, which is the console: a Lumen account signs in, and the
account, organization, notifications and billing pages live inside it.
Live deployment
This product is live. Verified URLs, identity, and the secrets inventory are recorded in ai/context/deployment.md (regenerated by the docs flow — command in the operating contract); how it deploys and how to operate it: ai/context/operations.md.
Working on it
Start at AGENTS.md. It is written for a coding agent and is the shortest way in for a person too: what to read first, how a change lands, and what not to touch.
A baseline: products from this repository
This repository is also the Multi-tenant Payload CMS baseline: a product
is born from it — its own repository, Supabase projects, Workers and CMS, live
on stage and prod — by one artifact, repo-blueprint.yaml,
run by orun new (BOOTSTRAP.md →
docs/phases/). Eight idempotent phases — scaffold,
foundation, infrastructure, database, workers, edge, console, docs — each land
a verified pull request, and each is selectable with --phase <name>. The
console phase is this baseline's own: it lands the Payload CMS and the console
URL that redirects into it. What the owner does afterwards is open the CMS
admin with a setup token only they hold.
A product receives product-only content, branded with its own name: the
source, infrastructure and CI, its own README, AGENTS.md and operating guide.
None of the factory below ships, and nothing in a product says lumen: the
CMS names the platform lumen in its code (lib/lumen/, lumenUserId,
LUMEN_API), and the rebrand renames every form of it — paths included — into
the product's, so a Payload field and the column it maps to, a route and the
URLs that reach it, still agree.
| Path | What it is |
|---|---|
blueprint.yaml | The card the console renders: overview, providers, inputs, the six brokered secrets, the programme |
repo-blueprint.yaml | The build: every module, the eight phases and their hooks |
BOOTSTRAP.md, docs/phases/ | How to run it, phase by phase, and what each phase proves |
.baseline/product/ | The product's README, AGENTS.md and deployment stub, rendered with its name |
tooling/rebrand/ | The rename engine: this repository's own identity (.rebrand/values.json) into the product's |
tooling/bootstrap/, hooks/ | The hooks' scripts: promotion and dev-lane deferral, redeploy markers, the deployment record |
testing/ | The baseline's own gates, run by .github/workflows/baseline.yml: the card against the build, every component placed once, a product placed and branded offline, and that product installed, typechecked and tested |
tasks/0*.TaskContract.yaml | The contract each phase's task is opened with |
What is here
| Path | What it is |
|---|---|
apps/api-edge | The one public HTTP entry point; reaches the workers over service bindings |
apps/*-worker | Twelve bounded-context Workers — identity, membership, projects, policy, events, config, metering, billing, notifications, webhooks, integrations, admin. Never public |
apps/cms | The product and its console: Payload CMS on Workers (OpenNext), signed in with a Lumen account; content, media on R2, and the account and billing pages, calling the edge server to server |
apps/web-console-next | The old console URL, now a redirect Worker: every path answers 308 to its place in the CMS |
packages/* | Shared libraries: contracts, SDK, CLI, the database harness, the policy engine, the notifications client, the webhook verifier |
infra/terraform/* | The data plane: Supabase projects, Hyperdrive, the edge's idempotency KV, and the custom-domain component (parked until a domain is set) |
infra/db-migrate | Database migrations — planned on pull requests, applied on merge |
tests/* | Per-component contract and verifier suites |
intent.yaml | The environments, the pinned composition catalog, and the Orun workspace this repository deploys into |
stage and prod are provisioned and deployed; dev is verify-only.
Getting started
Node.js 20 or later and pnpm 10.
pnpm install
pnpm typecheck
pnpm lint
pnpm test
pnpm build
How it deploys
Merges to main converge through Orun: .github/workflows/ci.yml runs
orun plan --changed, then one orun run lane per planned component. A pull
request plans and verifies; a push to main deploys stage, then prod once
stage has converged on the same commit. No pnpm, Wrangler or Terraform
command runs directly in CI.
The pipeline holds one credential, GitHub's own GITHUB_TOKEN. Cloudflare and
Supabase credentials are brokered per run from the workspace's connections;
nothing provider-shaped is stored in the repository or in GitHub.
Custom domain
The product answers on workers.dev from its first deploy. Setting a domain is one pull request, later: Setting the domain later.
Build from the console
Press Build: Multi-tenant Payload CMS goes into the workspace you choose (or a new one), you connect Cloudflare and Supabase, and an agent builds it.
Build from the CLI
# check providers, then build
orun baseline check lumen-payload
orun baseline new lumen-payload --via-platform --repo acme/lumen-payload