Platform baselineCloudflareSupabase

Multi-tenant Payload CMS

Lumen's platform, with Payload CMS as the console.

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.

PathWhat it is
blueprint.yamlThe card the console renders: overview, providers, inputs, the six brokered secrets, the programme
repo-blueprint.yamlThe 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.yamlThe contract each phase's task is opened with

What is here

PathWhat it is
apps/api-edgeThe one public HTTP entry point; reaches the workers over service bindings
apps/*-workerTwelve bounded-context Workers — identity, membership, projects, policy, events, config, metering, billing, notifications, webhooks, integrations, admin. Never public
apps/cmsThe 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-nextThe 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-migrateDatabase migrations — planned on pull requests, applied on merge
tests/*Per-component contract and verifier suites
intent.yamlThe 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.