Never commit secrets. Use platform secret stores:
| Platform | Store |
|---|---|
| GitHub Actions | pnpm secrets:sync:github |
| Cloudflare Workers | wrangler secret put / pnpm secrets:sync |
| Cloudflare Pages | Project environment variables |
| Fly.io | fly secrets set |
GitHub Actions (production environment)
Section titled “GitHub Actions (production environment)”Deploy workflows use the production environment. Sync from local .env files:
pnpm secrets:sync:github -- --dry-runpnpm secrets:sync:githubMerge order (later wins): frontend/.env → frontend/.env.development → dashboard/.env → dashboard/.env.development → repo root .env. Empty keys are skipped. If FROM_EMAIL_ADDRESS is missing but MAILGUN_DOMAIN is set, no-reply@<domain> is derived automatically.
Keep production values in .env; use .env.development only for local overrides you do not want uploaded.
Requires gh CLI authenticated with secret write access.
Dashboard (Cloudflare Workers)
Section titled “Dashboard (Cloudflare Workers)”Worker name: soultales-partner. Full runbook: dashboard/DEPLOY.md in the monorepo.
Build-time vs runtime
Section titled “Build-time vs runtime”| Type | Examples | Where to set |
|---|---|---|
PUBLIC_* | PUBLIC_CLERK_PUBLISHABLE_KEY, PUBLIC_SITE_URL | GitHub Actions build secrets + local .env |
| Runtime | CLERK_SECRET_KEY, STRIPE_SECRET_KEY, DIRECTUS_TOKEN | Cloudflare Worker secrets only |
Sync runtime secrets from dashboard/secrets.json:
cd dashboardcp secrets.json.example secrets.json # first time onlypnpm secrets:syncGitHub Actions (deploy pipeline)
Section titled “GitHub Actions (deploy pipeline)”Set on the production environment (sync with pnpm secrets:sync:github from local .env / dashboard/secrets.json):
CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, PUBLIC_SITE_URL, PUBLIC_CLERK_PUBLISHABLE_KEY, PUBLIC_STRIPE_PUBLISHABLE_KEY, PUBLIC_CHATWOOT_WEBSITE_TOKEN
Worker runtime (webhooks and server): required keys — DIRECTUS_OUTBOUND_SECRET, CLERK_SECRET_KEY, CLERK_WEBHOOK_SIGNING_SECRET, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, DIRECTUS_URL, DIRECTUS_TOKEN, DIRECTUS_ADMIN_TOKEN. Deploy fails if any required key is missing from GitHub production. Optional keys (Mailgun, Chatwoot, Google Places, OpenAI, etc.) are synced when set. The deploy workflow runs scripts/validate-worker-secrets.mjs --worker dashboard after each deploy.
Frontend runtime sync
Section titled “Frontend runtime sync”The frontend deploy workflow also validates and syncs runtime secrets to soultales-www after each deploy (validate-worker-secrets.mjs --worker frontend).
Directus shared secret
Section titled “Directus shared secret”DIRECTUS_OUTBOUND_SECRET must match on the Worker and Fly Directus (real-ireland-app), with FLOWS_ENV_ALLOW_LIST=DIRECTUS_OUTBOUND_SECRET on Directus.
Other packages
Section titled “Other packages”Frontend (Cloudflare Workers)
Section titled “Frontend (Cloudflare Workers)”Worker name: soultales-www. See frontend/DEPLOY.md.
DIRECTUS_URL, DIRECTUS_TOKEN, GOOGLE_API_KEY (YouTube thumbnails at build time), Better Auth secrets (AUTH_SECRET, BETTER_AUTH_URL), Turso connection (ASTRO_DB_REMOTE_URL / ASTRO_DB_APP_TOKEN or TURSO_DATABASE_URL / TURSO_AUTH_TOKEN), OAuth client IDs, Mailgun keys
Backend
Section titled “Backend”DB_PASSWORD, R2 S3 credentials (STORAGE_S3_KEY, STORAGE_S3_SECRET), Directus KEY/SECRET
Helpdesk
Section titled “Helpdesk”SECRET_KEY_BASE, Neon Postgres, Upstash Redis, R2 credentials: see helpdesk/.env.example
Local development
Section titled “Local development”Copy .env.example files where provided. Use .env locally; files are gitignored.