Skip to content

Migration: Fauna → Postgres

Strategy:

  • Progressive migration guarded by Statsig flags per entity (see lib/flags/index.js)
  • Dual-read/dual-path via GraphQL context and resolvers; Postgres path uses services with Neon Postgres client and decoded JWT

Switches:

  • Global: faunaStopped kill switch if needed @deprecated - Use per-entity flags instead
  • Per-entity: faunaMigration* flags (vehicles, orders, plans, settings, widgets, payments, invoices, users, user_tenants, etc.)

Context creation (createResolversContext.js):

  • Validates tokens via getTokens
  • If Postgres enabled + user migration flags, calls authMiddleware to create Neon Postgres client, determines tenant/role, and instantiates services via createTenantServices
  • Dataloaders: Postgres loaders when enabled, otherwise Fauna loaders

Data movement:

  • Migration scripts under scripts/fauna-migration/* and fauna*.fsl
  • Ensure Prisma schema parity and indices

Auth-context note:

  • Tenant services inject decoded JWT into the Postgres session via set_config('request.jwt.claims', ...) (see TenantBaseService.ts)
  • No RLS policies are currently defined in the database — access control is enforced at the application layer via tenantId filtering in service methods
  • If RLS policies are added in the future, verify that authMiddleware correctly propagates JWT session variables and test enforcement on key tables

Cutover checklist:

  1. Enable entity flags in lower env, validate reads/writes
  2. Run backfill/migration scripts
  3. Verify authMiddleware and service-layer JWT propagation works with Neon Postgres client
  4. Switch write path to Postgres-only for the entity
  5. Monitor via Sentry/Axiom; roll back flags if needed