Skip to main content

Architecture Overview

DealerOS is a multi-tenant SaaS for automotive dealer groups: vehicle inventory, a public marketplace with listings and lead capture, CRM leads, self-serve signup and onboarding, Stripe-backed billing, and a provider abstraction layer for third-party automotive integrations.

System overview

Runtime applications

  • Web (apps/web): Next.js App Router console and responsive public marketing site. Handles Auth0 authorization-code login, callback, logout, encrypted/signed HTTP-only session cookie, and console surfaces: organization, inventory, marketplace, leads, providers, onboarding, billing, signup, and public listing pages.
  • API (apps/api): NestJS API, default-deny behind a global guard. Provides session/tenant resolution, organization, inventory, marketplace, media, leads, signup, invitations, onboarding, billing, providers, and signature-verified Stripe/Resend/provider webhooks.
  • End-to-end tests (apps/web-e2e): Playwright specs plus local Auth0 and Stripe-compatible mocks, including the complete signup, trial, onboarding, and invite journey.
The web server calls the API from apps/web/src/lib/dealeros-api.ts. Authenticated calls attach an Auth0 access token and the selected tenant UUID. Public marketplace calls omit those headers.

Request flow

Authentication and tenant isolation

The API registers AuthenticatedTenantGuard as a global application guard. Unless a controller or handler is marked public, a request must provide:
  • Authorization: Bearer <auth0-access-token>
  • x-dealeros-tenant-id: <tenant-uuid>
Tenant resolution checks that the token’s Auth0 organization matches an active DealerOS tenant and that the subject has an active membership. A user without a previously verified email is rejected. Database work runs inside a transaction that calls app.set_tenant_context before executing tenant queries. SQL migrations enable and force row-level security across tenant-owned tables. Runtime connections are reset with DISCARD ALL before returning to the pool.

Shared packages

  • packages/config: validates runtime configuration with Zod
  • packages/db: PostgreSQL pooling, tenant transaction context, migration execution
  • packages/design-tokens: generates the theme consumed by the marketing build
  • packages/shared: request schemas and shared domain records
  • packages/provider-framework: provider registration, capability, rights, credential-reference, and idempotency contracts

Data model

The repository contains 19 ordered SQL migration files (0001_foundation.sql through 0019_credential_refs_are_references.sql). Major table groups include:
  • Tenancy and delivery: tenants, identities, memberships, audit log, outbox, webhook inbox, sent email, idempotency records
  • Inventory: vehicle identities, vehicles, builds, VIN snapshots, inventory units
  • Marketplace: media assets, dealer settings, vehicle offers, listings, revisions, search documents, saved searches, favorites
  • CRM: leads, routing rules, lead status events
  • Providers: catalog, entitlements, routes, circuit breakers, webhook inbox, usage events
  • Self-service: plan tiers, billing accounts, invitations, onboarding progress, signup requests, feature overrides, signup claims
Migrations are plain SQL, applied in lexical order, recorded in app.schema_migrations, and wrapped one file at a time in a transaction.

Configuration

packages/config/src/index.ts groups configuration for application URLs and release, Auth0, Turnstile, billing, PostgreSQL, email, media storage, marketplace search, observability, providers, Temporal, and Cloudflare switches. The implementation defaults marketplace search to PostgreSQL and local media storage. Azure Blob storage is supported when selected and configured.

Web route map

Deployment topology

The repository contains separate multi-stage Dockerfiles for the API and web application. Runtime images expose ports 4000 (API) and 3000 (web) and run as a non-root dealeros user. The infrastructure manifests describe two container services, an image build, and health checks for both services. Production media is configured for Azure Blob storage; marketplace search uses PostgreSQL.