- Remove marcadores de conflito git em admin_service que causavam erro 500 em ListCompanies. - Implementa SeederService no backend Go com streaming SSE para logs em tempo real. - Expõe endpoints: GET /api/v1/seeder/seed/stream e POST /api/v1/seeder/reset. - Atualiza config do frontend para apontar URL do seeder para a API backend. - Corrige erros de sintaxe na UI do dashboard Backoffice e implementa busca de estatísticas. - Garante lógica correta de UPSERT no seeder (RETURNING id) usando colunas 'identifier' e 'full_name' para evitar abortar transações. - Corrige constraint de role em user_companies no seeder para usar 'admin'.
105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
import { NestFactory } from '@nestjs/core';
|
|
import {
|
|
FastifyAdapter,
|
|
NestFastifyApplication,
|
|
} from '@nestjs/platform-fastify';
|
|
import { ValidationPipe, Logger } from '@nestjs/common';
|
|
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
|
import { AppModule } from './app.module';
|
|
import compression from '@fastify/compress';
|
|
import helmet from '@fastify/helmet';
|
|
import cookie from '@fastify/cookie';
|
|
|
|
async function bootstrap() {
|
|
const dbUrl = process.env.DATABASE_URL || 'NOT_SET';
|
|
console.log(`[DEBUG] DATABASE_URL loaded: ${dbUrl.replace(/:[^:]*@/, ':***@')}`); // Mask password
|
|
|
|
// Create Fastify adapter with Pino logging
|
|
const adapter = new FastifyAdapter({
|
|
logger: {
|
|
level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
|
|
transport:
|
|
process.env.NODE_ENV !== 'production'
|
|
? { target: 'pino-pretty', options: { colorize: true } }
|
|
: undefined,
|
|
},
|
|
trustProxy: true, // Required for getting real IP behind reverse proxy
|
|
bodyLimit: 10 * 1024 * 1024, // 10MB
|
|
});
|
|
|
|
const app = await NestFactory.create<NestFastifyApplication>(
|
|
AppModule,
|
|
adapter,
|
|
{ rawBody: true },
|
|
);
|
|
|
|
// Register Fastify plugins
|
|
await app.register(compression, { encodings: ['gzip', 'deflate'] });
|
|
await app.register(helmet, {
|
|
contentSecurityPolicy: process.env.NODE_ENV === 'production',
|
|
});
|
|
await app.register(cookie); // Enable cookie parsing for JWT auth
|
|
|
|
// CORS configuration (Fastify-native)
|
|
app.enableCors({
|
|
origin: (origin, callback) => {
|
|
// Parse CORS_ORIGINS from env (comma-separated)
|
|
const envOrigins = process.env.CORS_ORIGINS?.split(',').map(o => o.trim()) || [];
|
|
const allowedOrigins = [
|
|
'http://localhost:3000',
|
|
'http://localhost:8963',
|
|
...envOrigins,
|
|
].filter(Boolean);
|
|
|
|
if (!origin || allowedOrigins.includes(origin)) {
|
|
callback(null, true);
|
|
} else {
|
|
callback(new Error('Not allowed by CORS'), false);
|
|
}
|
|
},
|
|
credentials: true,
|
|
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
|
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
|
|
maxAge: 86400, // 24 hours preflight cache
|
|
});
|
|
|
|
// Global validation pipe
|
|
app.useGlobalPipes(
|
|
new ValidationPipe({
|
|
whitelist: true,
|
|
transform: true,
|
|
forbidNonWhitelisted: true,
|
|
transformOptions: { enableImplicitConversion: true },
|
|
}),
|
|
);
|
|
|
|
// Swagger documentation
|
|
const config = new DocumentBuilder()
|
|
.setTitle('GoHorse Backoffice API')
|
|
.setDescription('SaaS Administration and Subscription Management')
|
|
.setVersion('1.0')
|
|
.addTag('Stripe')
|
|
.addTag('Plans')
|
|
.addTag('Admin Dashboard')
|
|
.addBearerAuth()
|
|
.build();
|
|
|
|
SwaggerModule.setup('docs', app, SwaggerModule.createDocument(app, config));
|
|
|
|
// Health check endpoint
|
|
const fastifyInstance = app.getHttpAdapter().getInstance();
|
|
fastifyInstance.get('/health', async () => ({ status: 'ok', timestamp: new Date().toISOString() }));
|
|
|
|
// Start server
|
|
const port = process.env.BACKOFFICE_PORT || 3001;
|
|
const host = '0.0.0.0'; // Force 0.0.0.0 to allow container binding even if env injects public IP
|
|
|
|
await app.listen(port, host);
|
|
|
|
const logger = new Logger('Bootstrap');
|
|
logger.log(`🚀 Backoffice API running on: http://${host}:${port}`);
|
|
logger.log(`📚 Swagger docs: http://${host}:${port}/api/docs`);
|
|
logger.log(`❤️ Health check: http://${host}:${port}/health`);
|
|
}
|
|
|
|
void bootstrap();
|