88 lines
2.7 KiB
TypeScript
88 lines
2.7 KiB
TypeScript
import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
|
||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||
import { ScheduleModule } from '@nestjs/schedule';
|
||
import {
|
||
TenantContextService,
|
||
TenantContextMiddleware,
|
||
DEFAULT_TENANT_ID,
|
||
} from '@iconsulting/shared';
|
||
import { EvolutionModule } from './evolution/evolution.module';
|
||
import { AdminModule } from './admin/admin.module';
|
||
import { HealthModule } from './health/health.module';
|
||
import { AnalyticsModule } from './analytics/analytics.module';
|
||
import { TenantModule } from './infrastructure/tenant/tenant.module';
|
||
import { TenantFinderService } from './infrastructure/tenant/tenant-finder.service';
|
||
|
||
@Module({
|
||
imports: [
|
||
// 配置模块
|
||
ConfigModule.forRoot({
|
||
isGlobal: true,
|
||
envFilePath: ['.env.local', '.env'],
|
||
}),
|
||
|
||
// 定时任务模块
|
||
ScheduleModule.forRoot(),
|
||
|
||
// 数据库连接
|
||
TypeOrmModule.forRootAsync({
|
||
imports: [ConfigModule],
|
||
inject: [ConfigService],
|
||
useFactory: (config: ConfigService) => ({
|
||
type: 'postgres',
|
||
host: config.get('POSTGRES_HOST', 'localhost'),
|
||
port: config.get<number>('POSTGRES_PORT', 5432),
|
||
username: config.get('POSTGRES_USER', 'postgres'),
|
||
password: config.get('POSTGRES_PASSWORD'),
|
||
database: config.get('POSTGRES_DB', 'iconsulting'),
|
||
autoLoadEntities: true,
|
||
// 禁用synchronize,使用init-db.sql初始化schema
|
||
synchronize: false,
|
||
logging: config.get('NODE_ENV') === 'development',
|
||
}),
|
||
}),
|
||
|
||
// 租户模块
|
||
TenantModule,
|
||
|
||
// Health check
|
||
HealthModule,
|
||
|
||
// 功能模块
|
||
EvolutionModule,
|
||
AdminModule,
|
||
AnalyticsModule,
|
||
],
|
||
providers: [TenantContextService],
|
||
})
|
||
export class AppModule implements NestModule {
|
||
constructor(
|
||
private readonly tenantContext: TenantContextService,
|
||
private readonly tenantFinder: TenantFinderService,
|
||
) {}
|
||
|
||
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))
|
||
.exclude(
|
||
{ path: 'health', method: RequestMethod.GET },
|
||
{ path: 'health/(.*)', method: RequestMethod.ALL },
|
||
{ path: 'super-admin', method: RequestMethod.ALL },
|
||
{ path: 'super-admin/(.*)', method: RequestMethod.ALL },
|
||
)
|
||
.forRoutes('*');
|
||
}
|
||
}
|