diff --git a/.builder.Dockerfile b/.builder.Dockerfile new file mode 100644 index 0000000..36bb508 --- /dev/null +++ b/.builder.Dockerfile @@ -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"] diff --git a/.claude/settings.local.json b/.claude/settings.local.json index d2ac671..1eee7b5 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -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:*)" ] } } diff --git a/packages/services/conversation-service/src/app.module.ts b/packages/services/conversation-service/src/app.module.ts index 068c34d..88c1b1b 100644 --- a/packages/services/conversation-service/src/app.module.ts +++ b/packages/services/conversation-service/src/app.module.ts @@ -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 }, diff --git a/packages/services/evolution-service/src/app.module.ts b/packages/services/evolution-service/src/app.module.ts index 41a79a9..1f2273c 100644 --- a/packages/services/evolution-service/src/app.module.ts +++ b/packages/services/evolution-service/src/app.module.ts @@ -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 }, diff --git a/packages/services/file-service/src/app.module.ts b/packages/services/file-service/src/app.module.ts index 9e4cc5e..aa94c65 100644 --- a/packages/services/file-service/src/app.module.ts +++ b/packages/services/file-service/src/app.module.ts @@ -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 }, diff --git a/packages/services/knowledge-service/src/app.module.ts b/packages/services/knowledge-service/src/app.module.ts index 1772204..1f1a9eb 100644 --- a/packages/services/knowledge-service/src/app.module.ts +++ b/packages/services/knowledge-service/src/app.module.ts @@ -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 }, diff --git a/packages/services/payment-service/src/app.module.ts b/packages/services/payment-service/src/app.module.ts index 5fefe31..bec7c06 100644 --- a/packages/services/payment-service/src/app.module.ts +++ b/packages/services/payment-service/src/app.module.ts @@ -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 }, diff --git a/packages/services/user-service/src/app.module.ts b/packages/services/user-service/src/app.module.ts index 1fac6e4..4373847 100644 --- a/packages/services/user-service/src/app.module.ts +++ b/packages/services/user-service/src/app.module.ts @@ -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 },