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)
- Link-validation integration (registry validation + full Playwright E2E suite)
- External evidence-link monitoring (scheduled/manual, non-blocking)
- 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) | bryce.seefieldt.ca | 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@903f9c1a6ebcba6cf41d87230be49611ac97822ewith:version: '10.0.0' -
Setup Node
uses: actions/setup-node@v6with: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 unit suite execution (
pnpm test:unit) - Fails if unit tests fail
- Vitest unit suite execution (
-
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@v7with:name: coverage-reportpath: 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 quality, test, and link-validation jobs to pass
Conditional: if: always() && needs.quality.result == 'success' && needs.test.result == 'success' && needs.link-validation.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
5. Link-Validation Job
Purpose: Validate registry integrity and run deterministic Playwright E2E coverage as a dedicated gate.
Runs on: ubuntu-latest
Timeout: 15 minutes
Permissions: contents: read
Dependencies: Requires quality job to pass
Key steps:
pnpm install --frozen-lockfilepnpm registry:validate- Install Playwright browsers
- Start dev server + wait-on readiness
pnpm links:check(maps to full Playwright E2E suite)
Outcome: Fails if registry validation or Playwright E2E checks fail.
6. External Link Monitor Workflow (separate, non-blocking)
Workflow: external-link-monitor
Job: check-external-evidence-links
Triggers:
- Daily schedule (
20 9 * * *UTC) - Manual dispatch (
workflow_dispatch)
Command:
pnpm links:check:external
Design intent: monitor live external URL reachability without adding third-party uptime dependencies to required PR merge checks.
Build Blocking & Merge Gates
GitHub Ruleset Configuration
Branch: main
Required Status Checks (must pass before merge):
- ci / quality
- ci / test
- ci / link-validation
- ci / build
Note: external-link-monitor is intentionally non-blocking and not listed as a required PR merge check.
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://your-docs-domain.example
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.seefieldt.ca
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
Dependabot PR remediation boundaries
Dependabot automation currently auto-formats PRs, but only for formatting drift. Maintainer intervention is still required when a Dependabot PR fails on:
typechecklinttestbuildlink-validation
First-responder workflow:
- identify failing check and step from GitHub Actions logs
- checkout the Dependabot PR branch locally
- reproduce with repo verification command (
pnpm verify) - apply minimal fix and push back to the PR branch
Use Dependabot PR CI Remediation for full command-level procedure.
Known failure patterns (dependency upgrades)
- TypeScript major updates can fail on deprecated tsconfig options (for example
TS5101around deprecatedbaseUrlusage). - Lockfile formatting is usually auto-healed for Dependabot PRs, but configuration and type-system failures are not.
- Re-running CI without a code/config fix is only appropriate for transient infrastructure flakes.
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
External Link Monitor Failures
Because this workflow is non-blocking, failures should be triaged operationally:
- Re-run once to rule out transient outages.
- Validate failed URLs manually.
- Update registry evidence URLs when targets move.
- Track persistent upstream outages in issue/runbook workflow.
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/10-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