poc-deploy
Give a pocs/ app a Cloudflare Workers preview deploy so a PR returns a testable staging URL (auth-working). Use when wiring a POC for previews, or when "build X as a poc" needs to end at a clickable l
SKILL.md.claude/skills/poc-deploy/SKILL.md
GitHubPOC preview deploy
Makes the endpoint of a POC a live, testable Cloudflare Workers preview URL — the goal of epic #265. A POC lives in pocs/<name> (safe-to-break incubator; see root CLAUDE.md). This skill gives it a deploy workflow so every PR that touches the POC deploys an isolated, auto-provisioned staging env and posts the preview URL on the PR.
For launched apps/ apps (production counterpart, two-domain deploy) use the /deploy skill instead — this one is the lighter, staging-only POC path.
How it works
PR touches pocs/<name>/** (POC has a deploy.config.json) → deploy-pocs.yml (generic; detects
the changed/dispatched opted-in POCs) → deploy-app.yml (reusable, workspace: pocs, enable-review: true)
→ build (cloudflare_module, NUXT_PUBLIC_CROUTON_REVIEW=true) → wrangler deploy --env staging
→ auto-provision id-less D1/KV → sync review bridge secrets → sync ids → remote D1 migrate
→ sticky PR comment: 🚀 <name> staging deployed: <url> + overlay usage instructions
Review overlay is ON by default for all POC staging deploys (#596).
deploy-pocs.ymlpassesenable-review: truetodeploy-app.yml, so every POC preview is built withNUXT_PUBLIC_CROUTON_REVIEW=true(the@fyit/crouton-devtoolsoverlay + source stamper +/api/_feedbackbridge). The PR comment includes overlay usage instructions. For the bridge to post🎯 Preview feedbackcomments, set theNUXT_CROUTON_REVIEW_GITHUB_APP_*repo-level secrets (seewriteups/setup/review-bridge-token-setup.md); the overlay still renders without them.
One generic workflow, no per-POC file (#481). There is a single committed
.github/workflows/deploy-pocs.yml; a POC opts in withpocs/<name>/deploy.config.json(which the agent pipeline can push — it's underpocs/, not.github/workflows/, which needs theworkflowsscope the bot lacks). Do not generate a per-POCdeploy-<name>.yml.
- The reusable
deploy-app.ymltakes aworkspaceinput (appsdefault, orpocs) — that's the only thing that lets apocs/app reuse the same pipeline asapps/. - The preview is stable at
https://<name>.pmcp.dev(the #133 staging domain), soBETTER_AUTH_URLis predictable and auth works on the preview.
Wire a POC for previews
- Scaffold the POC first (it must exist at
pocs/<name>with awrangler.jsoncthat has anenv.stagingblock: id-less<name>-staging-db+ route<name>.pmcp.dev, andcf:stagingin itspackage.json— the app scaffold produces these, mirroringapps/velo).Add
cf:versionalongsidecf:staging(#1836). Themode: versiondispatch — immutable side-by-side previews — runs the POC's owncf:version, and nothing generates it: a POC wired for deploy but missing it fails the dispatch. Copy the POC's owncf:stagingand swapwrangler deployforwrangler versions upload, dropping the id-sync and migrate steps (a version upload activates nothing, so there's no DB to migrate). Mirror that POC's script, not a template —loop-station, for one, prepares data first and skipsinject-wrangler-env.deploy-pocs.ymlnow fails fast and tells you if it's missing. - Generate + commit the initial D1 migrations. Collections are not migrated by
crouton config/crouton init, so a fresh POC has none — and the deploy's remote-migrate step then fails with "No migrations present". Use thedb-migrationsbuild-first workaround:NITRO_PRESET=node-server nuxt builduntil.nuxt/hub/db/schema.mjsappears →pnpm db:generate→ commitpocs/<name>/server/db/migrations/sqlite/**. (Don't skip this — it's the step that bit library-catalog, #457.) - Opt the POC in — config only, NO workflow file:
It writespnpm poc:scaffold-deploy <name> # → pocs/<name>/deploy.config.json (NOT a workflow file)pocs/<name>/deploy.config.json({ stagingUrl, layerPackages }), read by the shareddeploy-pocs.yml. - Open a PR touching
pocs/<name>/**(e.g. thedeploy.config.json+ migrations).deploy-pocs.yml— which must be on the PR's base branch (an epic branch must carry it; see #481) — auto-fires → CI deploys the staging Worker and posts the preview URL. First deploy auto-provisions D1/KV. (workflow_dispatch(app=<name>)also works if the token hasactionsscope.)
Auth on a fresh preview (so it's testable)
A freshly deployed Worker has no users. To make the preview testable with auth, the POC's seed script provisions a known admin against the remote D1 (run it post-deploy, or have CI do it), and the admin creds are handed back alongside the URL. (Self-registration on the preview also works if the POC enables it.) See the per-app seed/shots scripts.
Requirements / gotchas
- CI-only: real Cloudflare deploys run in GitHub Actions — the
CLOUDFLARE_ACCOUNT_ID+CLOUDFLARE_API_TOKENrepo secrets must exist (same as theapps/deploys), and the token needs account Workers/D1/KV and zone Workers-Routes/DNS edit for the<name>.pmcp.devcustom domain. There are no CF creds in the dev sandbox; you cannot produce the URL locally — open the PR and let CI do it, then babysit to green. - Staging only. No production block — pocs are previews. Promote
pocs/<name>→apps/<name>and use/deployfor production. - Worker secrets (e.g.
BETTER_AUTH_SECRET) persist across deploys; set them once viaWORKER_SECRETS_JSON(an Environment secret) orwrangler secret bulk --env staging. - The POC opts in via
pocs/<name>/deploy.config.json(re-runpnpm poc:scaffold-deploy <name>to refresh it). The genericdeploy-pocs.ymlis shared — never add a per-POC workflow file. For apull_requestdeploy to fire, that workflow must be present on the PR's base branch (cut/refresh epic branches from currentmainso they carry it — #500/WS3). - Migrations must be committed (
pocs/<name>/server/db/migrations/sqlite/**) before the deploy, or the remote-migrate step fails — see step 2.