Skip to content

Deployment

This monorepo deploys two separate front-ends to Cloudflare Pages, both connected to this GitHub repository. Each Pages project has its own dashboard build configuration. Cloudflare Pages only reads a single wrangler.toml at the repo root, and that file belongs to the members portal — so the admin app's settings live only in its Pages dashboard. This document is the source-of-truth for both so the dashboards can be reproduced or audited.

The repo is a pnpm workspace (pnpm-workspace.yaml, packageManager: pnpm@11.2.2 in the root package.json). Every Pages build must install from the repo root so the workspace resolves; setting a project's "Root directory" to a sub-app breaks the install.

Project 1 — yourpeople (Members Portal)

  • App: apps/members (@yourpeople/members), Nuxt 4 + Nitro cloudflare-pages preset.
  • Repo config: root wrangler.toml (name = "yourpeople-members", pages_build_output_dir = "apps/members/dist", compatibility_flags = ["nodejs_compat"]). Pages reads this on every deploy.
SettingValue
Root directory/
Build commandpnpm install --frozen-lockfile && pnpm --filter @yourpeople/members build
Build output directoryapps/members/dist
Node version22 (NODE_VERSION=22)

Production + Preview env vars: NUXT_SESSION_PASSWORD (rotating 32-byte random — never commit), NUXT_API_BASE, NUXT_PUBLIC_API_BASE. See apps/members/README.md for the full rationale (incl. why nodejs_compat is required).

Required environment variables (summary)

  • Members portal (@yourpeople/members / apps/members):

    • NUXT_SESSION_PASSWORD — strong secret (>=32 chars). Set as a Pages secret for Production and Preview.
    • NUXT_API_BASE — server-side base URL for the .NET API (host root, no trailing /api). Must be reachable from Pages.
    • NUXT_PUBLIC_API_BASE — client-side API base (same as NUXT_API_BASE in most setups).
  • Admin portal (@yourpeople/web / apps/web):

    • VITE_API_BASE_URL — base URL used by the SPA for API requests (exposed to client bundles). Set in Pages envs for Production/Preview.
    • VITE_CLERK_PUBLISHABLE_KEY — Clerk publishable key (if using Clerk).
  • Internal docs (@yourpeople/internal-docs / apps/internal-docs): none required.

Additional deploy checklist

  • Ensure Cloudflare Pages project Root directory is / and the build command runs from the repo root (use the --filter pnpm flag to target the specific workspace). Examples in the top-level DEPLOYMENT.md.
  • Node version: set NODE_VERSION=22 in Pages.
  • Secrets management: add keys in the Pages UI under Environment variables → Variables and secrets. Never commit production secrets to the repository.
  • If you rely on external services (Clerk, API, 3rd-party webhooks), confirm the service endpoints and webhook URLs are configured with the correct Pages domain (preview vs production) and that any required webhook secret is provided to the service.

Project 2 — yourpeopleapp (Admin Portal)

  • App: apps/web (@yourpeople/web), Vue 3 + Vite SPA (static output, no Worker — nodejs_compat not needed).
  • Repo config: none. The root wrangler.toml belongs to the members project, so this project is driven entirely by its dashboard settings below.
SettingValue
Root directory/
Build commandpnpm install --frozen-lockfile && pnpm --filter @yourpeople/web build
Build output directoryapps/web/dist
Node version22 (NODE_VERSION=22)

Why this project has been failing: it predates the pnpm-workspace conversion (PR #18) and its dashboard build command still runs an npm-based install against apps/web. With no usable root package.json for npm and apps/web now a workspace member, that install fails before any build step. Updating the build command and root directory to the values above fixes it.

If the admin app does not need its own public Pages deployment, delete this project instead — that removes a perpetually-red status check and the duplicate deploy webhooks on every PR.

Project 3 — yourpeople-internaldocs (Internal Docs)

  • App: apps/internal-docs (@yourpeople/internal-docs), VitePress static site. Pure static output — no Worker, no nodejs_compat.
  • Repo config: none. The root wrangler.toml belongs to the members project, so this project is driven entirely by its dashboard settings below. VitePress emits to apps/internal-docs/.vitepress/dist (srcDir: '.', outDir: '.vitepress/dist' in apps/internal-docs/.vitepress/config.mts).
SettingValue
Root directory/
Build commandpnpm install --frozen-lockfile && pnpm --filter @yourpeople/internal-docs build
Build output directoryapps/internal-docs/.vitepress/dist
Node version22 (NODE_VERSION=22)

No production/preview env vars required.

Root-directory gotcha: a failed deploy showed Cannot find cwd: /opt/buildhome/repo/apps/internals-docs — two mistakes in one. The folder is apps/internal-docs (singular "internal"), and "Root directory" must be /, not the sub-app. With the v2 root directory strategy (see the deploy log), the build output directory is resolved relative to the repo root, so it stays the full apps/internal-docs/.vitepress/dist. The --filter flag in the build command is what targets the app — never move the root into apps/internal-docs to do it.

Notes

  • Do not set "Root directory" to apps/members, apps/web, or apps/internal-docs. Pages clones the whole repo; the build command reaches into the target app via the --filter flag. A sub-directory root breaks pnpm-workspace resolution and fails on branches that don't contain that directory.
  • The GitHub Actions workflow (.github/workflows/members-ci.yml) is a separate CI surface from these Pages deploys; it lints, type-checks, tests and builds both apps plus the .NET API on every push.