GitHub Actions workflows, branch protection, verification jobs, and CLI release flow.
CentraKit uses a small set of focused GitHub Actions workflows.
.github/workflows/ci.yml runs on pull requests, pushes to develop and main, and manual dispatch. It calls verify.yml (affected workspaces only on pull requests), then builds and checks payload budgets. The E2E suite runs locally with pnpm test:e2e and is not part of CI..github/workflows/verify.yml is the reusable fail-fast: false matrix: format, lint, Knip, typecheck, tests, Turbo boundaries, pnpm audit:high, OpenAPI drift, and the i18n catalog test..github/workflows/database.yml runs when supabase/** changes. It starts the local stack, runs the pgTAP suite with pnpm supabase:test, and lints SQL with supabase db lint..github/workflows/release.yml runs as the last job of CI on pushes to main, after Verify and Build pass, so it does not check, build or test the same commit again. It uses Changesets to open or update the chore: version packages PR. Merging that PR tags the release, creates the GitHub Releases, and merges main back into develop..github/workflows/release-cli.yml runs for published CLI releases and manual retries to package the tarball and attach it to the GitHub release..github/workflows/react-doctor.yml runs React Doctor on pull requests and on pushes to develop and main. On a pull request it scans the changed files, posts a summary comment with the new findings, and fails on new warnings or errors (blocking: warning). Run the same scan locally with pnpm doctor..github/dependabot.yml opens one grouped weekly PR each for npm and GitHub Actions, after a two-day cooldown..github/actions/setup is the shared composite action: Turborepo Remote Cache over OIDC, then pnpm/setup for pnpm, the Node 24 runtime, the store cache, and a frozen install.TURBO_TEAM: Vercel team slug for Turborepo remote cache. Use scaledock.NEXT_PUBLIC_SITE_URL: optional CI override for Next.js env validation. Defaults to https://localhost.NEXT_PUBLIC_SUPABASE_URL: optional CI placeholder override for Next.js env validation.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: optional CI placeholder override for Next.js env validation.SENTRY_AUTH_TOKEN: optional. CI does not upload source maps or create Sentry releases; Vercel production builds do.CI uses vercel/setup-turborepo-remote-cache-action to exchange a GitHub OIDC token for a short-lived Turborepo token. That token is team-scoped and can write cache artifacts. Workflows need id-token: write.
Create the matching Vercel policy once. In the team Build and Deployment settings, open OIDC Policies for CLI Access and add a Turborepo CLI policy for ScaleDockHQ/CentraKit. Workflows do not set TURBO_TOKEN themselves, so the token from the OIDC exchange is the only one Turborepo sees. Without the policy the setup step logs Failed to exchange OIDC token and every task runs without remote cache.
gh variable set TURBO_TEAM --body "scaledock" --repo ScaleDockHQ/CentraKit
gh variable set NEXT_PUBLIC_SITE_URL --body "https://localhost" --repo ScaleDockHQ/CentraKitVercel deployments do not need TURBO_TOKEN: when builds run turbo run build (configured per service in root vercel.json), Vercel Remote Cache is authenticated automatically. Root turbo.json sets remoteCache.teamSlug / teamId for the linked centrakit project.
From the repo root (one-time per machine):
pnpm exec turbo login
pnpm exec turbo linkThis writes gitignored .turbo/config.json. After linking, local turbo run build shares artifacts with Vercel and GitHub Actions.
develop is the default branch. Commit and push to it directly; feature branches are the exception and get no Vercel preview.main moves only through the pull request from develop to main, merged whenever a release is wanted. Never commit to main.develop as preview (app.centrakit.dev, api.centrakit.dev, docs.centrakit.dev) and main as production. git.deploymentEnabled in root vercel.json denies every other branch.main maps to the production project and develop to the persistent Supabase branch. The Supabase GitHub integration applies migrations and config.toml on push; do not supabase db push from Actions.develop. The Changesets version PR targets main from changeset-release/main; vercel.json skips Vercel deployments for changeset-release/* branches.The repository plan is private without rulesets, so there is no enforced branch protection. The checks below are the ones to require on the release PR once protection is available:
FormatLintKnipTypecheckTestBoundariesAuditOpenAPI drifti18n catalogsBuildReact DoctorThe Build job also captures SaaS and CLI payload artifacts and compares deterministic SaaS build
metrics with the latest successful artifact on the base branch. Regressions emit warnings by default. Set the
PAYLOAD_COMPARE_MODE repository variable to enforce, or choose enforce for a manual workflow
run, to make budget regressions fail the job.
The Build job records shipped-cost artifacts after turbo run build, so the payload steps reuse
that build instead of compiling the SaaS app again:
pnpm --filter saas baseline:payload reads the next build output, writes
.next/diagnostics/payload-artifact.json, and uploads static CSS/chunks, manifests, and
.nft.json traces.pnpm --filter saas analyze:payload runs next experimental-analyze --output,
a second full compile of about eight minutes on CI. It runs only on a manual workflow run, and its
output lands in the same saas-payload-baseline artifact.pnpm --filter centrakit baseline:payload packs a baseline tarball and prints dist/cli.js / tarball byte sizes.Locally:
pnpm exec turbo run baseline:payload --filter=saas --filter=./apps/cliThe versioned SaaS artifact records, per audited route, uncompressed production JS, route-only JS after removing chunks shared by every audited route, obtainable prerendered Flight/RSC bytes, server entry bytes, and the unique files/bytes referenced by its NFT trace. Audited routes are Dashboard, Planning, Tasks/all, Products, Admin subscriptions, Audit log, Agenda detail, and Product detail.
CI selects only audited routes affected by changed source paths. A shared App Shell change selects all audited routes. Shared production JS is compared once with a zero-growth budget, so the same shared regression is not repeated for every route. Route budgets allow the larger of the absolute or percentage allowance: 25 KiB/5% route JS, 10 KiB/5% Flight and server entry, and 100 KiB/2% server trace. Missing or schema-incompatible base artifacts warn and skip comparison, including in enforce mode. Runtime timings are intentionally excluded because CI compares build artifacts only.
develop and main run the same check set. Payload baselines compare against the latest successful run on the PR base branch (or the pushed branch).pnpm openapi:generate and fails if committed API artifacts drift./api/v1/health) and the SaaS app on port 3100 (ready on /login).NEXT_PUBLIC_SITE_URL=http://localhost:3101, so the SaaS /api/v1 rewrite resolves to http://api.localhost:3101. The root pnpm test:e2e script sets this variable, which means it rebuilds apps/saas/.next and apps/api/.next for the E2E origin.CK_DB_TRACE_FILE, so the database-call budget only counts SaaS requests.Every user-visible change gets a changeset (pnpm changeset). The apps share one fixed version (.changeset/config.json fixed group with privatePackages.version and tag), so the product has a single release number.
pnpm version-packages runs scripts/root-changelog.ts, which reads the pending changesets, runs changeset version (per-app CHANGELOG.md files), and prepends a dated section with every changeset summary to the root CHANGELOG.md. It then formats the changelogs. The docs site renders the root changelog.
Release automation is split into two workflows:
release.yml opens or updates the chore: version packages PR from the pending changesets.centrakit@<version> and publishes the GitHub release, and release-cli.yml packages the tarball and uploads it to the release.release-cli.yml also keeps workflow_dispatch for retrying an asset upload against an existing release tag.
Last updated on