# Deploy & Branch Guide — creative.relayctx.com

*How the creative estate is built, hosted, and shipped. Read this before
merging any PR in this repo.*

Companion to [`MAINTENANCE.md`](MAINTENANCE.md) (which covers the hub + area
index cards, labels, and `_redirects` rules). This file covers **the pipeline**:
host, build, branch model, and how work reaches production.

---

## TL;DR

- **Host:** Cloudflare Pages project **`relay-creative`** (né `relay-prototype`)
  → serves **`creative.relayctx.com`**.
- **No build step.** The repo root is served as **static files, verbatim**. The
  build config is intentionally empty.
- **Production branch is `main`** — the GitHub default. A push/merge to `main`
  auto-deploys. One trunk; there is no separate deploy branch anymore.
- Work on **area-prefixed branches** (`brand/*`, `marketing/*`, `concepts/*`,
  `email/*`, `mcp/*`, or `chore/*`/`fix/*`), PR into `main`.
- **`prototype.relayctx.com` is retiring** — it redirects to
  `creative.relayctx.com` until **2026-08-09**, then the custom domain comes off.

---

## Host & build

The site is a **Cloudflare Pages** project named **`relay-creative`**, connected
to `christensen-digital/relay-creative`. Because the pages are hand-authored
HTML/CSS/JS with **no bundler or generator**, there is **no build**:

| Cloudflare setting | Value | Why |
|---|---|---|
| Build command | *(empty)* | Nothing to compile — static files served as-is |
| Build output directory | *(empty)* | Output *is* the repo root |
| Root directory | *(empty)* | Repo root |
| Build system version | Version 3 | — |
| Build cache | Disabled | No build to cache |
| Deploy hooks | None | Deploys are triggered by branch pushes |
| **Production branch** | **`main`** | One trunk = one deploy branch |

> **The empty build config is correct, not broken.** If someone "fixes" it by
> adding a build command or output directory, deploys will start serving the
> wrong path (or nothing). Leave it blank.

**Clean URLs** are handled by [`_redirects`](_redirects) — a Cloudflare-native
file Pages reads automatically. It maps clean paths to versioned files
(`/concepts/app` → `/concepts/app-v34`), carries the full legacy map from the
2026-07-19 restructure (old `/web/*` and root paths 301 to their new homes),
and holds the host rule that redirects `prototype.relayctx.com` here. See
`MAINTENANCE.md` for the URL conventions.

**Markdown renders branded.** A single Pages Function —
[`functions/_middleware.js`](functions/_middleware.js) — intercepts `GET *.md`
and returns the file rendered in the v3.5 reader shell (server-side at the
edge; `?raw=1` serves the stored file verbatim). Pages auto-detects
`functions/` and bundles it itself, so the **empty build config still stands**.
`_redirects` rules are evaluated *before* Functions, so the legacy map is
unaffected. This is the one non-static piece of the site — keep it that way.
Cards to markdown *in this repo* (`briefs/`, `CHANGELOG.md`s, this guide) can
link locally now; the documentation pipeline (MkDocs) still covers the
separate doc repos — this site doesn't render *their* markdown, only its own.

---

## Branch model — one trunk

**`main` is the only long-lived branch.** It is the GitHub default, the
canonical branch, and the production branch — every merge to `main` deploys to
`creative.relayctx.com` immediately. The old two-trunk split (`prototype` =
served content, `main` = docs) was converged on 2026-07-19; docs, briefs,
workflows and served pages now travel together, and "merged but didn't ship"
can't happen anymore.

**Working branches are area-prefixed and short-lived:**

| Prefix | For |
|---|---|
| `concepts/*` | Product-surface concept work |
| `marketing/*` | Marketing site, stealth, decks, direction studies |
| `brand/*` | Identity, tokens, type, brand guide, assets |
| `email/*` | Email gallery + drafts |
| `mcp/*` | MCP visual reference |
| `chore/*`, `fix/*`, `docs/*` | Cross-area or repo-level work |

Branch from `main`, keep the branch scoped to its area, PR back into `main`.
A page lands with its card, its `_redirects` entry (if its clean URL changed),
and a line in its area `CHANGELOG.md` — in the same PR.

### Area → branch, at a glance

Every area folder ships from the **same single branch**. `prototype`,
`brand`, `marketing`, etc. are not separate deploy pipelines — they're
folders in this one repo that all merge into `main` and go live together
on the next push:

| Area you're editing | Folder | Ships via |
|---|---|---|
| Concepts / product prototypes | `concepts/` | `main` |
| Marketing site | `marketing/` | `main` |
| Brand | `brand/` | `main` |
| Email gallery | `email/` | `main` |
| MCP visual reference | `mcp/` | `main` |
| Decks | `decks/` | not served — reference only |
| Briefs, `MANIFEST.md`, this guide, `scripts/` | `briefs/`, root docs, `scripts/` | `main` — same branch, nothing is docs-only anymore |

> **The historical `prototype` branch is frozen at the convergence point —
> don't push to it.** It does not deploy (Cloudflare's production branch is
> `main`; `prototype.relayctx.com` is now only a redirect shim, see below),
> but it has still been taking stray merges since the freeze (e.g. PR #185
> on 2026-07-26, PR #192 on 2026-07-29) — those changes are **not live**
> anywhere. If a PR's base defaults to `prototype`, that's the trap:
> retarget it to `main`. The branch will be deleted once the redirect
> window closes (2026-08-09) — see the domain migration section below.

---

## Previews & rollback

- **Preview deploys:** Cloudflare Pages builds a preview URL for every
  non-production branch / PR, so you can eyeball a change before it hits
  `main` (and production).
- **Rollback:** there's no build to revert to — roll back from the **Cloudflare
  Pages dashboard** (Deployments → pick a previous successful deploy →
  *Rollback*), or revert the commit on `main` and push.

---

## Domain migration — prototype → creative (2026-07-19)

The gallery moved from `prototype.relayctx.com` to **`creative.relayctx.com`**
when the repo was restructured by area (hub at `/`, areas at `/concepts/`,
`/marketing/`, `/brand/`, `/email/`, `/mcp/`).

**Grace window:** both custom domains stay attached to the Pages project; the
host rule at the top of `_redirects` 301s every `prototype.relayctx.com` URL to
the same path on `creative.relayctx.com`, and the legacy path map carries it on
to the page's new home. Old bookmarks land correctly through both hops.

**Retire date: 2026-08-09** (3 weeks). After that:

1. Cloudflare Pages → the project's Custom domains → remove
   `prototype.relayctx.com`.
2. Delete the `prototype.relayctx.com` DNS record (relayctx.com zone).
3. Delete the host rule at the top of `_redirects`.
4. Delete the frozen `prototype` branch on GitHub.

### One-time dashboard setup (done at migration)

For the record, the migration required, in order: verify the restructure PR
merged to `main` → Pages project → Settings → Builds & deployments →
**Production branch: `main`** → Custom domains → add
`creative.relayctx.com` → confirm both domains resolve → merge the
`_redirects` host rule → rename the Pages project `relay-prototype` →
**`relay-creative`** (renaming changes the `*.pages.dev` preview hostnames —
custom domains are unaffected, but any saved preview links go stale, so
re-grab preview URLs after the rename).

---

*Last updated: 2026-07-19 · relay-creative/GUIDE.deploy.md*
