Development

Release Process

Deployment architecture, environment variables, CI/CD workflows, release checklist, and operational safety.

Release Process

Gerbtrace has three deployable surfaces:

  • Web app — a Nuxt app deployed on Cloudflare Workers (gerbtrace.com)
  • Desktop app — Tauri 2 builds for macOS/Windows shipped via GitHub Releases with the Tauri updater
  • API server — Supabase Cloud project gqrnlnlfidighosujpdb (https://gqrnlnlfidighosujpdb.supabase.co)

Architecture and operations decisions are tracked in docs/adr/. See docs/adr/README.md for the decision log and ADR-005 for deployment authority.

Environment variables

For local development, copy .env.example to .env and set:

  • SUPABASE_URL — https://gqrnlnlfidighosujpdb.supabase.co (or http://127.0.0.1:54321 when using Local Supabase development)
  • SUPABASE_ANON_KEY — Supabase anon key (JWT)

The Nuxt runtime config also accepts NUXT_PUBLIC_SUPABASE_URL and NUXT_PUBLIC_SUPABASE_ANON_KEY (same values). Never commit .env (it is gitignored). Treat service-role keys and SMTP credentials as secrets.

Version bump

Update the version in all four files:

  1. package.json – "version"
  2. src-tauri/tauri.conf.json – "version"
  3. src-tauri/Cargo.toml – version
  4. nuxt.config.ts – runtimeConfig.public.appVersion

All four must match for the release to be consistent. pnpm run version:check verifies this locally and in CI.

Tag and release

git add -A && git commit -m "Release vX.Y.Z"
git tag vX.Y.Z
git push origin vX.Y.Z

GitHub Actions builds signed macOS and Windows installers in the private source repository when a v* tag is pushed. After both jobs pass, mirror the binaries to the public release repository:

pnpm run desktop:publish -- vX.Y.Z /path/to/release-notes.md --dry-run
pnpm run desktop:publish -- vX.Y.Z /path/to/release-notes.md

The publisher requires gh access to both Newmatik repositories. It uploads all signed assets and a public latest.json before publishing the release. Existing installs through v1.4.3 need one manual reinstall because their embedded updater URL points to the private source repository.

Release notes

Every release includes short, user-oriented release notes on the GitHub Releases page. Guidelines:

  • Use the bare version number as the release title (e.g., v1.1.1)
  • Use a flat bullet list with concise sentences
  • Focus on new features and bug fixes that affect users
  • No emojis, no internal details, no auto-generated contributor lists

The same text appears in the desktop app's "What's New" dialog after an auto-update.

CI/CD workflows

WorkflowTriggerAction
ci.ymlPull request to main and push to mainType check, tests, architecture checks, Worker build, and the required browser smoke suite (ADR-007)
build-desktop.ymlTag push (v*)Quality gate (typecheck, version check, tests), then build macOS/Windows apps in the private source repository

Web deployment

The web app is deployed to Cloudflare Workers. Until a checked-in deploy workflow exists, Cloudflare Workers Builds is the deployment authority and its dashboard build command/environment are part of the release configuration.

  1. pnpm install --frozen-lockfile
  2. pnpm run build
  3. Deploy the generated Worker via the Cloudflare Workers Builds pipeline (wrangler deploy on the production branch, wrangler versions upload for preview branches)
  4. Optional cache purge in Cloudflare dashboard when needed

Desktop release

Triggered on v* tag push:

  1. quality job: typecheck, pnpm run version:check, Vitest. The build matrix does not start if it fails (ADR-005)
  2. Matrix build for macOS (universal binary) and Windows
  3. macOS: Apple certificate import, keychain setup, notarization
  4. Windows: standard build
  5. Signs updater artifacts with the Tauri signing key and creates the private release
  6. Run desktop:publish to publish the signed installers and rewritten latest.json in newmatik/gerbtrace-releases

API deployment

Database migrations are applied directly to Supabase Cloud (project gqrnlnlfidighosujpdb) using the Supabase MCP tools (apply_migration, execute_sql).

Edge functions are deployed via the Supabase dashboard or CLI.

GitHub secrets

Web deploy (Cloudflare Workers Builds)

  • CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID (if required by the configured build/deploy pipeline)
  • SENTRY_DSN, (optional) SENTRY_AUTH_TOKEN for source maps

Desktop builds (build-desktop.yml)

Updater signing:

  • TAURI_SIGNING_PRIVATE_KEY, TAURI_SIGNING_PRIVATE_KEY_PASSWORD

Runtime config:

  • SUPABASE_ANON_KEY (URL is fixed in workflows)

Apple signing / notarization (macOS):

  • APPLE_CERTIFICATE, APPLE_CERTIFICATE_PASSWORD, KEYCHAIN_PASSWORD
  • APPLE_SIGNING_IDENTITY
  • APPLE_API_ISSUER, APPLE_API_KEY, APPLE_API_KEY_CONTENT

Use the setup scripts to configure secrets:

  • scripts/setup-github-secrets.sh — Tauri signing keypair
  • scripts/setup-apple-signing.sh — Apple certificate and notarization
  • scripts/set-sentry-secrets.mjs — Sentry DSN and auth token

Updater signing

The desktop auto-updater verifies signatures to ensure update integrity:

  • The public key in src-tauri/tauri.conf.json (plugins.updater.pubkey) must match the private key used in CI
  • If desktop builds fail with incorrect updater private key password, rotate/update the keypair and secrets

Supabase migration review

If the release includes new SQL migrations, verify before merging:

  • pnpm run migrations:check passes
  • Every CREATE TABLE uses IF NOT EXISTS
  • Every CREATE FUNCTION uses CREATE OR REPLACE
  • Every ALTER TABLE ADD COLUMN uses IF NOT EXISTS
  • Every ALTER TABLE ADD CONSTRAINT checks pg_constraint before adding
  • Every CREATE POLICY is guarded against re-creation
  • Dedup DELETE statements use row_number() with a stable tiebreaker
  • No statement depends on postgres being able to SET ROLE supabase_admin
  • No statement requires table/function ownership that supabase_admin does not have

Verification checklist

After a release:

  • Web: Cloudflare Workers build/deploy succeeded after merge to main
  • Web: RELEASE_BUILD_ID=<deployed commit sha> pnpm run release:verify passes: synthetic routes, the deployed build id, the docs rows through the D1-backed content route, and the Sentry release with source maps (see Operational Runbooks)
  • Desktop: build-desktop.yml succeeded for both macos-latest and windows-latest
  • Desktop: the public GitHub Release has both macOS and Windows installers
  • Desktop: the public latest.json and installer URLs return 200 without GitHub authentication
  • Supabase: migrations applied (confirm via execute_sql or Supabase dashboard)

If release:verify reports the previous build id (or the footer shows an old version) after deploy, purge cache in the Cloudflare dashboard (Caching > Configuration > Purge Everything) and re-run it.

Operational safety

  • Never paste private keys into PRs, issues, or chat. Treat pasted keys as compromised and rotate them.
  • Keep deploy keys scoped and rotate periodically.
  • Confirm Actions logs do not contain secret material.

Historical failure log

ReleaseFailureRoot cause
v1.0.6Initial schema fails on provisioned DBMigration not idempotent
v1.0.6set -e kills script on expected errorsError handling too strict
v1.0.9must be owner of functionpostgres cannot replace function owned by supabase_admin
v1.0.10must be owner of tablepostgres cannot ALTER tables owned by supabase_admin
v1.0.10permission denied to set rolepostgres cannot SET ROLE to supabase_admin

Sample data

The project ships with sample Arduino UNO Gerber files for demo purposes. The "Try a Sample" button on the landing page loads these files so users can explore without importing their own data.