# Multi-Tenant Migration Guide ## Overview This guide walks you through migrating existing services from the single-database architecture to the new multi-database per-tenant architecture. ## Architecture Comparison ### Before (Single Database) ```typescript // Single Prisma client, data segregated by tenantId column @Injectable() export class UserService { constructor(private prisma: PrismaService) {} async findUserByEmail(tenantId: string, email: string) { return this.prisma.user.findFirst({ where: { tenantId, email }, }); } } ``` ### After (Multi-Database) ```typescript // Dynamic Knex connection per tenant, complete database isolation @Injectable() export class UserService { constructor(private tenantDb: TenantDatabaseService) {} async findUserByEmail(tenantId: string, email: string) { const knex = await this.tenantDb.getTenantKnex(tenantId); return User.query(knex).findOne({ email }); } } ``` ## Step-by-Step Service Migration Examples See full examples in the file for: - AuthService migration - RBACService migration - ObjectService migration - Controller updates - Common query patterns - Testing strategies ## Quick Reference ### Query Patterns **Simple Query** ```typescript // Prisma const user = await this.prisma.user.findUnique({ where: { tenantId, id } }); // Objection const knex = await this.tenantDb.getTenantKnex(tenantId); const user = await User.query(knex).findById(id); ``` **Query with Relations** ```typescript // Prisma const user = await this.prisma.user.findUnique({ where: { tenantId, id }, include: { roles: { include: { permissions: true } } }, }); // Objection const user = await User.query(knex) .findById(id) .withGraphFetched("roles.permissions"); ``` **Create** ```typescript // Prisma const user = await this.prisma.user.create({ data: { ... } }); // Objection const user = await User.query(knex).insert({ ... }); ``` **Update** ```typescript // Prisma const user = await this.prisma.user.update({ where: { id }, data: { ... } }); // Objection const user = await User.query(knex).patchAndFetchById(id, { ... }); ``` **Delete** ```typescript // Prisma await this.prisma.user.delete({ where: { id } }); // Objection await User.query(knex).deleteById(id); ``` ## Resources - [Knex.js Documentation](https://knexjs.org) - [Objection.js Documentation](https://vincit.github.io/objection.js) - [MULTI_TENANT_IMPLEMENTATION.md](./MULTI_TENANT_IMPLEMENTATION.md) - Full implementation details