Skip to content

Markdown version · llms.txt

On this page

This page is for the person who hosts the site, or for your AI agent. Most owners never need it.

Caution. Wrong environment values can take the site offline or send email from the wrong address. Back up first. Do not paste secret keys into chat logs. Ask your agent to do this with you.

Who should do this

  • Turning on a domain
  • Setting environment variables on Vercel (or another host)
  • First-time Supabase, Resend, or Twilio setup

Owners still click merge. The agent should not dispatch production database jobs unless you say so.

Where the site runs

Vercel is the usual host. Merging to main deploys production. There are no pull-request preview deploys.

The app also runs on any host that can run Node 24 with pnpm build and pnpm start. Details for Docker and other hosts live in the internal docs/HOSTING.md in the product repo. The environment names are the same everywhere.

Health check: GET /api/health returns {"ok":true}.

Environment variables

Set these on the host (Vercel → Environment Variables). Names:

NameWhat it is
NEXT_PUBLIC_SITE_URLPublic address, such as https://www.example.com. Baked in at build time.
NEXT_PUBLIC_SUPABASE_URLSupabase project URL. Build time.
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEYSupabase publishable key. Build time.
SUPABASE_SECRET_KEYSupabase secret key. Runtime.
NPM_TOKENGitHub token with read:packages, so the build can install @xylo/core. Never commit it.
RESEND_API_KEYEmail.
EMAIL_SENDERFrom-address, such as Brightside Studio <hello@example.com>.
STAFF_NOTIFY_EMAILSWho hears about new leads, comma-separated.
STAFF_NOTIFY_PHONESStaff mobiles in E.164 (+1…), comma-separated.
NEXT_PUBLIC_SMS_ENABLEDtrue only after Twilio is approved. Build time.
TWILIO_ACCOUNT_SID / TWILIO_AUTH_TOKENTexting.
TWILIO_MESSAGING_SERVICE_SIDMG…, preferred.
TWILIO_FROM_NUMBEROnly if you are not using a messaging service.
CRON_SECRETRandom, 32+ characters. Used by the follow-up job.
STRIPE_SECRET_KEYsk_test_… or sk_live_…. See Stripe setup.
STRIPE_WEBHOOK_SECRETwhsec_….
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYpk_…. Build time.
NEXT_PUBLIC_CAPTCHA_SITE_KEY / CAPTCHA_SECRET_TOKENOptional Turnstile, only if spam gets through.
CLIENT_IP_HEADEROptional. Host’s visitor-IP header.
XYLO_PUBLIC_SUPABASE_URLOptional. Only if phones cannot use the public Supabase URL.
POWERSYNC_URLOptional. Only if the native app syncs offline.

Leave Twilio and Stripe unset on Preview, so preview URLs never text real people or take real money.

NEXT_PUBLIC_* values are baked in at build time. Changing one means rebuild (a new deploy).

What a merge does

  1. You merge the pull request to main with a merge commit.
  2. Vercel builds and deploys.
  3. If the pull request added files under supabase/migrations/, migrations start on their own: backup, rehearse, then apply.

Code can go live a minute before migrations finish. New code is written to work with the old schema for that window.

First-time launch extras

The full launch runbook is internal (docs/LAUNCH.md). In short: create the owner’s Supabase project, turn off public sign-up, set site URL and /auth/confirm, paste the email templates, add Resend, then deploy. Invite the first owner with pnpm owner:invite. Everyone else is invited from admin → Staff.

Follow-up job

Supabase pg_cron calls /api/cron/nurture every 15 minutes with CRON_SECRET. Vercel also calls it once a day as a fallback. Backups do not run on Vercel. They run in GitHub Actions. See Backups and database changes.

Canonical: https://www.xylosoftware.com/cms/docs/hosting