3. System Architecture
3.1 System Overview
The target architecture replaces Prisma Client's runtime query
generation with Kysely for all tenant SQL operations while preserving
the existing service topology, migration tooling, and pooling
infrastructure. Application services continue to connect through
PgBouncer for database access. Kysely compiles queries to parameterized
SQL and executes them over a shared pg.Pool, with per-query schema
qualification via withSchema() replacing the per-tenant client model.
During the migration period, both query paths coexist. Each endpoint operates on either the Prisma path or the Kysely path, controlled by a routing mechanism at the service layer. The Prisma path remains available for rollback until the Kysely path is validated.
The target state eliminates the Prisma Engine intermediary for tenant
queries. Application services invoke Kysely's query API, which compiles
to parameterized SQL and dispatches through the shared pg.Pool to
PgBouncer and then to the tenant database. Migration tools continue
to use session pooling for schema operations.
3.2 Authority Domains
| Domain | Authority | Scope |
|---|---|---|
| Query Generation | Kysely query builder (target); Prisma Client (sunset) | Translates application query intent into parameterized SQL |
| Schema Definition | Prisma schema files in @pnats/schema-manager | Authoritative source for table structures and relation definitions |
| Type Generation | Prisma-generated types (current); Kysely type derivation (target) | Provides compile-time TypeScript types for query parameters |
| Connection Management | pg.Pool (target); Prisma Engine (sunset) | Manages database connections and pool lifecycle |
| Schema Migration | Prisma Migrate and Atlas | Applies DDL changes to metadata and tenant databases |
| Tenant Schema Scoping | withSchema() per query (target); search_path mutation (sunset) | Qualifies table references with the tenant schema identifier |
| Configuration Authority | @pnats/schema-manager PrismaModule and NestJS ConfigService | Provides database connection URLs and tenant configuration |
3.3 Trust Boundaries
| Boundary | Description |
|---|---|
| Service → Query Builder | Tenant module services pass tenant IDs and query parameters to the query builder; the query builder MUST scope all queries to the specified schema |
| Query Builder → Connection Pool | The query builder submits parameterized SQL to the connection pool; the pool MUST NOT retain schema context between queries from different tenants |
| Connection Pool → PgBouncer | The pg.Pool connects to PgBouncer transaction pooler; connection state MUST NOT leak between pooled connections |
| PgBouncer → Tenant Database | PgBouncer mediates authenticated connections to PostgreSQL; authentication and pooling rules MUST continue to enforce access boundaries |
| Migration Tools → Session Pooler | Prisma Migrate and Atlas use session pooling for DDL operations; migration connections are separate from query connections |
3.4 Stable Interfaces
The following interfaces remain stable through the migration:
| Interface | Description |
|---|---|
| HTTP API contracts | All endpoint request/response shapes, status codes, and pagination behavior remain unchanged |
| PgBouncer SQL protocol | Application traffic continues through PgBouncer transaction pooler via PostgreSQL wire protocol |
| Session pooler for migrations | Schema migration tooling continues to use session pooler for DDL operations |
x-tenant-id header | Tenant identification continues via the x-tenant-id HTTP header validated by TenantGuard |
@pnats/schema-manager module API | PrismaModule continues to export database configuration; Kysely integration extends rather than replaces |
| Prisma schema as source of truth | The multi-file Prisma schema in prisma/tenants/schema/ remains the authoritative schema definition |