CI/CD Pipeline Overview
Purpose
Document the CI/CD pipeline architecture, job dependencies, test integration, and quality gates that ensure code quality before production deployment.
Scope
- GitHub Actions workflow design
- Job sequence and dependencies
- Quality gates (lint, format, typecheck, tests)
- Test job integration (unit + E2E)
- Coverage reporting and artifacts
- Build promotion and deployment
Workflow Overview
The Portfolio App CI/CD pipeline enforces quality gates via GitHub Actions before build and deployment, with a three-tier environment strategy (Preview → Staging → Production).
Environment Tiers
| Environment | Branch | Deployment Trigger | Domain | Purpose |
|---|---|---|---|---|
| Preview | PR branches | Auto on PR creation | *.vercel.app (auto-generated) | Feature validation and PR review |
| Staging | staging | Manual (merge main) | staging-bns-portfolio.vercel.app | Pre-production validation |
| Production | main | Auto (after CI passes) | bns-portfolio.vercel.app | Live public site |
Deployment flow: PR → Preview (auto) → Merge to main → CI runs → Production (auto) → Staging (manual) → Production validated
Job Sequence
Job Execution Details
1. Quality Job
Purpose: Enforce code quality standards (lint, format, type safety)
Runs on: ubuntu-latest (GitHub-hosted runner)
Timeout: 10 minutes
Permissions: contents: write (for Dependabot auto-format), pull-requests: read
Steps:
-
Checkout code
uses: actions/checkout@v6 -
Setup pnpm
uses: pnpm/action-setup@v4
with:
version: '10.0.0' -
Setup Node
uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'pnpm' -
Install dependencies (frozen)
pnpm install --frozen-lockfile -
Auto-format for Dependabot PRs (conditional)
if: ${{ github.actor == 'dependabot[bot]' }}
pnpm format:write || true
# Auto-commit if changes detected
-
Lint (fails on warnings)
pnpm lint -
Format check
pnpm format:check -
Typecheck
pnpm typecheck -
Dependency audit
pnpm audit --audit-level=high- Gate: high/critical advisories fail the job
- Visibility: lower severities are logged separately (non-blocking)
Outcome: Fails if any checks fail; blocks subsequent jobs
2. Secrets-Scan Job
Purpose: Detect accidental secrets in code and configuration
Runs on: ubuntu-latest
Timeout: 5 minutes
Permissions: contents: read
Conditional: Only runs on pull requests (avoids BASE==HEAD issue on push)
Tool: TruffleHog (hardened with --only-verified flag)
Command:
trufflesecurity/trufflehog@main \
--base=${{ github.event.repository.default_branch }} \
--head=HEAD \
--debug \
--only-verified
Outcome: Fails if verified secrets detected (blocks PR merge)
Evidence: ADR-XXXX (secrets scanning strategy)
3. Test Job
Purpose: Run unit and E2E tests before build
Runs on: ubuntu-latest
Timeout: 15 minutes
Permissions: contents: read
Dependencies: Requires quality job to pass
Conditional: if: needs.quality.result == 'success'
Steps:
-
Checkout code
-
Setup pnpm (version 10.0.0)
-
Setup Node (version 20, cache: pnpm)
-
Install dependencies (frozen)
pnpm install --frozen-lockfile -
Run unit tests
pnpm test:unit- Vitest with coverage reporting
- Coverage targets: ≥95% lines, functions, branches, statements
- Fails if coverage targets not met
-
Install Playwright browsers
npx playwright install --with-deps -
Start dev server
pnpm dev & -
Wait for server readiness
npx wait-on http://localhost:3000 -
Run E2E tests
pnpm test:e2e- Multi-browser: Chromium, Firefox
- 66 tests covering core routes, slugs, 404s, metadata endpoints, evidence links, and security APIs
- 2 retries in CI, 0 locally
- HTML report generated
-
Upload coverage reports (if always)
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
retention-days: 7
Outcome: Fails if any tests fail or coverage targets not met
4. Build Job
Purpose: Compile production bundle and deploy to Vercel
Runs on: ubuntu-latest
Timeout: 15 minutes
Permissions: contents: read
Dependencies: Requires both quality and test jobs to pass
Conditional: if: always() && needs.quality.result == 'success' && needs.test.result == 'success'
Steps:
-
Checkout code
-
Setup pnpm (version 10.0.0)
-
Setup Node (version 20, cache: pnpm)
-
Install dependencies (frozen)
pnpm install --frozen-lockfile -
Build
pnpm build- Compiles Next.js app
- Registry validation runs at build time
- Fails if any build errors occur
-
Deploy to Vercel (automatic)
- Deployment happens automatically on
mainpush - Preview deployments on PRs
- Requires Vercel GitHub App integration
- Deployment happens automatically on
Outcome: Fails if build fails; deployment blocked until all gates pass
Build Blocking & Merge Gates
GitHub Ruleset Configuration
Branch: main
Required Status Checks (must pass before merge):
- ci / quality
- ci / test
- ci / build
Dismiss Stale PR Reviews: False (reviewers' approvals invalidated by new commits)
Require Code Review: At least 1 approval required
Rationale:
- Automation gates catch regressions early
- Code review gate ensures human review
- Build blocking prevents deployment of broken code
Promotion Path
- Feature branch → Create PR targeting
main - CI runs → Quality gate runs first, test gate runs second, build gate runs last
- All gates pass → PR is ready for merge
- Code review → Human review + approval required
- Merge to main → Automatically triggers deployment via Vercel
Environment Variables & Configuration
Public Configuration (CI Environment)
Portfolio App (.github/workflows/ci.yml env section):
env:
NEXT_PUBLIC_DOCS_BASE_URL: https://bns-portfolio-docs.vercel.app
NEXT_PUBLIC_GITHUB_URL: https://github.com/bryce-seefieldt/portfolio-app
NEXT_PUBLIC_DOCS_GITHUB_URL: https://github.com/bryce-seefieldt/portfolio-docs
NEXT_PUBLIC_SITE_URL: https://bryce-portfolio-app.vercel.app
Rationale: Non-sensitive public URLs used for registry interpolation during CI builds
Secrets (GitHub)
None required for Portfolio App (all config is public)
Troubleshooting Common Failures
Quality Job Failures
ESLint violations:
pnpm lint # Run locally to see errors
pnpm lint --fix # Auto-fix where possible
Prettier format violations:
pnpm format:write # Fix formatting
TypeScript type errors:
pnpm typecheck # Run locally to debug
Dependency audit failures:
pnpm audit --audit-level=high
pnpm up --latest
Test Job Failures
Unit tests fail:
pnpm test:unit # Run locally with details
pnpm test:coverage # View coverage report
E2E tests fail:
pnpm dev # Start dev server
pnpm test:e2e:ui # Debug in interactive UI
Timeout waiting for server:
- Ensure dev server starts:
pnpm dev - Check port 3000 availability
- Increase wait-on timeout if needed
Build Job Failures
Build errors:
pnpm build # Reproduce locally
Registry validation errors:
pnpm registry:validate # Test registry schema
pnpm registry:list # List all projects
Performance Optimization
Cache Strategy
- Dependencies: Cached via
actions/setup-node@v6withcache: pnpm - Playwright browsers: Installed fresh each run (pre-cached in runner images)
- Build output: Not cached between runs (fresh build each time)
Parallelization
- Browsers: E2E tests run in parallel across Chromium and Firefox
- Workers: 1 worker in CI (sequential), unlimited locally
- Jobs: Quality → Test → Build (sequential dependencies)
Runtime
- Quality job: ~2 minutes
- Test job: ~3-5 minutes (depends on E2E test duration)
- Build job: ~2-3 minutes
- Total: ~8-10 minutes (end-to-end)
Deployment Strategy
Vercel Integration
- Auto-deploy: Enabled for
mainbranch - Preview deployments: Enabled for all PRs
- Promotion checks: Vercel checks run after GitHub checks pass
Promotion Flow
- PR created: Vercel creates preview deployment
- CI runs: All GitHub checks must pass
- Vercel checks run: Promotion to production requires passing checks
- Merge to main: Triggers production deployment to
https://bryce-portfolio-app.vercel.app
Monitoring & Observability
Workflow Runs
- GitHub Actions tab: View all workflow runs
- PR Checks: See check status in PR UI
- Commit Status: Badge in commit history
Coverage Reports
- Artifacts: Download coverage reports from workflow run
- HTML Report: Open
coverage/index.htmlto view detailed metrics - Retention: 7 days (configured in upload-artifact action)
Test Reports
- Playwright Report: Generated after E2E tests
- Command:
pnpm exec playwright show-report - Location:
.playwright/report/
Related Documentation
- Testing Guide: docs/70-reference/testing-guide.md
- Portfolio App Testing: docs/60-projects/portfolio-app/05-testing.md
- Portfolio App Architecture: docs/60-projects/portfolio-app/02-architecture.md
- Security ADRs: docs/architecture/adr/ (CI security decisions)
- CI Triage Runbook: docs/50-operations/runbooks/rbk-portfolio-ci-triage.md
Maintenance & Evolution
Adding New Checks
- Update workflow file (
.github/workflows/ci.yml) - Document in this page (CI/CD Pipeline Overview)
- Update ADR if check represents new architectural decision
- Test locally before merging
Updating Node/pnpm Versions
- Update version in
.nvmrc/package.json - Update CI workflow (
node-version,pnpmversion) - Test workflow in feature branch
- Document change in ADR or release notes
Onboarding New Team Members
- Point to this documentation for CI/CD overview
- Have them review
.github/workflows/ci.yml - Run local verification commands (
pnpm verify) - Confirm workflow passes on first PR