a2acf88a57
## Summary Adds review apps for the marketing site. Every PR that touches `packages/twenty-website/**` or `packages/twenty-shared/**` gets a per-version Worker preview URL, sticky-commented on the PR, auto-cleaned up when the PR closes. Same Cloudflare machinery skew protection rides on, just used for previews — no extra plan, no extra services. Cleaner than the GitHub-Actions-runner + Cloudflare-tunnel pattern: previews persist for the life of the version, accessible from anywhere, no warm-up. ## Files - **`.github/workflows/website-pr-preview.yaml`** — on PR open/sync/reopen: builds the Worker with a per-PR `DEPLOYMENT_ID`, runs `wrangler versions upload --tag pr-<N>` (no production traffic), sticky-comments the preview URL. Skipped on fork PRs because GitHub doesn't pass secrets to forks anyway. - **`.github/workflows/website-pr-preview-cleanup.yaml`** — on PR close: walks the Worker version list via the CF API, deletes anything tagged `pr-<N>` (with message-based fallback if the annotation key changes), updates the sticky comment. - **`open-next.config.ts`** — `maxNumberOfVersions: 10 → 50` to leave room for PR previews on top of skew protection's prod-version retention. ## How it looks on a PR The bot leaves a sticky comment like: > 🔍 **Website preview** is up at **https://abc12345-twenty-website-dev.twentyhq.workers.dev** > > | | | > |---|---| > | Version | `abc12345-...` | > | Commit | `<sha>` | > | Bindings | shared with the `dev` Worker (R2 cache + secrets) | > > Updates on every push. Auto-deleted when the PR closes. On close it becomes: > 🧹 Website preview for this PR was cleaned up after close. ## Twenty repo credentials already provisioned - `secret CLOUDFLARE_API_TOKEN` — same scoped token the `twenty-infra` workflow uses - `var CLOUDFLARE_ACCOUNT_ID` = `67b2bbe4381006564d2b0aa6ce6177be` - `var CF_PREVIEW_DOMAIN` = `twentyhq` (no `.workers.dev` suffix — OpenNext appends it; [opennextjs-cloudflare#811](https://github.com/opennextjs/opennextjs-cloudflare/issues/811)) ## Known limitations - **Shared dev bindings**: PR previews use the dev Worker's R2 bucket + secrets (Stripe test key, JWT private key). Fine for a read-mostly marketing site; if two simultaneous PRs ever fight over ISR cache state we can prefix R2 keys per-PR later. - **Fork PRs don't get previews**. GitHub Actions doesn't pass `secrets.*` to fork-PR runs (security), and the wrangler upload requires the CF token. To enable forks, would need to switch to `pull_request_target` and gate on a maintainer label — not done here because the security tradeoff isn't worth it for a marketing-site preview. - **Version cap**: 50 versions is the new ceiling, and `maxVersionAgeDays: 14` auto-prunes anything older. Cleanup-on-close should keep us well under in steady state. ## Test plan - [ ] CI on this PR triggers the preview workflow itself; check that the sticky comment appears with a working URL - [ ] Hit the URL, click around — should look like a fresh marketing-site build with this PR's changes - [ ] Close (don't merge) → cleanup workflow should run; sticky comment switches to the "cleaned up" message; the version is gone from `wrangler versions list --name twenty-website-dev`