import 'reflect-metadata'; import { NestFactory } from '@nestjs/core'; import { ValidationPipe, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { NestExpressApplication } from '@nestjs/platform-express'; import { AppModule } from './app.module'; import { RedisIoAdapter } from './realtime/redis-io.adapter'; async function bootstrap() { // rawBody: التوقيع يُحسب على الجسم **كما وصل** (docs/17 — I6). إعادة تسلسل // JSON قد تغيّر ترتيب المفاتيح أو المسافات فيفشل توقيع سليم. const app = await NestFactory.create(AppModule, { rawBody: true }); const cfg = app.get(ConfigService); // مُحوّل Socket.IO عبر Redis — يفعّل التوسّع الأفقي (عدة نسخ) const redisIoAdapter = new RedisIoAdapter(app, cfg); await redisIoAdapter.connectToRedis(); app.useWebSocketAdapter(redisIoAdapter); // خلف بروكسي (Nginx ينهي الـTLS): بلا هذا يصير req.ip = 127.0.0.1 للجميع، // فيمتلئ سجل التدقيق المالي (docs/17 — I7) بعنوان البروكسي بدل عنوان // السائق — أي أثرٌ بلا قيمة عند النزاع. `1` = ثقة بقفزة واحدة فقط؛ الثقة // المفتوحة تسمح للعميل بتزوير X-Forwarded-For. app.set('trust proxy', 1); app.setGlobalPrefix('api'); app.useGlobalPipes( new ValidationPipe({ whitelist: true, transform: true }), ); app.enableCors(); const swagger = new DocumentBuilder() .setTitle('Tripz API') .setDescription('منصة نقل ذكي متعددة المستأجرين') .setVersion('0.1.0') .addBearerAuth() .build(); SwaggerModule.setup('api/docs', app, SwaggerModule.createDocument(app, swagger)); if (!process.env.ENCRYPTION_KEY) { Logger.warn( 'ENCRYPTION_KEY غير مضبوط — يُستخدم مفتاح تطوير غير آمن. اضبطه للإنتاج (openssl rand -hex 32).', 'Security', ); } if (!process.env.PLATFORM_SECRET) { Logger.warn('PLATFORM_SECRET غير مضبوط — كل نقاط السوبر-أدمن مغلقة.', 'Security'); } if (cfg.get('payments.requireSignature') !== true) { Logger.warn( 'PAYMENTS_REQUIRE_SIGNATURE=false — العمليات المالية غير موقَّعة. فعّله بعد أن يوقّع تطبيق فلاتر (docs/17 I6).', 'Security', ); } const port = cfg.get('apiPort') ?? 4010; await app.listen(port, '0.0.0.0'); Logger.log(`Tripz API on :${port} (docs at /api/docs)`, 'Bootstrap'); } bootstrap();