fix: add TenantContextMiddleware to initialize tenant context from X-Tenant-Id header
All services using TenantAwareRepository require AsyncLocalStorage tenant
context to set the correct PostgreSQL search_path. The middleware reads
X-Tenant-Id from request headers and wraps the request with
TenantContextService.run(), using schema naming convention it0_t_{tenantId}.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
806113554b
commit
5b6e7ee363
|
|
@ -1,9 +1,14 @@
|
||||||
import { DynamicModule, Module } from '@nestjs/common';
|
import { DynamicModule, MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { TenantContextMiddleware } from './tenant-context.middleware';
|
||||||
|
|
||||||
@Module({})
|
@Module({})
|
||||||
export class DatabaseModule {
|
export class DatabaseModule implements NestModule {
|
||||||
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
consumer.apply(TenantContextMiddleware).forRoutes('*');
|
||||||
|
}
|
||||||
|
|
||||||
static forRoot(): DynamicModule {
|
static forRoot(): DynamicModule {
|
||||||
return {
|
return {
|
||||||
module: DatabaseModule,
|
module: DatabaseModule,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './tenant-aware.repository';
|
export * from './tenant-aware.repository';
|
||||||
export * from './database.module';
|
export * from './database.module';
|
||||||
export * from './tenant-provisioning.service';
|
export * from './tenant-provisioning.service';
|
||||||
|
export * from './tenant-context.middleware';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||||
|
import { Request, Response, NextFunction } from 'express';
|
||||||
|
import { TenantContextService } from '@it0/common';
|
||||||
|
import { TenantInfo } from '@it0/common';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TenantContextMiddleware implements NestMiddleware {
|
||||||
|
use(req: Request, res: Response, next: NextFunction) {
|
||||||
|
const tenantId = req.headers['x-tenant-id'] as string;
|
||||||
|
|
||||||
|
if (!tenantId) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const tenantInfo: TenantInfo = {
|
||||||
|
tenantId,
|
||||||
|
tenantName: tenantId,
|
||||||
|
plan: 'free',
|
||||||
|
schemaName: `it0_t_${tenantId}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
TenantContextService.run(tenantInfo, () => next());
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue