Development

Architecture

System architecture, rendering pipeline, data flow, and high-level component overview.

Architecture

Gerbtrace uses a client-rendered Nuxt application and a Tauri desktop app that bundles the same application frontend. Public marketing and documentation routes render and prerender HTML on the web (ADR-012); authenticated application routes remain client-rendered. Collaboration features are backed by Supabase Cloud.

High-level components

The system consists of three main deployment targets:

  • Web app – hosted on Cloudflare Workers with public HTML and client-rendered application routes; the Worker serves static assets, a small set of Nitro API routes, and docs content from D1
  • Desktop app – Tauri 2 (Rust) wrapping the same Nuxt frontend, distributed via GitHub Releases
  • API server – Supabase Cloud (PostgreSQL, Storage, Realtime, Edge Functions, Auth)

The browser/desktop client communicates with the API server over HTTPS for data operations and WSS for real-time subscriptions. The desktop app additionally checks GitHub Releases for auto-updates.

Architecture decisions

Architecture Decision Records (ADRs) live in docs/adr/. Start with docs/adr/README.md for the central decision log, status taxonomy, accepted decisions, and proposed roadmap decisions. When this overview conflicts with an ADR, the ADR is the source of truth for the decision it covers.

Gerber rendering pipeline

Raw Gerber and drill files are processed through a multi-stage pipeline:

  1. Tokenizer – raw Gerber/drill text is split into tokens
  2. Parser – tokens are parsed into a typed AST (Abstract Syntax Tree) of Gerber commands
  3. Plotter – the AST is transformed into an ImageTree of drawing primitives (arcs, lines, regions, flashes)
  4. Renderer – the ImageTree is drawn onto an HTML5 Canvas element

The pipeline lives in lib/gerber/ (tokenizer, parser, plotter) and lib/renderer/ (canvas renderer, realistic renderer, SVG exporter, pixel diff).

Renderer variants

RendererLocationPurpose
Canvas 2Dlib/renderer/canvas-renderer.tsStandard layer rendering
Realisticlib/renderer/realistic-renderer.ts3D-style PCB appearance
SVG Exporterlib/renderer/svg-exporter.tsSVG export
DXF Exporterlib/renderer/dxf-exporter.tsDXF export for CAD integration
Pixel Difflib/renderer/pixel-diff.tsComparison mode pixel differencing

Data persistence

DataLocal (browser/desktop)Team (cloud)
ProjectsIndexedDB via Dexie.jsSupabase Postgres
FilesIndexedDB via Dexie.jsSupabase Storage
PackagesStatic JSON (public/packages/)Supabase JSONB (team_packages)
THT PackagesStatic JSON (public/packages/tht-libraries/)Supabase JSONB (team_tht_packages)
User preferenceslocalStorage–

Local projects work entirely offline. A successfully opened team project and its downloaded files are cached in account-scoped IndexedDB, so they can be reopened without a connection and edits queue in the durable outbox. Live collaboration, authentication refreshes, AI enrichment, supplier pricing, and the first load of uncached team data still require the Supabase/API connection.

Team project updates are measured at the viewer persistence boundary with app/utils/project-payload-metrics.ts. The metrics warn when a single update or field approaches the ADR-006 row-growth thresholds, which informs future extraction of large/hot feature data into child tables. BOM lines and pricing now use independent project_bom_data child rows.

Package system

Built-in packages are organized as a library tree under public/packages/libraries/. At runtime, the library tree manifest (_tree.json) is loaded, and individual packages are fetched on demand.

Team packages are stored in Supabase as JSONB and merged into the in-app library at runtime. Export to .pck uses the TPSys serializer in app/utils/pck-serializer.ts.

All packages use TPSys package types exclusively. See Package Definitions for the type system.

Collaboration and sync

  • Auth – Supabase Auth with Microsoft OAuth (Entra ID), GitHub OAuth, email/password, and magic link flows
  • Teams and projects – stored in Postgres, shared via Supabase Realtime subscriptions
  • Spaces – project and package scoping within teams, with guest access via space invitations
  • Conversations – threaded project discussions with mentions, references, and file attachments
  • Notifications – real-time notification delivery for mentions, approvals, and status changes
  • Presence – tracked via Realtime channels to show who is viewing a project
  • Files – stored in Supabase Storage (gerber-files bucket), metadata tracked in Postgres
  • Row-level security – all tables use RLS policies that enforce team membership, role-based access, and space-level scoping

Database schema

The database is defined through idempotent SQL migrations in supabase/migrations/. Key tables:

TablePurpose
profilesUser profiles with avatar and display name (auto-created on signup)
teamsTeam definitions with subdomain slugs and settings
team_membersUser-team relationships with roles (admin, editor, viewer, guest)
team_invitationsPending email invitations
spacesWorkgroups within teams for organizing projects
space_membersUser-space membership
space_invitationsGuest invitations to spaces with expiry tokens
projectsPCB projects with PnP, panel, paste, and pcb_data JSONB. BOM lines and pricing live in project_bom_data
project_bom_dataPartitioned BOM payloads keyed by kind (lines or pricing_cache), each an independent realtime row
project_filesGerber/drill file metadata
project_documentsPDF document metadata
project_conversation_messagesThreaded conversation messages per project
project_conversation_attachmentsFile attachments on conversation messages
notificationsUser notifications (mentions, approvals, status changes)
bom_groupsNamed groups for organizing BOM lines
team_packagesCustom SMD package definitions
team_tht_packagesCustom THT package definitions

Edge functions

Supabase Edge Functions (Deno runtime) handle server-side operations:

FunctionPurpose
admin-password-resetAdmin-initiated password resets
send-invitationSend team and space guest invitation emails (via Resend API)
elexess-exchange-rateDaily USD→EUR rate for BOM pricing, proxied from the ECB reference feed (CORS bypass)
main/ai-enrich-bomSpark AI BOM enrichment
main/ai-validate-keyValidate Spark AI provider keys (platform admins only)
main/elexess-searchElexess part search through api.elexess.com with the team's or the platform's Elexess API token, mapped to the cached pricing shape
main/elexess-validate-credentialsValidate an Elexess API token against the quota-free suppliers endpoint (platform admins only)
stripe-*Stripe checkout, portal, and webhook handling
admin-*Platform admin usage and team actions
delete-accountAccount deletion workflow
telemetryLightweight telemetry endpoint

API routes

Supabase Edge Functions are the canonical server-side API for business logic (ADR-001). Nuxt server API routes are reserved for operations that must live on the app's own origin:

RoutePurpose
/api/legal/consentRecord legal consent on the app origin
/api/account/exportExport account data as a same-origin download

Frontend structure

The Nuxt app follows a composable-driven architecture:

  • Pages (app/pages/) – route definitions for viewer, compare, team, auth, docs, inbox, and spaces
  • Components (app/components/) – organized by feature area (viewer, compare, import, packages, docs, shared)
  • Composables (app/composables/) – state management and business logic (useProject, useBom, usePickAndPlace, useAuth, useTeamProjects, useSpaces, useProjectConversation, useNotifications, useDrawTool, useAiEnrichment, useErrorReporting, etc.)
  • Utils (app/utils/) – pure functions for parsing, geometry, formatting, and conventions
  • Libraries (lib/) – rendering pipeline, Gerber/drill generation, jet print export, DXF export