import { NestFactory } from '@nestjs/core'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { AppModule } from './app.module'; import helmet from 'helmet'; import { ConfigService } from '@nestjs/config'; import { NestExpressApplication } from '@nestjs/platform-express'; async function bootstrap() { const app = await NestFactory.create(AppModule); const configService = app.get(ConfigService); const isProduction = configService.get('app.nodeEnv') === 'production'; app.use(helmet()); app.setGlobalPrefix('api', { exclude: ['health', 'admin-api/(.*)', 'internal/(.*)'] }); app.enableCors({ origin: isProduction ? [configService.get('app.allowedOrigin', 'https://longde.cloud')] : ['https://longde.cloud', 'http://localhost:4321', 'http://localhost:5173'], methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], credentials: true, maxAge: 86400, }); app.useBodyParser('json', { limit: '10mb' }); const swaggerEnabled = !isProduction || configService.get('app.enableSwagger') === true; if (swaggerEnabled) { const config = new DocumentBuilder() .setTitle('知习 API') .setDescription('知习 AI-first 系统化学习产品后端 API') .setVersion('0.1.0') .addBearerAuth() .addTag('health', '服务健康检查') .addTag('auth', '用户认证') .addTag('admin-auth', '管理员认证') .addTag('users', '用户管理') .addTag('knowledge-base', '知识库') .addTag('knowledge-items', '知识点') .addTag('document-import', '资料导入') .addTag('learning-session', '学习会话') .addTag('active-recall', '主动回忆') .addTag('ai-analysis', 'AI 分析') .addTag('review', '复习管理') .addTag('focus-items', '待巩固项') .addTag('learning-activity', '学习活跃') .addTag('notifications', '消息通知') .addTag('feedback', '用户反馈') .addTag('files', '文件管理') .addTag('waitlist', '等待名单') .build(); const document = SwaggerModule.createDocument(app, config); if (isProduction) { const swaggerUser = configService.get('app.swaggerUser', 'admin'); const swaggerPassword = configService.get('app.swaggerPassword'); if (swaggerPassword) { const basicAuthMiddleware = (req: any, res: any, next: any) => { const auth = req.headers.authorization; if (!auth?.startsWith('Basic ')) { res.setHeader('WWW-Authenticate', 'Basic'); return res.status(401).send('Authentication required'); } const [user, pass] = Buffer.from(auth.split(' ')[1], 'base64') .toString() .split(':'); if (user === swaggerUser && pass === swaggerPassword) { return next(); } return res.status(401).send('Invalid credentials'); }; app.use('/api-docs', basicAuthMiddleware); app.use('/api-docs-json', basicAuthMiddleware); } } SwaggerModule.setup('api-docs', app, document, { swaggerOptions: { persistAuthorization: true }, customCss: '.swagger-ui .topbar { display: none }', customSiteTitle: '知习 API 文档', }); app.getHttpAdapter().get('/api-docs-json', (_req: any, res: any) => { res.json(document); }); console.log('[Swagger] API 文档已启用'); } app.enableShutdownHooks(); const port = configService.get('app.port', 3000); await app.listen(port); console.log(`[API] Server running on http://localhost:${port}`); } bootstrap();