b768441c13aed1c978522f59d2cc326f3bd5a708
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
00fad657f4 |
feat(website): enable OpenNext skew protection + tune CF cache (#20760)
## Summary
The original goal of this whole migration: **cross-deployment skew is
now handled by OpenNext's per-version routing instead of by users having
to refresh.**
A client holding a stale tab from deployment X requests assets with
`?dpl=X` — the Worker compares X to the current `DEPLOYMENT_ID`, looks
it up in `CF_DEPLOYMENT_MAPPING`, and routes to the matching old Worker
version via its per-version preview URL
(`<old-version>-twenty-website-<env>.twentyhq.workers.dev`). The old
version serves the old assets / RSC payloads / Server Actions
consistently.
**Verified end-to-end on dev**:
| | Marker in HTML |
|---|---|
| Current Worker (`twenty-main.com/`) | `9npeiytir8EPOtW71cqDZ` |
| Stale request (`twenty-main.com/?dpl=<previous-deploy-id>`) |
`B9OC_TNl1vaGcJ5oUUty6` |
| Direct hit on old preview URL | `B9OC_TNl1vaGcJ5oUUty6` ← matches the
skew-routed response |
## Changes
**`open-next.config.ts`** — enable skew protection
```ts
const baseConfig = defineCloudflareConfig({ incrementalCache: r2IncrementalCache });
export default {
...baseConfig,
cloudflare: {
...baseConfig.cloudflare,
skewProtection: {
enabled: true,
maxNumberOfVersions: 10,
maxVersionAgeDays: 14,
},
},
};
```
(`defineCloudflareConfig` doesn't accept `skewProtection` directly — has
to be merged in)
**`next.config.ts`** — `deploymentId: process.env.DEPLOYMENT_ID`. CI
sets `DEPLOYMENT_ID` per-build; Next bakes it into prerendered HTML,
`?dpl=…` on asset URLs, Server Actions, and RSC fetch headers.
**`wrangler.jsonc`**:
- `compatibility_date: 2026-04-15` (was `2025-01-15`; build was warning)
- `assets.run_worker_first: true` — Worker must intercept asset requests
so the skew handler can route stale `/_next/static/*` to the old
version. CF edge cache absorbs hot paths so this isn't a 5×
billable-invocation tax
- `preview_urls: true` — required; skew routes via the per-version
preview URL which only exists when previews are enabled
- Per-env `services: [{ binding: WORKER_SELF_REFERENCE, service:
twenty-website-<env> }]` — OpenNext's recommended setup for
fire-and-forget ISR revalidation
- Per-env `vars`: `CF_WORKER_NAME` + `CF_PREVIEW_DOMAIN` (bare
`twentyhq`, *not* `twentyhq.workers.dev` — OpenNext appends
`.workers.dev` itself, see
[opennextjs-cloudflare#811](https://github.com/opennextjs/opennextjs-cloudflare/issues/811))
- Kept `global_fetch_strictly_public` in compat flags — without it, CF's
optimised intra-account routing self-loops the cross-version fetch and
522s out. With it, the fetch takes the public-Internet path which routes
correctly.
**`public/_headers`** — deleted (with `run_worker_first: true` the
assets pipeline doesn't process it; Next sets the same `Cache-Control:
immutable` on `/_next/static/*` anyway).
## Companion infra PR
https://github.com/twentyhq/twenty-infra/pull/__ — wires the four CF env
vars (`DEPLOYMENT_ID`, `CF_WORKER_NAME`, `CF_PREVIEW_DOMAIN`,
`CF_ACCOUNT_ID`, `CF_WORKERS_SCRIPTS_API_TOKEN`) into the deploy
workflow.
## Known limitation
Skew routing only works for Worker versions deployed AFTER this PR
(older versions don't have `preview_urls: true` and don't have
`DEPLOYMENT_ID` bindings OpenNext can read). Users on tabs older than
the first post-merge deploy still fall through to the current Worker
(same behaviour as today).
OpenNext marks `skewProtection` as **experimental** in their type docs
("might break on minor releases") — worth keeping an eye on.
|
||
|
|
f630ce34fe |
feat(website): mirror prod hostname pattern on dev (apex + www) (#20753)
## Summary Drops the `website.` subdomain on dev entirely and serves the marketing site from the bare zone + `www`, mirroring how prod is served at `twenty.com` + `www.twenty.com`. Also fixes a latent root-path substitution bug in the existing www→apex redirect that was masked on prod by a CF-level redirect. ## What changes - `wrangler.jsonc` env.dev routes: `twenty-main.com` (apex) + `www.twenty-main.com` (was `website.twenty-main.com`) - `next.config.ts`: extends host-based www→apex redirect to also cover `www.twenty-main.com`, and adds explicit `source: '/'` rules for both prod + dev before the catch-all `source: '/:path*'` (the `:path*` parameter doesn't substitute properly when it matches the empty root path against an absolute destination URL — Next.js leaves the literal `:path*` in the `Location` header) ## Live verification (after redeploy) | URL | Status | Notes | |---|---|---| | `https://twenty-main.com/` | 200 | `x-opennext: 1`, `x-nextjs-cache: HIT` | | `https://twenty-main.com/pricing` | 200 | Worker SSR | | `https://www.twenty-main.com/` | 308 → `https://twenty-main.com/` | Root-redirect fix applied | | `https://www.twenty-main.com/pricing` | 308 → `https://twenty-main.com/pricing` | Path preserved | | `https://twenty.com/` | 200 | Unchanged | | `https://www.twenty.com/` | 301 → `https://twenty.com/` | Still routed via CF-level redirect, now also covered by the new explicit Next rule as a defense-in-depth | | `https://website.twenty-main.com/` | 503 | DNS record removed by wrangler when route was deleted; hostname effectively retired | ## Companion infra PR https://github.com/twentyhq/twenty-infra/pull/__ — `cloudflare/website/dev.env` + `docs/4-environments.md` updated to the new URL; also bundles the CI fix that should have landed in #683 (was pushed too late). |
||
|
|
d17393e91d |
feat(website): migrate dev hostname website-new.twenty-main.com → website.twenty-main.com (#20747)
## Summary Last "-new" trace in the source repo, follow-up to the rename in #20745. The dev Worker custom domain swaps from `website-new.twenty-main.com` to `website.twenty-main.com`, matching the prod pattern (no "-new" anywhere). ## Live operations already performed - Deleted the legacy CNAME at `website.twenty-main.com` that pointed at the dev EKS NLB (record id `52b4a4174dfd382ecf38111b7f08e642`, was the Docusaurus dev deploy that had been 503'ing) - Redeployed `twenty-website-dev` Worker — Wrangler provisioned the new custom domain via the CF API - Verified `https://website.twenty-main.com/` returns 200 with `x-opennext: 1` and `x-nextjs-cache: HIT` The old hostname `website-new.twenty-main.com` is now unbound; Wrangler removed its DNS record when the route disappeared from this file. Visitors get 522, which is the desired state for a retired hostname. ## Companion infra PR https://github.com/twentyhq/twenty-infra/pull/683 — removes `charts/dev/apps/website` Helm chart (the legacy Docusaurus deploy) + ArgoCD app, updates `cloudflare/website/dev.env` and `docs/4-environments.md`. ## Out of scope - Legacy `website.twenty-staging.com` and `website.twenty.com` are still alive serving Docusaurus content. Decommissioning those is a separate decision (those URLs may still be linked externally). |
||
|
|
658bdf3e57 |
chore(website): rename twenty-website-new → twenty-website (#20745)
## Summary Follow-up to the Cloudflare/OpenNext migration (#20741). Now that the legacy `twenty-website` package was already removed in #20270, the `-new` suffix on the marketing site package is no longer meaningful. ## What changes - **Directory rename**: `git mv packages/twenty-website-new packages/twenty-website` (1213 files moved, no content change) - **Package + nx config**: `package.json` and `project.json` name fields updated, `sourceRoot` repointed - **Source refs**: `load-local-articles.ts` and `load-local-release-notes.ts` had a hardcoded `'twenty-website-new'` segment in their monorepo-root fallback path; `app/[locale]/releases/page.tsx` had display strings showing where to add content - **External refs**: root `package.json` workspaces, root `CLAUDE.md` / `README.md`, `twenty-sdk` + `create-twenty-app` READMEs, `.vscode/twenty.code-workspace`, `.cursor/rules/changelog-process.mdc`, Crowdin config + the three `website-i18n-*` CI workflows + `ci-website.yaml` - **Docker cleanup**: `packages/twenty-docker/twenty-website-new/Dockerfile` deleted; the two Makefile targets (`prod-website-new-build` / `prod-website-new-run`) that referenced it removed — EKS deploy was retired in the Cloudflare migration - **`yarn.lock`** regenerated against the new workspace path ## What's deliberately not in this PR The dev hostname `website-new.twenty-main.com` in `wrangler.jsonc` stays for now. Migrating it to `website.twenty-main.com` needs coordinated DNS deletion (current CNAME points at the legacy Docusaurus NLB and serves 503s) and removal of the matching legacy `website` Helm chart in `twenty-infra`. Flagged as a separate cleanup. Companion infra PR: https://github.com/twentyhq/twenty-infra/pull/682 (workflow paths + Terraform ECR + docs) ## Test plan - [x] `yarn install --immutable` resolves clean against the new path - [x] `npx nx typecheck twenty-website` passes - [x] `npx nx lint twenty-website` passes - [ ] CI on this PR confirms the same on a fresh checkout - [ ] After merge: trigger `Deploy Website` workflow against `environment=dev` to confirm the renamed working-directory deploys correctly |