mirror of
http://172.20.10.11:3000/gitadmin/INSIGHT-MVP.git
synced 2026-06-25 05:56:39 +02:00
Full-stack implementation of the Expert Profile tab with 6 sections: - Skills (tag/chip UI with add/remove) - Experience (area, years, optional level) - Languages (language + proficiency level) - Project History (modal form with dates, role, tasks, company details) - Certifications (modal form with title, issuer, website, year) - Attachments (file upload/download as Base64, max 10MB) Backend: 15 API endpoints, 8 DTOs, full CRUD service with ownership verification. Frontend: Reusable Modal component (React Portal), ExpertProfileTab orchestrator, 8 section components. Database: 6 new tables (expert_profiles, expert_experiences, expert_languages, expert_projects, expert_certifications, expert_attachments). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
import { NestFactory } from '@nestjs/core';
|
|
import { ValidationPipe, Logger } from '@nestjs/common';
|
|
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
|
import cookieParser from 'cookie-parser';
|
|
import helmet from 'helmet';
|
|
import { json } from 'express';
|
|
import { AppModule } from './app.module';
|
|
|
|
async function bootstrap(): Promise<void> {
|
|
const logger = new Logger('Bootstrap');
|
|
const app = await NestFactory.create(AppModule, {
|
|
logger: ['error', 'warn', 'log', 'debug', 'verbose'],
|
|
});
|
|
|
|
// Security
|
|
app.use(helmet());
|
|
app.use(cookieParser());
|
|
|
|
// Body size limit für Base64-Uploads (Avatare, Profilanlagen bis 10MB)
|
|
app.use(json({ limit: '12mb' }));
|
|
|
|
// CORS
|
|
const corsOrigins = process.env.CORS_ORIGINS?.split(',') ?? [
|
|
'http://172.20.10.59',
|
|
];
|
|
app.enableCors({
|
|
origin: corsOrigins,
|
|
credentials: true,
|
|
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
|
allowedHeaders: [
|
|
'Content-Type',
|
|
'Authorization',
|
|
'X-Tenant-ID',
|
|
'X-Request-ID',
|
|
],
|
|
});
|
|
|
|
// Global Validation Pipe (Sicherheitsregel: whitelist + forbidNonWhitelisted)
|
|
app.useGlobalPipes(
|
|
new ValidationPipe({
|
|
whitelist: true,
|
|
forbidNonWhitelisted: true,
|
|
transform: true,
|
|
transformOptions: { enableImplicitConversion: true },
|
|
}),
|
|
);
|
|
|
|
// Global Prefix
|
|
app.setGlobalPrefix('api/v1', {
|
|
exclude: ['health'],
|
|
});
|
|
|
|
// Swagger (nur Development)
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
const config = new DocumentBuilder()
|
|
.setTitle('INSIGHT Platform API')
|
|
.setDescription('Multi-Tenant Business Platform API')
|
|
.setVersion('0.1.0')
|
|
.addBearerAuth(
|
|
{
|
|
type: 'http',
|
|
scheme: 'bearer',
|
|
bearerFormat: 'JWT',
|
|
description: 'Access Token (RS256)',
|
|
},
|
|
'access-token',
|
|
)
|
|
.addCookieAuth('refresh_token', {
|
|
type: 'apiKey',
|
|
in: 'cookie',
|
|
description: 'HttpOnly Refresh Token',
|
|
})
|
|
.build();
|
|
|
|
const document = SwaggerModule.createDocument(app, config);
|
|
SwaggerModule.setup('api/docs', app, document);
|
|
logger.log('Swagger UI: /api/docs');
|
|
}
|
|
|
|
const port = process.env.APP_PORT ?? 3000;
|
|
await app.listen(port);
|
|
logger.log(`Core-Service laeuft auf Port ${port}`);
|
|
logger.log(`Umgebung: ${process.env.NODE_ENV ?? 'development'}`);
|
|
}
|
|
|
|
bootstrap();
|