Add three new NestJS modules following DDD/CQRS architecture: - Industrial: KCN (industrial park) management with PostGIS geo queries, Typesense search, and market statistics - Transfer: Furniture/premises transfer listings with AI-powered price estimation and depreciation modeling - Reports: Async AI report generation via BullMQ with Claude narrative service, PDF generation, and macro data integration Includes Prisma schema models, migrations, seed scripts, and app.module wiring with BullMQ Redis config. Co-Authored-By: Paperclip <noreply@paperclip.ing>
126 lines
4.3 KiB
TypeScript
126 lines
4.3 KiB
TypeScript
import { BullModule } from '@nestjs/bullmq';
|
|
import { type MiddlewareConsumer, Module, type NestModule, RequestMethod } from '@nestjs/common';
|
|
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core';
|
|
import { CqrsModule } from '@nestjs/cqrs';
|
|
import { ScheduleModule } from '@nestjs/schedule';
|
|
import { ThrottlerModule } from '@nestjs/throttler';
|
|
import { SentryGlobalFilter, SentryModule } from '@sentry/nestjs/setup';
|
|
import { AdminModule } from '@modules/admin';
|
|
import { AgentsModule } from '@modules/agents';
|
|
import { AnalyticsModule } from '@modules/analytics';
|
|
import { AuthModule } from '@modules/auth';
|
|
import { HealthModule } from '@modules/health';
|
|
import { IndustrialModule } from '@modules/industrial';
|
|
import { InquiriesModule } from '@modules/inquiries';
|
|
import { LeadsModule } from '@modules/leads';
|
|
import { ListingsModule } from '@modules/listings';
|
|
import { McpIntegrationModule } from '@modules/mcp';
|
|
import { MessagingModule } from '@modules/messaging';
|
|
import { HttpMetricsInterceptor, MetricsModule } from '@modules/metrics';
|
|
import { NotificationsModule } from '@modules/notifications';
|
|
import { PaymentsModule } from '@modules/payments';
|
|
import { ReportsModule } from '@modules/reports';
|
|
import { ReviewsModule } from '@modules/reviews';
|
|
import { SearchModule } from '@modules/search';
|
|
import { SharedModule } from '@modules/shared';
|
|
import { ThrottlerBehindProxyGuard } from '@modules/shared/infrastructure/guards/throttler-behind-proxy.guard';
|
|
import { CsrfMiddleware } from '@modules/shared/infrastructure/middleware/csrf.middleware';
|
|
import { SanitizeInputMiddleware } from '@modules/shared/infrastructure/middleware/sanitize-input.middleware';
|
|
import { SubscriptionsModule } from '@modules/subscriptions';
|
|
import { TransferModule } from '@modules/transfer';
|
|
import { AppController } from './app.controller';
|
|
|
|
@Module({
|
|
imports: [
|
|
SentryModule.forRoot(),
|
|
BullModule.forRoot({
|
|
connection: {
|
|
host: process.env['REDIS_HOST'] ?? 'localhost',
|
|
port: Number(process.env['REDIS_PORT'] ?? 6379),
|
|
password: process.env['REDIS_PASSWORD'] ?? undefined,
|
|
},
|
|
}),
|
|
CqrsModule.forRoot(),
|
|
ScheduleModule.forRoot(),
|
|
SharedModule,
|
|
HealthModule,
|
|
AuthModule,
|
|
AgentsModule,
|
|
InquiriesModule,
|
|
LeadsModule,
|
|
ListingsModule,
|
|
ReviewsModule,
|
|
SearchModule,
|
|
NotificationsModule,
|
|
PaymentsModule,
|
|
SubscriptionsModule,
|
|
AdminModule,
|
|
AnalyticsModule,
|
|
MetricsModule,
|
|
McpIntegrationModule,
|
|
MessagingModule,
|
|
ReportsModule,
|
|
IndustrialModule,
|
|
TransferModule,
|
|
|
|
// ── Rate Limiting ──
|
|
// Default: 60 requests per 60 seconds per IP
|
|
// Override per-route with @Throttle() decorator
|
|
ThrottlerModule.forRoot({
|
|
throttlers: [
|
|
{
|
|
name: 'default',
|
|
ttl: 60_000,
|
|
limit: process.env['NODE_ENV'] === 'test' || process.env['NODE_ENV'] === 'development' ? 10_000 : 60,
|
|
},
|
|
{
|
|
name: 'auth',
|
|
ttl: 60_000,
|
|
limit: process.env['NODE_ENV'] === 'test' || process.env['NODE_ENV'] === 'development' ? 10_000 : 10,
|
|
},
|
|
{
|
|
name: 'payment-callback',
|
|
ttl: 60_000,
|
|
limit: process.env['NODE_ENV'] === 'test' || process.env['NODE_ENV'] === 'development' ? 10_000 : 20,
|
|
},
|
|
],
|
|
}),
|
|
],
|
|
controllers: [AppController],
|
|
providers: [
|
|
{
|
|
provide: APP_FILTER,
|
|
useClass: SentryGlobalFilter,
|
|
},
|
|
{
|
|
provide: APP_GUARD,
|
|
useClass: ThrottlerBehindProxyGuard,
|
|
},
|
|
{
|
|
provide: APP_INTERCEPTOR,
|
|
useClass: HttpMetricsInterceptor,
|
|
},
|
|
],
|
|
})
|
|
export class AppModule implements NestModule {
|
|
configure(consumer: MiddlewareConsumer): void {
|
|
// Sanitize all incoming request strings to prevent stored XSS
|
|
consumer
|
|
.apply(SanitizeInputMiddleware)
|
|
.forRoutes('*');
|
|
|
|
// CSRF double-submit cookie (sets on GET, validates on state-changing methods)
|
|
// Exclude health endpoints — they must remain accessible without cookies
|
|
// Skip entirely in test mode so E2E / API tests can POST without a CSRF cookie
|
|
if (process.env['NODE_ENV'] !== 'test') {
|
|
consumer
|
|
.apply(CsrfMiddleware)
|
|
.exclude(
|
|
{ path: 'health', method: RequestMethod.GET },
|
|
{ path: 'health/(.*)', method: RequestMethod.GET },
|
|
)
|
|
.forRoutes('*');
|
|
}
|
|
}
|
|
}
|