2026 06 16 Manager Cloudflare Review
apps/manager Cloudflare Pages review — 2026-06-16
Scope: apps/manager Cloudflare implementation/configuration only. This review used the Cloudflare Pages/Workers/Storage/DNS skills and the repository Cloudflare inventory at docs/cloudflare-review/2026-06-16-skill-inventory.md. No Cloudflare APIs were called, no deploys were run, and no secrets were printed.
Evidence inspected#
apps/manager/wrangler.toml:1-4— Pages project name, output directory, compatibility date.apps/manager/package.json:7-15— Vite build/preview/typecheck/test scripts.apps/manager/vite.config.ts:25-54—VITE_BASE_PATH,build.outDir = "build", and chunking.apps/manager/public/_headers:1-10andapps/manager/public/_redirects:1— Pages headers and SPA fallback..mise.toml:1442-1444,.mise.toml:1532-1534,.github/workflows/cd.yml:75-88— build/deploy entrypoints.packages/saas-api/src/client.ts:36-47,packages/saas-api/src/client.ts:66-68,packages/saas-api/src/client.ts:114-123— browser API URL fallbacks.apps/manager/.env.example:1-14,apps/manager/src/env.d.ts:4-10,turbo.json:153-163— documented and cached build-time environment.
Verification run:
1$ mise run cf:build:manager2✓ 2955 modules transformed.3build/index.html 1.07 kB │ gzip: 0.47 kB4build/assets/index-BapuG47C.css 26.48 kB │ gzip: 5.76 kB5build/assets/vendor-query-537Rw8Y5.js 35.63 kB │ gzip: 10.53 kB6build/assets/vendor-router-KdrO8a7-.js 87.38 kB │ gzip: 28.19 kB7build/assets/vendor-ui-YeKRssKa.js 109.81 kB │ gzip: 36.45 kB8build/assets/vendor-react-C4mGKPvO.js 142.43 kB │ gzip: 45.84 kB9build/assets/index-ME5Hu1xp.js 378.37 kB │ gzip: 97.68 kB10build/assets/vendor-charts-CtruBP5P.js 392.70 kB │ gzip: 108.01 kB11✓ built in 8.73s1213$ mise exec -- pnpm exec node tools/scripts/check-cloudflare-artifact-budgets.mjs --app manager14manager: 11 files from apps/manager/build15 OK javascriptGzip: 319.0 KiB / 1.50 MiB16 OK assetsRaw: 1.12 MiB / 15.0 MiB17 OK largestAssetRaw: 383.5 KiB / 4.00 MiB18 OK workerRaw: 0 B / 1.00 MiBFindings#
HIGH — production Pages deploys do not pin the production branch#
Evidence:
wwwdeploys with--branch mainin.mise.toml:1528-1530and.github/workflows/cd.yml:78-82.managerdeploys omit--branch mainin.mise.toml:1532-1534and.github/workflows/cd.yml:84-88.- The CD workflow is tag-triggered (
.github/workflows/cd.yml:1-5), so relying on Wrangler's inferred branch can create or update a preview deployment instead of the Pages production deployment.
Impact: manager.assistance.bg may not receive a production deployment even when CI reports a successful Pages upload.
Recommended fix: confirm the Pages production branch for assistance-manager, then add the explicit branch to both deploy surfaces, matching www if production is main:
1cd apps/manager && wrangler pages deploy build --project-name assistance-manager --branch mainHIGH — Cloudflare build-time API URLs are not enforced for production#
Evidence:
cf:build:manageronly runspnpm --filter manager build(.mise.toml:1442-1444), and CI builds manager without environment overrides (.github/workflows/cd.yml:75-76).- The API client falls back in-browser to the current hostname plus local/dev ports when
VITE_AUTH_URL,VITE_API_URL, orVITE_LEARN_API_URLare absent (packages/saas-api/src/client.ts:36-47,packages/saas-api/src/client.ts:66-68,packages/saas-api/src/client.ts:114-123). apps/manager/.env.example:1-14documents local URLs for auth/billing and does not document the learn/academy URL.turbo.json:153-163tracks onlyVITE_API_URL,VITE_AUTH_URL,VITE_BASE_PATH, andNODE_ENVfor manager builds.- Manager admin academy routes use
academyClient(apps/manager/src/routes/_admin/admin/academy/live-sessions.tsx:25,:63,:75,:113,:122,:320), which uses theVITE_LEARN_API_URL/:3065fallback.
Impact: a Cloudflare-hosted browser can be compiled to call https://manager.assistance.bg:3046, https://manager.assistance.bg:3047/api/v1, and https://manager.assistance.bg:3065/api/v1, which are dev-port assumptions rather than durable Cloudflare production endpoints.
Recommended fix: make the production Pages build/deploy require explicit public API origins for auth, billing, and academy/learn. Add VITE_LEARN_API_URL to apps/manager/src/env.d.ts, apps/manager/.env.example, and turbo.json once the production origin is chosen. In CI/Pages, set the actual public values as environment variables/secrets; do not rely on fallback ports for production.
MEDIUM — custom domain/routing ownership is not represented as desired state in this repo#
Evidence:
apps/manager/wrangler.toml:1-4declares only the Pages project name, output directory, and compatibility date; no routes/custom-domain state is represented there..mise.toml:1643-1655expectshttps://manager.assistance.bg/to be healthy, but the repo has no reviewed desired-state artifact bindingmanager.assistance.bgto theassistance-managerPages project.- The Cloudflare Pages skill documents custom-domain binding as a REST/API operation and the Service Registry skill says registry-owned DNS/Caddy surfaces should remain coordinated rather than manually drifted.
Impact: an operator can rebuild and deploy the Pages project while the public hostname binding/DNS state remains undocumented or drifts outside the repository.
Recommended fix: document the current ownership path for manager.assistance.bg in .docs/cloudflare-deployment.md or a small runbook: Pages project, production branch, custom-domain binding owner, DNS owner, and the exact non-secret verification command. If DNS is registry-owned, use the Service Registry workflow for DNS records; if Cloudflare-owned, use the Cloudflare DNS desired-state workflow.
Positive findings#
- Static Pages suitability is good:
apps/manager/package.json:9runsvite build,apps/manager/vite.config.ts:30-31emitsbuild/, andapps/manager/wrangler.toml:2-3points Pages at the same project/output. - SPA routing is configured for Cloudflare Pages via
apps/manager/public/_redirects:1and was present in the built output. - Private/noindex and basic security headers are configured in
apps/manager/public/_headers:1-10and copied intobuild/_headers. - Artifact size is comfortably under the configured Cloudflare budget: JavaScript gzip is
319.0 KiB / 1.50 MiB, raw assets are1.12 MiB / 15.0 MiB. - No Worker, KV, D1, R2, Durable Object, or service bindings are required by the current Manager Cloudflare shape. It is a static Vite SPA that talks to backend APIs over HTTP.
compatibility_date = "2025-04-01"is explicit (apps/manager/wrangler.toml:4). For the current static-only Pages deployment, nonodejs_compator runtime compatibility flag is needed because there are no Pages Functions or Worker bindings.
Changes applied#
No implementation/configuration fixes were applied. The only repository change from this review is this evidence-backed audit document.