first (part 3: src directory)
Deploy Iddaai Backend / build-and-deploy (push) Successful in 33s

This commit is contained in:
2026-04-16 15:12:27 +03:00
parent 2f0b85a0c7
commit 182f4aae16
125 changed files with 22552 additions and 0 deletions
Executable
+119
View File
@@ -0,0 +1,119 @@
import { NestFactory } from '@nestjs/core';
import { ValidationPipe, Logger as NestLogger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
import helmet from 'helmet';
import * as express from 'express';
import { Logger, LoggerErrorInterceptor } from 'nestjs-pino';
import { SanitizeInterceptor } from './common/interceptors/sanitize.interceptor';
// BigInt serialization polyfill — Prisma returns BigInt for mstUtc etc.
(BigInt.prototype as unknown as { toJSON: () => string }).toJSON = function () {
return this.toString();
};
async function bootstrap() {
const logger = new NestLogger('Bootstrap');
logger.log('🔄 Starting application...');
const app = await NestFactory.create(AppModule, { bufferLogs: false });
// Use Pino Logger
app.useLogger(app.get(Logger));
app.useGlobalInterceptors(
new LoggerErrorInterceptor(),
new SanitizeInterceptor(),
);
// Security Headers
app.use(helmet());
// Request payload size limit
app.use(express.json({ limit: '1mb' }));
app.use(express.urlencoded({ extended: true, limit: '1mb' }));
// Graceful Shutdown (Prisma & Docker)
app.enableShutdownHooks();
// Get config service
const configService = app.get(ConfigService);
const port = configService.get<number>('PORT', 3005);
const nodeEnv = configService.get('NODE_ENV', 'development');
// Enable CORS
app.enableCors({
origin:
nodeEnv === 'production'
? [
'https://ui-suggestbet.bilgich.com',
'https://suggestbet.bilgich.com',
'https://iddaai.com',
'https://www.iddaai.com',
]
: true,
credentials: true,
});
// Global prefix
app.setGlobalPrefix('api');
// Validation pipe (Strict)
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
forbidNonWhitelisted: true,
transformOptions: {
enableImplicitConversion: true,
},
}),
);
// Swagger setup — hidden in production
if (nodeEnv !== 'production') {
const swaggerConfig = new DocumentBuilder()
.setTitle('Suggest-Bet API')
.setDescription(
'AI-driven sports betting prediction engine with smart coupon generation',
)
.setVersion('1.0')
.addBearerAuth()
.addTag('Auth', 'Authentication endpoints')
.addTag('Users', 'User management endpoints')
.addTag('Admin', 'Admin management endpoints')
.addTag('Health', 'Health check endpoints')
.addTag('Matches', 'Match listing and detail endpoints')
.addTag('Leagues', 'League, country, and team discovery endpoints')
.addTag('Analysis', 'AI analysis and analysis history endpoints')
.addTag('Coupon', 'Coupon generation and coupon management endpoints')
.addTag('Predictions', 'Prediction and smart-coupon endpoints')
.build();
logger.log('Initializing Swagger...');
const document = SwaggerModule.createDocument(app, swaggerConfig);
SwaggerModule.setup('api/docs', app, document, {
swaggerOptions: {
persistAuthorization: true,
},
});
logger.log('Swagger initialized');
}
logger.log(`Attempting to listen on port ${port}...`);
await app.listen(port, '0.0.0.0');
logger.log('═══════════════════════════════════════════════════════════');
logger.log(`🚀 Server is running on: http://localhost:${port}/api`);
logger.log(`📚 Swagger documentation: http://localhost:${port}/api/docs`);
logger.log(`💚 Health check: http://localhost:${port}/api/health`);
logger.log(`🌍 Environment: ${nodeEnv.toUpperCase()}`);
logger.log('═══════════════════════════════════════════════════════════');
if (nodeEnv === 'development') {
logger.warn('⚠️ Running in development mode');
}
}
void bootstrap();