Files
neo/MULTI_TENANT_MIGRATION.md

116 lines
2.4 KiB
Markdown

# 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