2026 06 16 Deployment Docs Review
Cloudflare deployment docs/task surface review — 2026-06-16
Scope: repo-level Cloudflare deployment, task, and documentation surfaces: .mise.toml, root package.json, .docs/cloudflare-deployment.md, docs/cloudflare-*.md, docs/hosting-inventory-2026-06-16.md, and docs/performance-smoke-checks.md. App Wrangler/OpenNext files were inspected only where needed to verify drift claimed by repo-level docs or tasks.
No Cloudflare APIs were called, no deployments were run, and no secrets were printed.
Guidance baseline used#
- Cloudflare skills index prefers
CF_API_TOKEN, optionally mirrored toCLOUDFLARE_API_TOKEN, plusCF_ACCOUNT_IDfor account-level Workers/Storage/Pages operations; it also documents least-privilege scopes for Workers, KV/D1/R2, Pages, and DNS. - Cloudflare Pages guidance prefers Wrangler for uploads/deploys, REST only where Wrangler lacks coverage, and says to coordinate DNS through the Service Registry when the registry owns the zone.
- Cloudflare Workers guidance prefers route declarations in
wrangler.toml/wrangler.jsoncand notes thatsvc.assistance.bg/internal routing is typically Service Registry-owned. - Cloudflare Storage guidance requires explicit KV/D1/R2 bindings and careful token/scopes for storage operations.
- Service Registry guidance says
https://registry.svc.assistance.bgis the default routed endpoint,svc.assistance.bghosts are registry/Caddy/split-horizon managed, and new internal hosts should use delegated subzones rather than flat public-domain/internal-zone names.
Positive findings#
- The repo has a centralized
miseCloudflare surface for build, deploy, release, D1 indexing, and health checks (.mise.toml:1396-1656). - Root
package.jsonpins Wrangler as a managed dev dependency and exposes Cloudflare performance-budget scripts (package.json:30-32,package.json:96,package.json:125-134). - The hosting inventory captures the current high-level topology: Pages for
www/manager, Workers+OpenNext fordocs/blog/academy/design-system/ui-library, and self-hosted Go backends (docs/hosting-inventory-2026-06-16.md:17-36). - Aggregate deploys include a preflight that prevents the most common OpenNext/KV auth failure by requiring
CLOUDFLARE_API_TOKENbefore parallel deploys (.mise.toml:1477-1513).
Findings#
1. Health/smoke targets do not match repo-declared Cloudflare routes#
- Severity: High
- Evidence:
cf:healthchecks flat hostnames for all frontend apps:docs.assistance.bg,ds.assistance.bg,ui.assistance.bg,academy.assistance.bg,manager.assistance.bg, andblog.assistance.bg(.mise.toml:1643-1656).prod:smokechecks onlywww.assistance.bg,manager.assistance.bg, anddocs.assistance.bgfor frontends (.mise.toml:959-967).- The only inspected Worker config with explicit routes is
apps/docs/wrangler.jsonc, and those routes are path-based:www.assistance.bg/docs*andassistance.bg/docs*(apps/docs/wrangler.jsonc:7-14). docs,blog,design-system, andui-librarysetworkers_dev=false, but onlydocshas repo-declared routes;blog,design-system, andui-libraryhave no routes in their checked Wrangler configs (apps/blog/wrangler.jsonc:5,apps/design-system/wrangler.jsonc:5,apps/ui-library/wrangler.jsonc:5).
- Why this matters: a deployment can pass
wrangler deploywhile the repo health task probes hostnames that are not declared in repo-managed routing. Conversely, a correct path-based deployment (www.assistance.bg/docs*) may be reported unhealthy by checks againstdocs.assistance.bg. - Recommended fix:
- Decide the canonical public URL per app.
- If flat hostnames are canonical, declare the corresponding Workers routes/custom domains in the relevant Wrangler configs or document the external dashboard-managed source of truth.
- If path-based composition is canonical, change
cf:healthandprod:smoketo probe the actual routes, e.g.https://www.assistance.bg/docs/for docs and the Pages Function paths for blog/docs where applicable.
2. Academy enables OpenNext KV incremental cache without a Wrangler KV binding#
- Severity: High
- Evidence:
apps/academy/open-next.config.tsimports and enableskvIncrementalCache(apps/academy/open-next.config.ts:3-7).apps/academy/wrangler.jsoncdeclares the Worker entry,nodejs_compat, and Workers Assets, but has nokv_namespacesbinding (apps/academy/wrangler.jsonc:1-10).- The hosting inventory already flags that no KV namespace was present for academy (
docs/hosting-inventory-2026-06-16.md:33). - Other OpenNext apps using KV expose a
NEXT_INC_CACHE_KVbinding in Wrangler config (apps/blog/wrangler.jsonc:12-16,apps/design-system/wrangler.jsonc:12-16,apps/ui-library/wrangler.jsonc:12-16,apps/docs/wrangler.jsonc:19-23).
- Why this matters: this is a repo-local OpenNext/storage binding drift. Depending on adapter behavior, academy can fail during deploy/runtime cache operations or silently lose intended incremental-cache behavior.
- Recommended fix: choose one desired state and make config/docs agree:
- If academy needs KV incremental cache, provision a namespace and add
NEXT_INC_CACHE_KVtoapps/academy/wrangler.jsoncwith the same binding convention as other OpenNext apps. - If academy should not use KV, remove the
kvIncrementalCacheoverride fromapps/academy/open-next.config.tsand update docs that currently imply academy is a normal KV-backed Worker.
- If academy needs KV incremental cache, provision a namespace and add
3. .docs/cloudflare-deployment.md DNS guidance is stale and boundary-blurring#
- Severity: Medium
- Evidence:
- The doc says
www.assistance.bgis “managed in Cloudflare DNS (proxied, orange cloud)” (.docs/cloudflare-deployment.md:109-112). - It also says internal
dev/prodsubzones are NS-delegated to Linode and then recommendsmcp__registry__dns_cloudflare/mcp__registry__dns_linodegenerically (.docs/cloudflare-deployment.md:113-128). - Current repo tasks and inventory focus on public
assistance.bgapp hostnames and Pages/Workers deployments, not the nestedassistance.prod.assistance.bg/assistance.dev.assistance.bgtree shown in that doc (.mise.toml:1528-1554,docs/hosting-inventory-2026-06-16.md:79-105). - Service Registry guidance draws a stricter boundary:
svc.assistance.bginternal hosts are registry/Caddy/split-horizon managed, while Cloudflare Pages/Workers custom-domain bindings and public-zone DNS need explicit coordination.
- The doc says
- Why this matters: an operator following the stale DNS section could mutate the wrong DNS plane, assume flat public hostnames are registry-owned, or miss that Worker routes/custom domains must align with the actual Cloudflare zone.
- Recommended fix: rewrite the DNS section around ownership boundaries:
- Public
assistance.bgCloudflare zone: use Cloudflare DNS/Workers routes/custom-domain guidance and avoid hardcoded zone IDs. - Registry/Linode/split-horizon zones: use Service Registry MCP/API, especially for
svc.assistance.bg, delegated service subzones, and Caddy exposure. - Document the current canonical app URL map and where each URL is configured (
wranglerroute, Pages custom domain, registry record, or external dashboard state).
- Public
4. Token and secret handling is partially documented but inconsistent across surfaces#
- Severity: Medium
- Evidence:
cf:deploy:preflightrequires onlyCLOUDFLARE_API_TOKENand prints minimum scopes for Workers Scripts, Workers KV Storage, and Pages (.mise.toml:1477-1492).- The Cloudflare skills baseline prefers
CF_API_TOKEN, withCLOUDFLARE_API_TOKENas a compatibility alias, and also calls outCF_ACCOUNT_IDfor account-level operations. .docs/cloudflare-deployment.mdlists deploy and D1 index commands but does not document required env vars/scopes for deploys, Pages secrets, D1 indexing, or Worker routes (.docs/cloudflare-deployment.md:62-79,.docs/cloudflare-deployment.md:147-157).apps/www/wrangler.tomlcorrectly keeps form secrets as comments/instructions rather than values (apps/www/wrangler.toml:5-9).
- Why this matters: missing/ambiguous env guidance causes late failures in parallel deploys or D1 indexing, and inconsistent token naming increases the chance operators set one variable while a task expects another.
- Recommended fix:
- Add a single “Cloudflare auth and secrets” section to
.docs/cloudflare-deployment.mdcoveringCF_API_TOKEN,CLOUDFLARE_API_TOKEN=$CF_API_TOKEN,CF_ACCOUNT_ID, Pages secrets viawrangler pages secret put, and least-privilege scopes. - Either teach
cf:deploy:preflightto acceptCF_API_TOKENby exportingCLOUDFLARE_API_TOKENwhen absent, or document that this repo’s deploy tasks require theCLOUDFLARE_API_TOKENalias specifically. - Add D1-specific scope/account guidance near
mise run cf:index:search.
- Add a single “Cloudflare auth and secrets” section to
5. Verification coverage is not explicit enough for the full Cloudflare surface#
- Severity: Low
- Evidence:
cf:buildruns all app builds and thencheck:links:prod, but that link task covers onlywww,docs, andacademy(.mise.toml:1396-1402,.mise.toml:1344-1361).- Per-app release tasks for
blog,manager,design-system, andui-librarybuild and deploy without link checks (.mise.toml:1581-1641). docs/performance-smoke-checks.mddocuments local performance smoke checks forwww,docs, andblogonly, plus rootpnpm perf:*scripts (docs/performance-smoke-checks.md:10-38,package.json:30-32).- Recent Cloudflare performance docs recommend per-app build evidence, route/cache smoke checks, and artifact budgets, but the deployment doc does not provide a current verification matrix.
- Why this matters: operators can overstate “Cloudflare is green” from checks that do not cover every deployed app or from local smoke checks that do not prove deployed routes.
- Recommended fix: add a verification matrix to
.docs/cloudflare-deployment.mdthat separates:- build proof (
mise run cf:build:*), - deploy proof (
mise run cf:deploy:*), - post-deploy HTTP route proof (
mise run cf:health, after fixing canonical URLs), - link checks for apps with specs,
- artifact budgets (
pnpm perf:cf-budgets/pnpm perf:check), and - local-only performance smoke checks.
- build proof (
Changes applied in this review#
No existing deployment tasks or docs were edited. The findings above require operator decisions about canonical hostnames, DNS ownership, and academy cache behavior, so this review records recommended fixes rather than guessing.