Skip to content

Step 8 — Deploy on Vercel (Git integration) #10

Description

@nficano

Summary

Stand up production and preview hosting for the new Astro + Markdoc site repo on Vercel using native Vercel Git integration (push to main → production, PRs → preview), and retire the old, currently-broken GH-Actions + Vercel-CLI-prebuilt deploy. This delivers a working preview/production pipeline with zero custom deploy workflow, zero VERCEL_TOKEN, and none of the old native-dependency / Node-version baggage.

Why / context

The old www site deploys through .github/workflows/deploy.yml, which runs vercel pull / vercel build / vercel deploy --prebuilt against a VERCEL_TOKEN that is now expired — the deploy is broken. That pipeline also drags along native deps (better-sqlite3, @resvg/resvg-js, satori), a FontAwesome-Pro private-registry npm token, and a Node 22-in-CI vs 24-on-Vercel skew. The Astro rebuild (output: 'static', no SQLite content index, FontAwesome dropped) lets us replace all of that with Vercel's first-party Git integration: no token to rotate, no prebuilt dance, no GH-Actions deploy job. Big-picture spec: /Users/nficano/code/arpc/site/docs/markdoc-migration.md (this is "Step 8").

Reference files (read these first)

  • /Users/nficano/code/arpc/www/.github/workflows/deploy.yml — the OLD deploy. Do NOT port it. It encodes everything we're removing: VERCEL_ORG_ID/VERCEL_PROJECT_ID/VERCEL_TOKEN secrets, the vercel pullvercel buildvercel deploy --prebuilt flow, --prod only on refs/heads/main, plus build-time secrets GITHUB_TOKEN and FONTAWESOME_NPM_AUTH_TOKEN, and SDK_DOCS_REMOTE: '1'. Use it only to understand prod-vs-preview branch logic and to confirm which env vars carry over (only SDK_DOCS_REMOTE, and optionally GITHUB_TOKEN — see gotchas).
  • /Users/nficano/code/arpc/www/vercel.json — old project-level build config: "framework": null, "installCommand": "pnpm install --frozen-lockfile", "buildCommand": "pnpm sync:docs && nuxt generate", "outputDirectory": ".output/public". Copy the install command verbatim; change the build command to pnpm sync:docs && astro build and the output dir to dist; drop "framework": null (let Vercel auto-detect Astro, or set "framework": "astro").
  • /Users/nficano/code/arpc/www/.vercel/project.json — old linked project: projectName: "arcp-www", framework: "nuxtjs", nodeVersion: "24.x", orgId: team_TJzllI1zwt8dXpGGYOKSNytD. We create a new project arcp-site in the same org/team (team_TJzllI1zwt8dXpGGYOKSNytD). Do not reuse projectId prj_1KQq08x5SIPFHfIur4ysg1Db2Qat. Note the Node skew here: 24.x on Vercel vs node-version: 22 in CI — we standardize on Node 22.
  • /Users/nficano/code/arpc/www/package.json — shows the native-dep footprint to be gone in site: better-sqlite3, @resvg/resvg-js, satori, all @fortawesome/*, @nuxt/*, and the pnpm.onlyBuiltDependencies allowlist (@parcel/watcher, better-sqlite3, esbuild, vue-demi). The sync:docs script entry (node scripts/sync-docs.mjs) is the one piece that carries over (ported in Step 4).
  • /Users/nficano/code/arpc/www/.npmrc — the FontAwesome private-registry config: @fortawesome:registry=https://npm.fontawesome.com/ + //npm.fontawesome.com/:_authToken=${FONTAWESOME_NPM_AUTH_TOKEN}. This entire file must NOT be carried into site (we drop FontAwesome per the hard constraints), which also eliminates the FONTAWESOME_NPM_AUTH_TOKEN secret.
  • Discovered while reading: /Users/nficano/code/arpc/www/scripts/sync-docs.mjs reads process.env["SDK_DOCS_REMOTE"] (L14) and process.env["GITHUB_TOKEN"] || process.env["GH_TOKEN"] (L16-17); in remote mode it hits https://api.github.com/repos/${ORG}/${repo}/... and sends Authorization: Bearer <token> only if a token is present (L351). /Users/nficano/code/arpc/www/server/middleware/lowercase-redirect.ts is the source for the lowercase-redirect rules that, for a static build, must move into vercel.json redirects or Astro middleware (Step 7 owns the logic; this ticket just hosts the result).

Tasks

  • Confirm prerequisites are merged in site: an Astro project that builds locally with pnpm build (pnpm sync:docs && astro build) producing output in dist/ (Step 0 scaffold), and scripts/sync-docs.mjs present (Step 4). If pnpm build does not yet pass locally, stop and flag the blocking step rather than configuring deploy around a broken build.
  • Create site/vercel.json with: "$schema": "https://openapi.vercel.sh/vercel.json", "installCommand": "pnpm install --frozen-lockfile", "buildCommand": "pnpm sync:docs && astro build", "outputDirectory": "dist". Either omit framework (Astro auto-detected) or set "framework": "astro". Do not set "framework": null (that was a Nuxt workaround).
  • If Step 7's lowercase-redirect was implemented as Vercel redirects, add the "redirects" array to this same vercel.json (preserving the skip rules for /_, /__, /api, and static assets from lowercase-redirect.ts). If Step 7 used Astro middleware instead, leave redirects out of vercel.json and note it.
  • Pin Node to 22 for parity with the local/Astro toolchain and to kill the old 22-vs-24 skew. Prefer an .nvmrc/"engines" in package.json ("node": "22.x") and/or the Vercel project Node setting; do not carry over nodeVersion: "24.x".
  • Ensure site has a committed pnpm-lock.yaml (required by --frozen-lockfile) and that packageManager / pnpm 10 is declared so Vercel selects the right pnpm.
  • Verify site/.npmrc does not contain the FontAwesome registry lines. If a .npmrc exists at all, it must have no reference to npm.fontawesome.com or FONTAWESOME_NPM_AUTH_TOKEN.
  • Confirm no native build deps remain: there should be no better-sqlite3, @resvg/resvg-js (unless deliberately kept for the OG endpoint in Step 6 — if so, add it to pnpm's built-deps allowlist), satori (same caveat), or @fortawesome/* in site/package.json. Drop the old pnpm.onlyBuiltDependencies entries that no longer apply (@parcel/watcher, better-sqlite3, vue-demi); keep only what the Astro build actually needs (likely just esbuild, if anything).
  • In the Vercel dashboard (org/team team_TJzllI1zwt8dXpGGYOKSNytD), create a new project named arcp-site and connect it to the agentruntimecontrolprotocol/site GitHub repo via Git integration (NOT the CLI prebuilt flow).
  • In the new project's settings, confirm Vercel picked up the framework as Astro and that Build & Output settings match vercel.json (pnpm install --frozen-lockfile, pnpm sync:docs && astro build, output dist). Set Production Branch = main.
  • Add the only required env var: SDK_DOCS_REMOTE=1 (scope: Production + Preview; this makes sync-docs.mjs pull SDK/spec docs from the GitHub API at build time instead of from sibling checkouts). Do not add VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID, or FONTAWESOME_NPM_AUTH_TOKEN.
  • Decide on GITHUB_TOKEN: sync-docs.mjs works unauthenticated (token is optional, L16-17/L351), but unauthenticated GitHub API calls are rate-limited (~60/hr) and the script fetches many trees/blobs. If builds hit 403/rate-limit, add a GITHUB_TOKEN (read-only / public-repo scope) env var in Vercel. Document whichever choice is made.
  • Trigger the first deploy by pushing a branch and opening a PR; confirm a preview deployment builds and succeeds. Then merge to main and confirm a production deployment.
  • Delete the old deploy machinery from site so nothing competes with Git integration: ensure there is no .github/workflows/deploy.yml and no .vercel/ directory committed in site (.vercel should be gitignored).
  • Keep the production domain agentruntimecontrolprotocol.io pointed at the existing arcp-www project for now. Do not repoint DNS in this ticket — that is the Step 9 cutover after parity is verified. Record the auto-assigned arcp-site.vercel.app (or preview) URL for the Step 9 audit.
  • Add/append to MIGRATION.md noting what changed: Git integration replaces GH-Actions, VERCEL_TOKEN removed, FontAwesome + its npm token dropped, SQLite/native OG deps removed, Node pinned to 22, only carryover env is SDK_DOCS_REMOTE (+ optional GITHUB_TOKEN).

Details & gotchas

  • The old deploy is genuinely broken, not flaky. VERCEL_TOKEN is expired, so any attempt to "fix" the GH-Actions workflow is wasted effort — the whole prebuilt-CLI approach is being deleted, not repaired.
  • Output directory changes Nuxt → Astro: old outputDirectory was .output/public (Nuxt nuxt generate); Astro static output is dist. Pointing Vercel at the wrong dir is the most likely first-deploy failure.
  • framework field: the old vercel.json set "framework": null and .vercel/project.json said "framework": "nuxtjs". Neither is correct here — use Astro detection or "framework": "astro". A stale nuxtjs/null framework can break asset routing.
  • Node skew is real: old Vercel ran nodeVersion: "24.x" while CI used node-version: 22. Standardize on 22 (matches the spec's "Node 22+, pnpm 10").
  • --frozen-lockfile requires a committed lockfile. installCommand: "pnpm install --frozen-lockfile" will fail the build if pnpm-lock.yaml is missing or out of sync — regenerate and commit it before the first deploy.
  • FontAwesome token elimination: the old .npmrc pins @fortawesome:registry=https://npm.fontawesome.com/ with _authToken=${FONTAWESOME_NPM_AUTH_TOKEN}. If any @fortawesome/* dep sneaks into site, pnpm install --frozen-lockfile will try to hit that private registry and fail without the token — which is exactly why the dependency (and the .npmrc) must be absent.
  • SDK_DOCS_REMOTE is load-bearing for CI builds. On Vercel there are no sibling repo checkouts, so sync-docs.mjs must run in remote mode (SDK_DOCS_REMOTE=1) to fetch docs via https://api.github.com. Without it, sync:docs produces an empty/partial docs tree and most routes 404.
  • GITHUB_TOKEN is optional but rate-limit-sensitive. Per L16-17/L351, the token is only attached if present; unauthenticated builds risk GitHub's ~60 req/hr cap given the recursive tree + per-blob fetches. Note that in GH-Actions this came for free via the workflow's secrets.GITHUB_TOKEN; under Vercel Git integration you must supply it explicitly if needed.
  • Don't commit .vercel/. The old repo had .vercel/project.json because it linked via CLI. Git integration manages the link server-side; a committed .vercel/project.json (with the old arcp-www IDs) would mislink the project.
  • Lowercase redirects: lowercase-redirect.ts was Nuxt server middleware (301 miscased doc URLs → lowercase canonical, skipping /_, /__, /api, static assets). With output: 'static' there is no server middleware at runtime, so these must live in vercel.json "redirects" (or Astro middleware). This ticket only needs to host the artifact Step 7 produces — coordinate, don't reinvent the rule set.

Acceptance criteria

  • A new Vercel project arcp-site exists in team team_TJzllI1zwt8dXpGGYOKSNytD, connected to agentruntimecontrolprotocol/site via Git integration (no CLI/prebuilt).
  • Pushing to main produces a production deploy; opening a PR produces a preview deploy — both green.
  • The Vercel build runs pnpm install --frozen-lockfile then pnpm sync:docs && astro build, publishes dist/, and the deployed preview serves real docs content (synced pages resolve, not 404s), confirming SDK_DOCS_REMOTE=1 took effect.
  • No VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID, or FONTAWESOME_NPM_AUTH_TOKEN is referenced anywhere in site (no deploy workflow, no .npmrc FontAwesome lines).
  • site contains no .github/workflows/deploy.yml and no committed .vercel/ directory; .vercel is gitignored.
  • Node is pinned to 22 for the Vercel build; no 24.x setting carried over.
  • agentruntimecontrolprotocol.io still resolves to the old arcp-www project (DNS untouched); the new deploy is reachable only at its Vercel-assigned URL, which is recorded for Step 9.
  • MIGRATION.md documents the deploy changes (Git integration, dropped token/FontAwesome/SQLite/native-OG deps, Node 22, env vars).

Dependencies & out of scope

  • Depends on: Step 0 (Astro scaffold that builds with pnpm builddist/) and Step 4 (the ported scripts/sync-docs.mjs + sync:docs script that this build invokes). Benefits from Step 7 (lowercase-redirect + sitemap) if its redirects are expressed in vercel.json, but this ticket only hosts that output.
  • Out of scope: the production DNS cutover / repointing agentruntimecontrolprotocol.io and archiving wwwwww-legacy (Step 9 cutover after parity); the regression audit itself (audit-http.mjs / audit-site.mjs, Step 9); the OG-image endpoint implementation (Step 6); design-system, routing, and content-collection work (Steps 1–7). This ticket establishes hosting and the preview pipeline only — it does not gate cutover on visual parity.

Part of #1 · Full spec: docs/markdoc-migration.md

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    deployVercel deploymentinfraBuild, sync, deploy infrastructuremigrationNuxt → Astro+Markdoc migration

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions