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(orhttp://127.0.0.1:54321when 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:
package.json–"version"src-tauri/tauri.conf.json–"version"src-tauri/Cargo.toml–versionnuxt.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
| Workflow | Trigger | Action |
|---|---|---|
ci.yml | Pull request to main and push to main | Type check, tests, architecture checks, Worker build, and the required browser smoke suite (ADR-007) |
build-desktop.yml | Tag 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.
pnpm install --frozen-lockfilepnpm run build- Deploy the generated Worker via the Cloudflare Workers Builds pipeline
(
wrangler deployon the production branch,wrangler versions uploadfor preview branches) - Optional cache purge in Cloudflare dashboard when needed
Desktop release
Triggered on v* tag push:
qualityjob: typecheck,pnpm run version:check, Vitest. The build matrix does not start if it fails (ADR-005)- Matrix build for macOS (universal binary) and Windows
- macOS: Apple certificate import, keychain setup, notarization
- Windows: standard build
- Signs updater artifacts with the Tauri signing key and creates the private release
- Run
desktop:publishto publish the signed installers and rewrittenlatest.jsoninnewmatik/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_TOKENfor 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_PASSWORDAPPLE_SIGNING_IDENTITYAPPLE_API_ISSUER,APPLE_API_KEY,APPLE_API_KEY_CONTENT
Use the setup scripts to configure secrets:
scripts/setup-github-secrets.sh— Tauri signing keypairscripts/setup-apple-signing.sh— Apple certificate and notarizationscripts/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:checkpasses - Every
CREATE TABLEusesIF NOT EXISTS - Every
CREATE FUNCTIONusesCREATE OR REPLACE - Every
ALTER TABLE ADD COLUMNusesIF NOT EXISTS - Every
ALTER TABLE ADD CONSTRAINTcheckspg_constraintbefore adding - Every
CREATE POLICYis guarded against re-creation - Dedup
DELETEstatements userow_number()with a stable tiebreaker - No statement depends on
postgresbeing able toSET ROLE supabase_admin - No statement requires table/function ownership that
supabase_admindoes 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:verifypasses: 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.ymlsucceeded for bothmacos-latestandwindows-latest - Desktop: the public GitHub Release has both macOS and Windows installers
- Desktop: the public
latest.jsonand installer URLs return 200 without GitHub authentication - Supabase: migrations applied (confirm via
execute_sqlor 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
| Release | Failure | Root cause |
|---|---|---|
| v1.0.6 | Initial schema fails on provisioned DB | Migration not idempotent |
| v1.0.6 | set -e kills script on expected errors | Error handling too strict |
| v1.0.9 | must be owner of function | postgres cannot replace function owned by supabase_admin |
| v1.0.10 | must be owner of table | postgres cannot ALTER tables owned by supabase_admin |
| v1.0.10 | permission denied to set role | postgres 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.