Runbook: Deploy Portfolio Docs App
Purpose
Provide a deterministic, reviewable deployment procedure for the Portfolio Docs App that:
- ensures build integrity and navigation quality
- produces a validated public deployment
- includes clear rollback triggers and recovery steps
Scope
Use when
- publishing documentation changes to the public site
- releasing structural IA changes (categories, hubs, routing)
- shipping governance or operational content updates
Do not use when
- validating a local change prior to PR (use
pnpm startandpnpm buildlocally)
Prereqs / Inputs
- Required access:
- ability to open PRs and merge to
main(per branch protection rules)
- ability to open PRs and merge to
- Required tools:
pnpm,node(local validation)- Environment variables:- Local:
.env.localconfigured (see Environment Variables Contract) - Production: Variables set in Vercel dashboard- Preconditions:
- Changes are on a feature branch
- PR template completed, including “No secrets added”
- Local build gate has passed
Do not deploy changes that include secrets, internal endpoints, or sensitive logs/screenshots. If suspected, stop and treat as a security incident.
Procedure / Content
What causes a production deployment?
Production deployments to the Portfolio Docs App are triggered by:
- Merge to
main: Any PR merged to themainbranch automatically triggers a Vercel production deployment - GitHub detects push: Vercel webhook activates immediately
- Build starts: Vercel runs
pnpm install --frozen-lockfilethenpnpm build - Deployment Checks run: GitHub Actions
ci / qualityandci / buildworkflows execute - Conditional domain assignment: Vercel assigns production domain only if both checks pass
This means:
- Production deployments are automatic (not manual) once PR is merged
- Deployment creation and promotion are decoupled
- If checks fail, the deployment exists but remains unpromoted (site stays on previous version)
1) Pre-deploy validation (local)
From repository root:
# First time setup
cp .env.example .env.local
# Edit .env.local with your local values (http://localhost:3000 for development)
pnpm install
pnpm start
- Confirm sidebar/navigation is coherent.
- Confirm category landing pages behave correctly.
Then run all quality gates (required):
- Recommended:
pnpm verify - Faster iteration:
pnpm verify:quick(skips the build gate; rerun fullpnpm verifybefore merge) - Manual equivalent:
pnpm format:write # Auto-fix formatting
pnpm lint # ESLint
pnpm typecheck # TypeScript
pnpm audit --audit-level=high # Dependency vulnerability gate
pnpm format:check # Prettier
pnpm build # Docusaurus build
Expected outcome:
- All quality gates pass without errors or warnings.
- Dependency audit passes at
--audit-level=high. - Build succeeds without broken links or structural errors.
2) Open PR (required)
- Ensure PR includes:
- what changed
- why
- evidence: All quality gates passed (
pnpm verify) - security statement: “No secrets added”
- If preview deployments are available:
- validate the preview environment renders as expected.
3) Merge to main
- Merge only when all CI checks pass (
ci / qualityandci / build). - Prefer squash merge for clean history (recommended).
4) Confirm production deployment
After merge:
- Confirm production deployment completed successfully (hosting provider status UI).
- Important: Confirm both Deployment Checks are green (
ci / qualityandci / build) before considering the release complete. - Validate the site:
- home/entry docs page renders
- sidebar loads and navigation works
- key sections (Portfolio, Projects) open without errors
5) Verify build artifact and pnpm version
To ensure deterministic builds and prevent toolchain-related regressions:
Check environment variables in Vercel:
- Go to Vercel Dashboard → Settings → Environment Variables
- Confirm production variables are set for both Production and Preview scopes:
DOCUSAURUS_SITE_URLDOCUSAURUS_BASE_URLDOCUSAURUS_GITHUB_*DOCUSAURUS_PORTFOLIO_APP_URL
- See Portfolio Docs Environment Variables Contract for complete reference
Check Vercel build logs:
- Go to Vercel Dashboard → Deployments
- Open the latest deployment from
main - Click "View Build Logs"
- Confirm output shows:
Enabling Corepack...
Resolving corepack shim for pnpm@10.0.0...
pnpm 10.0.0 - Verify the pnpm version matches
package.json#packageManager
Verify build artifact correctness:
- Output directory contains
build/with expected static HTML/CSS/JS - No build errors in logs
- No warnings about missing assets or broken links (these should fail the build)
6) Validate key routes
Perform spot-check navigation on production:
- Home page (
/) loads - Portfolio section (
/docs/portfolioor equivalent) accessible - Projects dossier (
/docs/projects) accessible - Architecture domain (
/docs/architecture) with sidebar navigation works - Operations runbooks load (
/docs/operations/runbooks)
6a) Verify security headers (docs hardening)
Confirm the hosting layer is applying baseline headers from vercel.json:
curl -I https://<docs-domain>/ | grep -E "Content-Security-Policy|X-Frame-Options|X-Content-Type-Options|Referrer-Policy|Permissions-Policy|Strict-Transport-Security"
Expected outcome:
- CSP present and scoped to
self - X-Frame-Options is
DENY - HSTS is present for production domains
7) Roll forward or rollback decision
If post-deploy validation discovers issues:
Option A: Roll forward (fix-forward, if minor)
- Create a new PR with the fix
- Merge and redeploy once checks pass
- Use when: issue is isolated and quick to fix
Option B: Rollback (if major or production-impacting)
- Use the rollback runbook:
docs/50-operations/runbooks/rbk-docs-rollback.md - Revert the offending PR
- Redeploy once rollback PR merges
- Use when: site is broken, navigation corrupted, or sensitive content exposed
5) Post-deploy verification checklist
- Navigation:
- “Start here” page loads\
- category labels and ordering are correct
- Integrity:
- no broken internal links discovered during spot-check
- Governance:
- new folders include
_category_.json(where applicable) - hub pages exist for top-level domains
- new folders include
Validation / Expected outcomes
Deployment is successful when:
- production site is reachable and renders without errors
- navigation is coherent and matches the intended IA
- spot-check confirms no broken links and no sensitive content
Rollback / Recovery
Rollback trigger conditions
Rollback immediately if:
- site fails to render or navigation is broken
- critical pages are missing due to routing/base path errors
- sensitive content may have been published
Rollback procedure
- Revert the offending PR on main (see rollback runbook):
docs/50-operations/runbooks/rbk-docs-rollback.md
- Confirm redeploy occurs from updated
main. - Re-validate production site.
Common Deployment Failures
This section documents CI and Vercel-specific deployment failures and how to diagnose and recover from them.
Failure: Quality gate failures (lint, typecheck, format)
Symptom:
ci / qualitycheck fails in GitHub Actions- PR cannot merge or deployment is blocked
- Error messages in CI logs about ESLint, TypeScript, or Prettier failures
Likely cause:
- Code violates ESLint rules (unused variables, incorrect React patterns)
- TypeScript compilation errors in config or components
- Code doesn't match Prettier formatting standards
Diagnostics:
-
Check GitHub Actions logs:
- Go to PR → Checks →
ci / quality - Identify which step failed (lint, typecheck, or format:check)
- Go to PR → Checks →
-
Reproduce locally:
pnpm lint # Check ESLint
pnpm typecheck # Check TypeScript
pnpm format:check # Check Prettier
Fix:
For lint failures:
pnpm lint:fix # Auto-fix where possible
pnpm lint # Verify remaining issues
# Manually fix remaining ESLint errors
git add .
git commit -m "fix: resolve linting issues"
For typecheck failures:
pnpm typecheck # See TypeScript errors
# Fix type errors in source files
# Use @ts-expect-error with justification only for edge cases
git add .
git commit -m "fix: resolve type errors"
For format failures:
pnpm format:write # Auto-format all files
git add .
git commit -m "style: apply prettier formatting"
See Testing for quality gate details.
Failure: Output directory mismatch (404 errors or missing pages)
Symptom:
- Site deploys successfully but returns 404 for routes that exist locally
- Pages are missing or routing is broken in production
Likely cause:
- Vercel Output Directory is not set to
build/(where Docusaurus outputs) - Vercel is serving a different directory, missing the compiled site
Diagnostics:
- Verify locally:
pnpm buildproducesbuild/directory withindex.htmland assets - In Vercel Dashboard:
- Go to project settings → Build & Development
- Confirm "Output Directory" is set to
build
Fix:
Vercel Project Settings:
Build Command: pnpm build
Output Directory: build
Install Command: pnpm install --frozen-lockfile
See Vercel Configure a build for details.
See Build Determinism in the deployment dossier for more context.
Failure: pnpm lockfile drift or version mismatch
Symptom:
- Build passes locally but fails in Vercel with "dependency not found" or "version conflict" errors
- Vercel build logs show pnpm version different from expected
- Errors like: "could not resolve operator @ …" or similar lockfile-related failures
Likely cause:
pnpm-lock.yamlis out of sync withpackage.json- Local pnpm version differs from Vercel's pinned version
- Dependencies were updated locally but lockfile not committed
Diagnostics:
-
Check Vercel build logs:
- Vercel Dashboard → Deployments → failing deployment → View Build Logs
- Look for pnpm version output:
pnpm X.X.X - Compare to
package.json#packageManagerpinned version
-
Reproduce locally:
pnpm --version # Should match package.json#packageManager
pnpm install --frozen-lockfile
pnpm build
Fix:
Option A: Lockfile drift (dependencies changed)
# Locally
pnpm install
# This updates pnpm-lock.yaml to match package.json
# Verify
pnpm build # Must pass locally
# Commit and push
git add pnpm-lock.yaml package.json
git commit -m "deps: update dependencies"
git push
# Vercel redeploys with updated lockfile
Option B: Corepack/pnpm version mismatch
# Verify Corepack pin
grep packageManager package.json
# Expected: "packageManager": "pnpm@10.0.0"
# Enable Corepack locally if needed
corepack enable
corepack install
pnpm --version # Should now match
# Verify and rebuild
pnpm install --frozen-lockfile
pnpm build
See Vercel Package Managers and Build Determinism in the deployment dossier for details.
Failure: Missing build logs or build doesn't start
Symptom:
- Deployment shows no build output or minimal logs
- "Build started" but no actual build output appears
- Deployment status unclear (no error message)
Likely cause:
- Vercel "Ignored Build Step" misconfiguration
- Build preconditions violated (e.g., branch filter blocking build)
- Vercel webhook or Git integration issue
Diagnostics:
-
In Vercel Dashboard:
- Go to project settings → Git
- Confirm "Production Branch" is
main - Check for "Ignored Build Steps" (should be empty)
-
In Vercel Dashboard → Deployments:
- Click the deployment
- Look for build status and any error messages
Fix:
- Do not use Ignored Build Steps for this repository initially
- Keep the build pipeline transparent and predictable
- If build doesn't start:
- Verify branch name and protection rules
- Confirm Vercel webhook is active in GitHub settings
- Redeploy manually from Vercel Dashboard as temporary recovery
- Create a runbook/postmortem if issue repeats
See Vercel Troubleshooting Build Errors for more details.
Failure modes / Troubleshooting
- Build passes locally but fails in CI:
- verify toolchain versions; rerun
pnpm installcleanly; confirm lockfile integrity
- verify toolchain versions; rerun
- Broken links introduced:
- remove premature links; replace with plain-text path references until targets exist
- Routing/base path mismatch:
- treat as breaking change; rollback; record an ADR if changing routing is required
References
- Portfolio Docs App deployment model:
docs/60-projects/portfolio-docs-app/deployment.md - Hosting ADR:
docs/10-architecture/adr/adr-0003-hosting-vercel-with-preview-deployments.md - Rollback runbook:
docs/50-operations/runbooks/rbk-docs-rollback.md - Broken link triage runbook:
docs/50-operations/runbooks/rbk-docs-broken-links-triage.md