Contents · Releases and partners

Docs / Releases and partners

Partner demo (5 min)

Partner loop: edit on draft, then promote.

Click-to-edit overlays on the draft host. Edits PATCH the entry on the same Worker — then promote when ready.
Immutable snapshot, then flip the published pointer. Roll back by pointing at the previous release.

Prove EdgeCMS’s wedge: edit → publish snapshot → channel promote → rollback on the same Worker, with Storyblok-class click-to-edit on a real demo route.

Audience: design-partner eng + marketer. No rebuild, no CDN purge dance.

Staging dry-run (operator, ~90s)

Live staging already has tenant partner + seeded baseline. Prefer this before a partner call:

bash
# From edgecms-saas tip
bun run demo:partner:dry-run:staging
# or:
bun scripts/partner-demo-dry-run.ts \
  --base-url https://edgecms-api-staging.cheongnanfeng.workers.dev \
  --website-url https://edgecms-website-staging.cheongnanfeng.workers.dev \
  --tenant partner \
  --email smoke.admin@example.com \
  --password 'SmokePassw0rd!'
# After website deploy with short aliases:
#   … --check-aliases

Expect every beat PASS (ensure → visual-edit → draft fidelity → promote → zh-CN provenance → locale-readiness → synergy → abac-deny → rollback). Auth requires an Origin header matching the API host (the script sets it).

SurfaceURL
1. Configurehttps://edgecms.skyvis.ai/demo/
2. Waiting roomhttps://edgecms.skyvis.ai/demo/waiting-room/
3. Protected sitehttps://edgecms.skyvis.ai/demo/site/
Legacy studio URL…/api/demo/studio → 302 to /demo/
Admin sign-inhttps://edgecms-api-staging.cheongnanfeng.workers.dev/sign-in
Releases UIhttps://edgecms-api-staging.cheongnanfeng.workers.dev/tenants/partner/releases
Published page…/api/tenants/partner/api/demo/pages/home?locale=en
Locale provenance…/demo/pages/home?locale=zh-CN
Docs (5 min)https://edgecms.skyvis.ai/docs/partner-demo-5min/
Docs (promote)https://edgecms.skyvis.ai/docs/atomic-edge-promote/
Short aliases/docs/partner-demo/ → 5 min; /docs/promote/ → Atomic Edge Promote

Product flow (same-site UI on edgecms.skyvis.ai): Configure brand/locale/channel → join waiting room (POST …/waiting-room/join) → gate opens after admitAt → admit (POST …/waiting-room/admit) → protected site (/demo/site/) loads JSON content and edits/promotes in page — no iframe studio.

Protection: marketing pages never show admin passwords. Waiting ticket is HMAC-scoped waiting only; admit upgrades to visual-edit + release (~15 min) on tenant partner / pages/home. Content/promote/rollback require the admitted capability.

Inventory: store docs/partner-staging.md. Do not quote public SLO numbers; no certification claims.

Prep (once, ~60s — local)

bash
cd edgecms-saas
bun install
bun run --filter edgecms-api db:migrate:local
# first-time local DB only — use the prepare-local-dev SUPER_ADMIN_EMAILS default
# so Admin dashboard tenant fleet does not 403 (role=admin ≠ allowlisted super-admin)
bun run db:seed:smoke -- --email smoke.admin@example.com --password 'SmokePassw0rd!' \
  --tenant-slug partner --tenant-name 'Partner Demo'
bun run dev:api    # :8787
bun run dev:admin  # :5173  (prefer explicit; `bun run dev` also runs website :8790)
  1. Sign in to Admin (http://localhost:5173) → open tenant partner → Releases.
  2. Click Ensure demo content (idempotent: creates pages / home + zh-CN → zh → en cascade; backfills thin zh body when missing).
  3. Label a release baseline, leave Promote to published checked → Publish snapshot.

Sanity:

bash
curl -i "http://localhost:8787/api/tenants/<tenant>/api/demo/pages/home?locale=en"
# expect 200, X-EdgeCMS-Perspective: published, X-EdgeCMS-Release-Id present

curl -i "http://localhost:8787/api/tenants/<tenant>/api/demo/pages/home?locale=zh-CN"
# expect X-Content-Locale-Resolved + X-Content-Locale-Provenance (title→en, body→zh)

Script (≈5 minutes)

MinYou doPartner sees
0:00Open Published page from Releases.Live page from the channel release (immutable KV snapshot).
0:30Open Visual edit host (same tenant). Click a field (title / hero heading), change copy, blur.Overlay highlight → status Saved … → D1 (draft). Host loads draft perspective with a preview token.
1:30Refresh Published page (no new snapshot yet).Old copy still live — DB is truth for draft; channel still points at baseline.
2:00Releases → label partner-edit-1 → Publish snapshot (promote on).New release id; channel pointer flips (<~2s).
2:30Refresh Published page.New copy live. Note X-EdgeCMS-Release-Id changed.
3:00Optional: ?locale=zh-CN on the demo page.Cascade headers: fallible title→en, body→zh; locale-exact legal→zh-CN (no silent fallback).
3:10Optional: GET …/admin/releases/<id>/locale-readiness after snapshot.ready: true (or LOCALE_EXACT_NOT_READY gaps block promote).
3:15ABAC deny beat (same sitting): POST …/admin/releases/demo/abac-deny (default locale=fr). Or open GET …/admin/releases/demo/synergy for the composed checklist.403 Attribute policy denied; audit chain / SIEM sink shows abac.denied next to entry.visual_edited / release.promoted.
3:30On the published channel card → Rollback.Pointer returns to baseline; previous snapshot still in KV; audit release.rolled_back.
4:00Refresh published page.Baseline copy restored — no rebuild.
4:30Close on the line: “Same Worker, draft and live; promote is a pointer, not a pipeline — and SecOps sees the loop.”

URLs (tenant-scoped)

Admin Releases:  /tenants/<tenant>/releases
Visual host:     /api/tenants/<tenant>/api/demo/host/home?locale=en
Published page:  /api/tenants/<tenant>/api/demo/pages/home?locale=en
Draft overlays:  …/pages/home?visualEdit=1&perspective=draft&previewToken=<token>
                 (host mints token; prefer opening via Visual edit host)

Failure checklist

SymptomFix
404 on demo pageEnsure demo content, then publish a snapshot.
Visual host save fails / CSRFStay signed in; host fetches /api/csrf and sends x-csrf-token.
Edits don’t show on published page after saveExpected until Publish snapshot + promote. Draft host should show edits immediately.
Rollback disabledNeed a previousReleaseId — publish at least two promoted releases.
Releases UI empty / wrong tenantAdmin calls must use /admin/releases (tenant-prefixed), not bare /api/admin/releases.

Composed synergy path (VE × locale-exact × release × env×release × locale × ABAC)

One partner sitting that multiplies the wedge bets:

bash
# Checklist + URLs (auth required) — includes locale-exact-readiness beat
curl -s -b <session> "http://localhost:8787/api/tenants/<tenant>/api/admin/releases/demo/synergy"

# After snapshot: locale-exact readiness (promote gate preview)
curl -s -b <session> "http://localhost:8787/api/tenants/<tenant>/api/admin/releases/<releaseId>/locale-readiness"

# ABAC deny → abac.denied on the tenant audit chain (and AUDIT_SIEM_* sink if set)
curl -i -b <session> -X POST "http://localhost:8787/api/tenants/<tenant>/api/admin/releases/demo/abac-deny" \
  -H 'content-type: application/json' -d '{}'

Lifecycle audit actions SecOps should see on the chain: entry.visual_edited, release.created, release.promoted, environment.release_pushed (when a linked-env push is release-sourced / promoteChannel), release.rolled_back (category content). Optional: set ENABLE_RELEASE_SEMANTIC=true → promote also indexes + emits release.semantic_indexed; search via GET …/admin/releases/:releaseId/semantic-search?q=… (spike, not GA). Environments carry a channel release across instances — they are not a second publish UX (atomic-edge-promote.md).

The visual-edit host forwards x-edgecms-locale + x-edgecms-channel=published on PATCH so custom roles with locale conditions can deny real edits; built-in unrestricted roles stay RBAC-only unless you use the abac-deny probe.

Out of scope for this script

Packaged Datadog/Splunk connectors (hookable webhook/NDJSON sink already exists — see operations-security.md), GA semantic search UX, release history pagination redesign, full invite→SIEM SecOps sitting (use security-walkthrough-10min.md).

Deep dive: atomic-edge-promote.md.

Edit docs/public/partner-demo-5min.md on GitHub