Appearance
Cloudflare Pages V2 Dev Deploy Runbook
Status: deployed and verified on Cloudflare Pages
Source Of Truth
Manifest:
txt
deploy/cloudflare/pages.frontend.jsonDeploy script:
txt
scripts/deploy/cloudflare-pages.mjsThe deployment method is Cloudflare Pages Direct Upload with Wrangler:
bash
npx wrangler pages deploy <DIRECTORY> --project-name <PROJECT_NAME> --branch v2-devOfficial references:
- Cloudflare Pages Direct Upload:
https://developers.cloudflare.com/pages/get-started/direct-upload/ - Cloudflare Pages custom domains:
https://developers.cloudflare.com/pages/configuration/custom-domains/ - Cloudflare Pages REST API:
https://developers.cloudflare.com/pages/configuration/api/ - Cloudflare Pages monorepos:
https://developers.cloudflare.com/pages/configuration/monorepos/
This runbook uses Direct Upload because the v2-dev target has seven Pages surfaces: six frontend apps plus the VitePress docs site. Cloudflare's Git-connected monorepo flow currently documents a default limit of five Pages projects per repository. If v2-dev later moves from Direct Upload to Git integration, request a limit increase, split repositories, or move one surface to another static deployment target before wiring all seven projects to the same repository.
Domain Map
| App | Pages project | Domain |
|---|---|---|
| Admin | hoctapaz-v2-dev-admin-web | v2.dev.admin.hoctapaz.com |
| Staff | hoctapaz-v2-dev-staff-web | v2.dev.staff.hoctapaz.com |
| Teacher | hoctapaz-v2-dev-teacher-web | v2.dev.teacher.hoctapaz.com |
| Student | hoctapaz-v2-dev-student-web | v2.dev.student.hoctapaz.com |
| Parent | hoctapaz-v2-dev-parent-web | v2.dev.parent.hoctapaz.com |
| Public | hoctapaz-v2-dev-public-web | v2.dev.hoctapaz.com |
| Docs | hoctapaz-v2-dev-docs-web | v2.dev.docs.hoctapaz.com |
Provisioned Cloudflare State
As of 2026-07-05, Cloudflare account 9dcb06f92077d2d922d47c332b54cd32 owns the active hoctapaz.com zone 1d768be3b6af3f0a6e52acce15fef09b.
The seven Pages projects have been created with production branch v2-dev:
| Pages project | Pages subdomain |
|---|---|
hoctapaz-v2-dev-admin-web | hoctapaz-v2-dev-admin-web.pages.dev |
hoctapaz-v2-dev-staff-web | hoctapaz-v2-dev-staff-web.pages.dev |
hoctapaz-v2-dev-teacher-web | hoctapaz-v2-dev-teacher-web.pages.dev |
hoctapaz-v2-dev-student-web | hoctapaz-v2-dev-student-web.pages.dev |
hoctapaz-v2-dev-parent-web | hoctapaz-v2-dev-parent-web.pages.dev |
hoctapaz-v2-dev-public-web | hoctapaz-v2-dev-public-web.pages.dev |
hoctapaz-v2-dev-docs-web | hoctapaz-v2-dev-docs-web.pages.dev |
Each target hostname is attached to its Pages project as a custom domain and has a proxied CNAME in the hoctapaz.com zone:
txt
v2.dev.admin.hoctapaz.com -> hoctapaz-v2-dev-admin-web.pages.dev
v2.dev.staff.hoctapaz.com -> hoctapaz-v2-dev-staff-web.pages.dev
v2.dev.teacher.hoctapaz.com -> hoctapaz-v2-dev-teacher-web.pages.dev
v2.dev.student.hoctapaz.com -> hoctapaz-v2-dev-student-web.pages.dev
v2.dev.parent.hoctapaz.com -> hoctapaz-v2-dev-parent-web.pages.dev
v2.dev.hoctapaz.com -> hoctapaz-v2-dev-public-web.pages.dev
v2.dev.docs.hoctapaz.com -> hoctapaz-v2-dev-docs-web.pages.devdig @1.1.1.1 resolves all seven names to Cloudflare edge IPs. Cloudflare API reports all seven custom domains as active.
Initial verified deployment evidence:
| App | Deployment ID | Preview URL | Custom domain status |
|---|---|---|---|
| Admin | bccd99d5-49a9-4fab-85ff-0954bfa92d71 | https://bccd99d5.hoctapaz-v2-dev-admin-web.pages.dev | active |
| Staff | 333f56d2-4a94-488b-8e80-c442840c091a | https://333f56d2.hoctapaz-v2-dev-staff-web.pages.dev | active |
| Teacher | e800a534-8ffb-440d-bfbf-b1ea5570e6b9 | https://e800a534.hoctapaz-v2-dev-teacher-web.pages.dev | active |
| Student | 10955c91-7270-49f9-bcdd-ab46f8b0cf98 | https://10955c91.hoctapaz-v2-dev-student-web.pages.dev | active |
| Parent | c8d70b0f-1d6d-4547-8d92-a44212303e9e | https://c8d70b0f.hoctapaz-v2-dev-parent-web.pages.dev | active |
| Public | 32ad82e9-f8c6-4ab4-ac9a-065674a2b05e | https://32ad82e9.hoctapaz-v2-dev-public-web.pages.dev | active |
| Docs | c54b85c8-6d70-4f84-943f-7281842b4f7e | https://c54b85c8.hoctapaz-v2-dev-docs-web.pages.dev | active |
Prerequisites
Wrangler must be authenticated by one of:
bash
npx wrangler loginor non-interactive environment variables:
bash
export CLOUDFLARE_API_TOKEN=...
export CLOUDFLARE_ACCOUNT_ID=...
export VITE_API_BASE_URL=https://<gateway-host>Token permissions must include Cloudflare Pages edit access. Custom domains require the hoctapaz.com zone to be available in the same Cloudflare account or a valid CNAME/custom-domain setup. The deploy script compiles apps with VITE_APP_ENV=v2-dev; VITE_API_BASE_URL is required so deployed bundles never fall back to localhost or demo auth behavior.
turbo.json whitelists VITE_API_BASE_URL and VITE_APP_ENV for the build task. If you prebuild with Turbo and then deploy with --skip-build, use --force when changing these env values:
bash
VITE_API_BASE_URL=https://hoctapaz.com VITE_APP_ENV=v2-dev pnpm turbo run build '--filter=./apps/*' --forceCommands
Deploy all apps:
bash
cd go-platform
pnpm deploy:cloudflare:pagesDeploy one app:
bash
pnpm deploy:cloudflare:pages -- --app public-webDeploy only the VitePress docs site:
bash
pnpm docs:build
pnpm deploy:cloudflare:pages -- --app docs-web --skip-buildCreate Pages projects before deploying when they do not exist. The v2-dev projects listed above already exist, so this flag should not be used for the current account unless a project was deleted:
bash
pnpm deploy:cloudflare:pages -- --create-projectsUse existing build outputs:
bash
pnpm deploy:cloudflare:pages -- --skip-buildDry-run command expansion:
bash
pnpm deploy:cloudflare:pages -- --dry-run --skip-buildCustom Domains
After the first successful deployment, attach each domain through Pages Custom domains. Cloudflare docs require associating the hostname with the Pages project; adding a DNS CNAME alone is not sufficient.
If the zone is managed by the same Cloudflare account, the dashboard can create the DNS records during custom-domain setup. Otherwise create the CNAME to the project *.pages.dev hostname after the Pages custom-domain association is created.
Verification
For each domain:
bash
curl -I https://v2.dev.hoctapaz.com/
curl -I https://v2.dev.admin.hoctapaz.com/
curl -I https://v2.dev.staff.hoctapaz.com/
curl -I https://v2.dev.teacher.hoctapaz.com/
curl -I https://v2.dev.student.hoctapaz.com/
curl -I https://v2.dev.parent.hoctapaz.com/
curl -I https://v2.dev.docs.hoctapaz.com/Expected:
200for/.- SPA fallback works for
/login,/register, and/auth/login. - Static assets return long cache headers from
_headers.
2026-07-05 verification:
npx wrangler whoamiauthenticated against account9dcb06f92077d2d922d47c332b54cd32.pnpm deploy:cloudflare:pages -- --skip-builduploaded all six app outputs.pnpm deploy:cloudflare:pages -- --app docs-web --skip-builduploaded the VitePress docs output fromdocs/.vitepress/dist.- Cloudflare API reported each latest deployment stage as
success. - Cloudflare API reported each attached custom domain as
active. curlreturned200 text/htmlfor all six frontend custom domains and representative/login//registerSPA fallback paths.curlreturned200 text/htmlforhttps://v2.dev.docs.hoctapaz.com/,/api/, and/contracts/openapi/.- Live Playwright smoke passed for
https://v2.dev.hoctapaz.com/public auth hub andhttps://v2.dev.admin.hoctapaz.com/admin login redirect. - Live Playwright smoke passed for
https://v2.dev.docs.hoctapaz.com/home, API guide, and OpenAPI contracts pages.
Notes
The Cloudflare API connector can manage projects, custom domains, DNS, and deployment metadata. Local asset upload still uses Wrangler because Pages Direct Upload sends build files from dist/ through Wrangler's upload-token and asset upload flow.