fix(tenant): use TenantContextModule.forRoot() for global tenant context
All services were providing TenantContextService directly without making it global, causing DI resolution failures in child modules. Now using TenantContextModule.forRoot() which exports TenantContextService globally so all repositories can access it. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
89d9645c02
commit
7ff701369b
|
|
@ -0,0 +1,13 @@
|
|||
FROM node:20-alpine
|
||||
|
||||
# 安装 pnpm
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 设置 pnpm store 目录
|
||||
ENV PNPM_HOME=/root/.local/share/pnpm
|
||||
ENV PATH=$PNPM_HOME:$PATH
|
||||
|
||||
CMD ["sh"]
|
||||
|
|
@ -28,7 +28,21 @@
|
|||
"Bash(cmd /c \"dir %USERPROFILE%\\\\.ssh\")",
|
||||
"Bash(git fetch:*)",
|
||||
"Bash(TEST_USER_ID=\"a1b2c3d4-e5f6-7890-abcd-ef1234567890\":*)",
|
||||
"Bash(git reset:*)"
|
||||
"Bash(git reset:*)",
|
||||
"Bash(ls \"c:\\\\Users\\\\dong\\\\Desktop\\\\iConsulting\\\\packages\\\\services\\\\evolution-service\\\\src\\\\infrastructure\\\\database\\\\entities\"\" 2>/dev/null || echo \"Directory empty or not exists \")",
|
||||
"Bash(done)",
|
||||
"Bash(for service in knowledge-service conversation-service user-service payment-service evolution-service file-service)",
|
||||
"Bash(do echo \"=== $service ===\" find \"/c/Users/dong/Desktop/iConsulting/packages/services/$service/src\" -type d)",
|
||||
"Bash(pnpm build)",
|
||||
"Bash(find:*)",
|
||||
"Bash(grep:*)",
|
||||
"Bash(timeout:*)",
|
||||
"Bash(git restore:*)",
|
||||
"Bash(pnpm build:*)",
|
||||
"Bash(pnpm --filter @iconsulting/shared build:*)",
|
||||
"Bash(pnpm --filter @iconsulting/user-service build:*)",
|
||||
"Bash(pnpm --filter @iconsulting/conversation-service build:*)",
|
||||
"Bash(pnpm --filter @iconsulting/payment-service build:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/c
|
|||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import {
|
||||
TenantContextService,
|
||||
TenantContextModule,
|
||||
TenantContextMiddleware,
|
||||
SimpleTenantFinder,
|
||||
DEFAULT_TENANT_ID,
|
||||
|
|
@ -19,6 +19,17 @@ import { HealthModule } from './health/health.module';
|
|||
envFilePath: ['.env.local', '.env'],
|
||||
}),
|
||||
|
||||
// Tenant context module (global)
|
||||
TenantContextModule.forRoot({
|
||||
tenantFinder: SimpleTenantFinder,
|
||||
middlewareOptions: {
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*'],
|
||||
},
|
||||
isGlobal: true,
|
||||
}),
|
||||
|
||||
// Database
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
|
|
@ -53,27 +64,15 @@ import { HealthModule } from './health/health.module';
|
|||
ConversationModule,
|
||||
ClaudeModule,
|
||||
],
|
||||
providers: [TenantContextService, SimpleTenantFinder],
|
||||
})
|
||||
export class AppModule implements NestModule {
|
||||
constructor(
|
||||
private readonly tenantContext: TenantContextService,
|
||||
private readonly tenantFinder: SimpleTenantFinder,
|
||||
private readonly tenantMiddleware: TenantContextMiddleware,
|
||||
) {}
|
||||
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
const tenantMiddleware = new TenantContextMiddleware(
|
||||
this.tenantContext,
|
||||
this.tenantFinder,
|
||||
{
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*'],
|
||||
},
|
||||
);
|
||||
|
||||
consumer
|
||||
.apply((req: any, res: any, next: any) => tenantMiddleware.use(req, res, next))
|
||||
.apply((req: any, res: any, next: any) => this.tenantMiddleware.use(req, res, next))
|
||||
.exclude(
|
||||
{ path: 'health', method: RequestMethod.GET },
|
||||
{ path: 'health/(.*)', method: RequestMethod.ALL },
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
|
|||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ScheduleModule } from '@nestjs/schedule';
|
||||
import {
|
||||
TenantContextService,
|
||||
TenantContextModule,
|
||||
TenantContextMiddleware,
|
||||
DEFAULT_TENANT_ID,
|
||||
} from '@iconsulting/shared';
|
||||
|
|
@ -25,6 +25,17 @@ import { TenantFinderService } from './infrastructure/tenant/tenant-finder.servi
|
|||
// 定时任务模块
|
||||
ScheduleModule.forRoot(),
|
||||
|
||||
// Tenant context module (global) - uses custom TenantFinderService
|
||||
TenantContextModule.forRoot({
|
||||
tenantFinder: TenantFinderService,
|
||||
middlewareOptions: {
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*', '/super-admin/*'],
|
||||
},
|
||||
isGlobal: true,
|
||||
}),
|
||||
|
||||
// 数据库连接
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
|
|
@ -54,28 +65,15 @@ import { TenantFinderService } from './infrastructure/tenant/tenant-finder.servi
|
|||
AdminModule,
|
||||
AnalyticsModule,
|
||||
],
|
||||
providers: [TenantContextService],
|
||||
})
|
||||
export class AppModule implements NestModule {
|
||||
constructor(
|
||||
private readonly tenantContext: TenantContextService,
|
||||
private readonly tenantFinder: TenantFinderService,
|
||||
private readonly tenantMiddleware: TenantContextMiddleware,
|
||||
) {}
|
||||
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
// 创建租户中间件
|
||||
const tenantMiddleware = new TenantContextMiddleware(
|
||||
this.tenantContext,
|
||||
this.tenantFinder,
|
||||
{
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*', '/super-admin/*'],
|
||||
},
|
||||
);
|
||||
|
||||
consumer
|
||||
.apply((req: any, res: any, next: any) => tenantMiddleware.use(req, res, next))
|
||||
.apply((req: any, res: any, next: any) => this.tenantMiddleware.use(req, res, next))
|
||||
.exclude(
|
||||
{ path: 'health', method: RequestMethod.GET },
|
||||
{ path: 'health/(.*)', method: RequestMethod.ALL },
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/c
|
|||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import {
|
||||
TenantContextService,
|
||||
TenantContextModule,
|
||||
TenantContextMiddleware,
|
||||
SimpleTenantFinder,
|
||||
DEFAULT_TENANT_ID,
|
||||
|
|
@ -18,6 +18,17 @@ import { FileModule } from './file/file.module';
|
|||
envFilePath: ['.env.local', '.env'],
|
||||
}),
|
||||
|
||||
// Tenant context module (global)
|
||||
TenantContextModule.forRoot({
|
||||
tenantFinder: SimpleTenantFinder,
|
||||
middlewareOptions: {
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*'],
|
||||
},
|
||||
isGlobal: true,
|
||||
}),
|
||||
|
||||
// 数据库连接
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
|
|
@ -41,27 +52,15 @@ import { FileModule } from './file/file.module';
|
|||
// 功能模块
|
||||
FileModule,
|
||||
],
|
||||
providers: [TenantContextService, SimpleTenantFinder],
|
||||
})
|
||||
export class AppModule implements NestModule {
|
||||
constructor(
|
||||
private readonly tenantContext: TenantContextService,
|
||||
private readonly tenantFinder: SimpleTenantFinder,
|
||||
private readonly tenantMiddleware: TenantContextMiddleware,
|
||||
) {}
|
||||
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
const tenantMiddleware = new TenantContextMiddleware(
|
||||
this.tenantContext,
|
||||
this.tenantFinder,
|
||||
{
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*'],
|
||||
},
|
||||
);
|
||||
|
||||
consumer
|
||||
.apply((req: any, res: any, next: any) => tenantMiddleware.use(req, res, next))
|
||||
.apply((req: any, res: any, next: any) => this.tenantMiddleware.use(req, res, next))
|
||||
.exclude(
|
||||
{ path: 'health', method: RequestMethod.GET },
|
||||
{ path: 'health/(.*)', method: RequestMethod.ALL },
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/c
|
|||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import {
|
||||
TenantContextService,
|
||||
TenantContextModule,
|
||||
TenantContextMiddleware,
|
||||
SimpleTenantFinder,
|
||||
DEFAULT_TENANT_ID,
|
||||
|
|
@ -19,6 +19,17 @@ import { HealthModule } from './health/health.module';
|
|||
envFilePath: ['.env.local', '.env'],
|
||||
}),
|
||||
|
||||
// Tenant context module (global)
|
||||
TenantContextModule.forRoot({
|
||||
tenantFinder: SimpleTenantFinder,
|
||||
middlewareOptions: {
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*'],
|
||||
},
|
||||
isGlobal: true,
|
||||
}),
|
||||
|
||||
// 数据库连接
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
|
|
@ -44,27 +55,15 @@ import { HealthModule } from './health/health.module';
|
|||
KnowledgeModule,
|
||||
MemoryModule,
|
||||
],
|
||||
providers: [TenantContextService, SimpleTenantFinder],
|
||||
})
|
||||
export class AppModule implements NestModule {
|
||||
constructor(
|
||||
private readonly tenantContext: TenantContextService,
|
||||
private readonly tenantFinder: SimpleTenantFinder,
|
||||
private readonly tenantMiddleware: TenantContextMiddleware,
|
||||
) {}
|
||||
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
const tenantMiddleware = new TenantContextMiddleware(
|
||||
this.tenantContext,
|
||||
this.tenantFinder,
|
||||
{
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*'],
|
||||
},
|
||||
);
|
||||
|
||||
consumer
|
||||
.apply((req: any, res: any, next: any) => tenantMiddleware.use(req, res, next))
|
||||
.apply((req: any, res: any, next: any) => this.tenantMiddleware.use(req, res, next))
|
||||
.exclude(
|
||||
{ path: 'health', method: RequestMethod.GET },
|
||||
{ path: 'health/(.*)', method: RequestMethod.ALL },
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/c
|
|||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import {
|
||||
TenantContextService,
|
||||
TenantContextModule,
|
||||
TenantContextMiddleware,
|
||||
SimpleTenantFinder,
|
||||
DEFAULT_TENANT_ID,
|
||||
|
|
@ -18,6 +18,17 @@ import { HealthModule } from './health/health.module';
|
|||
envFilePath: ['.env.local', '.env'],
|
||||
}),
|
||||
|
||||
// Tenant context module (global)
|
||||
TenantContextModule.forRoot({
|
||||
tenantFinder: SimpleTenantFinder,
|
||||
middlewareOptions: {
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*'],
|
||||
},
|
||||
isGlobal: true,
|
||||
}),
|
||||
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
|
|
@ -56,27 +67,15 @@ import { HealthModule } from './health/health.module';
|
|||
OrderModule,
|
||||
PaymentModule,
|
||||
],
|
||||
providers: [TenantContextService, SimpleTenantFinder],
|
||||
})
|
||||
export class AppModule implements NestModule {
|
||||
constructor(
|
||||
private readonly tenantContext: TenantContextService,
|
||||
private readonly tenantFinder: SimpleTenantFinder,
|
||||
private readonly tenantMiddleware: TenantContextMiddleware,
|
||||
) {}
|
||||
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
const tenantMiddleware = new TenantContextMiddleware(
|
||||
this.tenantContext,
|
||||
this.tenantFinder,
|
||||
{
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*'],
|
||||
},
|
||||
);
|
||||
|
||||
consumer
|
||||
.apply((req: any, res: any, next: any) => tenantMiddleware.use(req, res, next))
|
||||
.apply((req: any, res: any, next: any) => this.tenantMiddleware.use(req, res, next))
|
||||
.exclude(
|
||||
{ path: 'health', method: RequestMethod.GET },
|
||||
{ path: 'health/(.*)', method: RequestMethod.ALL },
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
|
|||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import {
|
||||
TenantContextService,
|
||||
TenantContextModule,
|
||||
TenantContextMiddleware,
|
||||
SimpleTenantFinder,
|
||||
DEFAULT_TENANT_ID,
|
||||
|
|
@ -19,6 +19,17 @@ import { HealthModule } from './health/health.module';
|
|||
envFilePath: ['.env.local', '.env'],
|
||||
}),
|
||||
|
||||
// Tenant context module (global)
|
||||
TenantContextModule.forRoot({
|
||||
tenantFinder: SimpleTenantFinder,
|
||||
middlewareOptions: {
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*'],
|
||||
},
|
||||
isGlobal: true,
|
||||
}),
|
||||
|
||||
TypeOrmModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
|
|
@ -52,27 +63,15 @@ import { HealthModule } from './health/health.module';
|
|||
UserModule,
|
||||
AuthModule,
|
||||
],
|
||||
providers: [TenantContextService, SimpleTenantFinder],
|
||||
})
|
||||
export class AppModule implements NestModule {
|
||||
constructor(
|
||||
private readonly tenantContext: TenantContextService,
|
||||
private readonly tenantFinder: SimpleTenantFinder,
|
||||
private readonly tenantMiddleware: TenantContextMiddleware,
|
||||
) {}
|
||||
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
const tenantMiddleware = new TenantContextMiddleware(
|
||||
this.tenantContext,
|
||||
this.tenantFinder,
|
||||
{
|
||||
allowDefaultTenant: true,
|
||||
defaultTenantId: DEFAULT_TENANT_ID,
|
||||
excludePaths: ['/health', '/health/*'],
|
||||
},
|
||||
);
|
||||
|
||||
consumer
|
||||
.apply((req: any, res: any, next: any) => tenantMiddleware.use(req, res, next))
|
||||
.apply((req: any, res: any, next: any) => this.tenantMiddleware.use(req, res, next))
|
||||
.exclude(
|
||||
{ path: 'health', method: RequestMethod.GET },
|
||||
{ path: 'health/(.*)', method: RequestMethod.ALL },
|
||||
|
|
|
|||
Loading…
Reference in New Issue