Skip to content

Deployment

Jaloliddin Ismailov edited this page Oct 4, 2026 · 11 revisions

The Hub deploys to Vercel with its database on Neon, and every pull request gets a live preview with its own isolated database branch. This page covers the pipeline end to end — what deploys where, what the preview actually proves, and the runbook for the things that go wrong.

The topology

flowchart TB
    subgraph GitHub
        PR[Pull request]
        Main[main branch]
    end

    subgraph CI["GitHub Actions"]
        Verify["verify.yml<br/>lint · build · tests · MCP smoke · types drift"]
        NeonPrev["neon-preview.yml<br/>branch pr-N · migrate · seed"]
    end

    subgraph Vercel
        Preview["Preview deployment<br/>per-PR URL"]
        Prod["Production<br/>youngo-hub.vercel.app"]
    end

    subgraph Neon["Neon"]
        PRBranch["pr-N branch<br/>(schema + seeded data)"]
        ProdBranch["production branch"]
    end

    PR --> Verify & NeonPrev
    NeonPrev --> PRBranch --> Preview
    Verify --> Preview
    Main --> Prod --> ProdBranch
Loading

Two things run on every PR in parallel: verify.yml proves the code (lint, build, integration tests on a Docker Postgres, the MCP handshake, a types-drift check that committed payload-types.ts matches the collections), and neon-preview.yml proves the schema against the real Neon stack — it creates a pr-<number> branch, runs npm run migrate, and hands the preview deployment its own database.

The preview contract

A preview is only as useful as its isolation, and the pipeline is built to provide it:

  • Its own Neon branch — migrations run against a copy of the schema, so a breaking migration fails in CI rather than on the shared preview.
  • EMAIL_RECIPIENT_ALLOWLIST set — preview environments can send mail, but only to a defined list, so a test notification never reaches a real member.
  • NEXT_PUBLIC_HUB_DEMO on — the UI marks the deployment as demo so nobody mistakes seeded content for real governance.
  • The branch is torn down when the PR closes (pull_request.closed → cleanup job), so previews don't leak databases.

Deploying to production

Production is the main branch on the existing Vercel youngo-hub project — do not create a second Vercel project. Migrations run as part of the deploy flow against the production Neon branch. The ordering that keeps deploys safe:

  1. Merge to main — Vercel builds and deploys.
  2. npm run migrate against the production DATABASE_URL — either via the deploy hook or manually with payload migrate pointed at production.
  3. Verify /api/ health and spot-check a real flow.

Migrations are designed to be backwards-compatible within a deploy — schema changes that would break the currently-running code should be split across deploys (expand first, contract after the code using the old shape is gone). This is the standard expand-and-contract discipline; the migration history shows it in practice.

The runbook

Preview database is stale or broken. Close and reopen the PR — the cleanup/recreate cycle gives it a fresh branch. Or neonctl branches delete pr-N and push an empty commit.

A migration failed partway. Migrations run in a transaction where possible, so a failure usually leaves the database untouched. Check payload_migrations for what applied, fix the file, re-run npm run migrate.

Notifications aren't arriving in preview. Check the outbox endpoint first — rows in queued mean the cron drain isn't firing (Vercel cron needs to be configured per environment); rows in failed carry the SMTP error.

A member lost access after deploy. Almost always a record whose ends_at passed, or a migration that changed role strings — check unmappedRecords in their access profile.

Rollback. Vercel keeps previous deployments — promote the last good one from the dashboard. If a migration already ran, roll back code first, then assess whether the migration's down() needs to run; down scripts are maintained precisely for this case.

Invariants worth restating

  • One Vercel project, one production Neon project — preview isolation is per-branch, not per-service.
  • The MCP content service deploys separately (it's a separate process, not part of the Next.js app) with its own MCP_TOKEN.
  • No deploy step prints secrets or reset URLs — PRINT_ADMIN_RESET_URLS is an emergency opt-in for bootstrap only.

Clone this wiki locally