import express from 'express' import path from 'path' import cors from 'cors' import helmet from 'helmet' import morgan from 'morgan' import compression from 'compression' import { errorHandler } from './middleware/errorHandler' import { apiLimiter } from './middleware/rateLimit' import logger from './lib/logger' const app = express() app.set('trust proxy', 1) app.use(helmet()) app.use(compression({ filter: (req, res) => { // SSE 流式响应不压缩,避免缓冲导致前端一次性收到所有数据 if (req.headers['accept'] === 'text/event-stream' || res.getHeader('Content-Type') === 'text/event-stream') { return false } return compression.filter(req, res) }, })) app.use( cors({ origin: true, credentials: true, exposedHeaders: ['Content-Disposition'], }), ) app.use(express.json({ limit: '10mb' })) app.use(morgan('dev')) app.get('/health', (_req, res) => { res.json({ success: true, data: { status: 'ok', timestamp: new Date().toISOString() } }) }) // deploy.sh 验证脚本检查 /api/v1/health app.get('/api/v1/health', (_req, res) => { res.json({ success: true, data: { status: 'ok', timestamp: new Date().toISOString() } }) }) app.use('/api/v1', apiLimiter) // 路由挂载 import authRoutes from './routes/auth.routes' import dashboardRoutes from './routes/dashboard.routes' import employeeRoutes from './routes/employee.routes' import terminationRoutes from './routes/termination.routes' import aiRoutes from './routes/ai.routes' import portalRoutes from './routes/portal.routes' import settingsRoutes from './routes/settings.routes' import payrollRoutes from './routes/payroll.routes' import payroll2Routes from './routes/payroll2.routes' import socialRoutes from './routes/social.routes' import notificationRoutes from './routes/notification.routes' import attachmentRoutes from './routes/attachment.routes' import rosterRoutes from './routes/roster.routes' import exportRoutes from './routes/export.routes' import importRoutes from './routes/import.routes' import evidenceRoutes from './routes/evidence.routes' import policyRoutes from './routes/policy.routes' import attendanceRoutes from './routes/attendance.routes' import templateRoutes from './routes/template.routes' import auditRoutes from './routes/audit.routes' import calendarRoutes from './routes/calendar.routes' import platformRoutes from './routes/platform.routes' import workProcessRoutes from './routes/work-process.routes' import departmentRoutes from './routes/department.routes' import positionRoutes from './routes/position.routes' import approvalRoutes from './routes/approval.routes' import supportRoutes from './routes/support.routes' import enterpriseTemplateRoutes from './routes/enterprise-template.routes' import specialStatusRoutes from './routes/special-status.routes' import companyFileRoutes from './routes/company-file.routes' import acceptanceTestRoutes from './routes/acceptance-test.routes' import leaveRoutes from './routes/leave.routes' import salaryRoutes from './routes/salary.routes' import commercialInsuranceRoutes from './routes/commercial-insurance.routes' import benefitRoutes from './routes/benefit.routes' import esignRoutes from './routes/esign.routes' app.use('/api/v1/auth', authRoutes) app.use('/api/v1/dashboard', dashboardRoutes) app.use('/api/v1/employees', employeeRoutes) app.use('/api/v1/termination', terminationRoutes) app.use('/api/v1/ai', aiRoutes) app.use('/api/v1/portal', portalRoutes) app.use('/api/v1/settings', settingsRoutes) app.use('/api/v1/payroll', payrollRoutes) app.use('/api/v1/payroll2', payroll2Routes) app.use('/api/v1/social', socialRoutes) app.use('/api/v1/notifications', notificationRoutes) app.use('/api/v1/attachments', attachmentRoutes) app.use('/api/v1/roster', rosterRoutes) app.use('/api/v1/export', exportRoutes) app.use('/api/v1/import', importRoutes) app.use('/api/v1/evidence', evidenceRoutes) app.use('/api/v1/policies', policyRoutes) app.use('/api/v1/attendance', attendanceRoutes) app.use('/api/v1/templates', templateRoutes) app.use('/api/v1/audit', auditRoutes) app.use('/api/v1/calendar', calendarRoutes) app.use('/api/v1/platform', platformRoutes) app.use('/api/v1/work-processes', workProcessRoutes) app.use('/api/v1/departments', departmentRoutes) app.use('/api/v1/positions', positionRoutes) app.use('/api/v1/approvals', approvalRoutes) app.use('/api/v1/support', supportRoutes) app.use('/api/v1/enterprise-templates', enterpriseTemplateRoutes) app.use('/api/v1/special-statuses', specialStatusRoutes) app.use('/api/v1/company-files', companyFileRoutes) app.use('/api/v1/acceptance-tests', acceptanceTestRoutes) app.use('/api/v1/leaves', leaveRoutes) app.use('/api/v1/salary', salaryRoutes) app.use('/api/v1/commercial-insurance', commercialInsuranceRoutes) app.use('/api/v1/benefits', benefitRoutes) app.use('/api/v1/esign', esignRoutes) // 静态文件服务:上传的文件(入职文件、工会回执等) app.use('/uploads', express.static(path.join(process.cwd(), 'uploads'))) app.use(errorHandler) // RAG 知识库自动初始化(异步,不阻塞启动) import { seedKnowledgeBase } from './services/rag.service' seedKnowledgeBase().catch((err) => { logger.warn({ err }, 'RAG 知识库初始化失败,AI 问答将不使用 RAG 检索') }) export default app