import express from 'express'; import cors from 'cors'; import helmet from 'helmet'; import { env } from './config/env.js'; import { notFoundHandler, errorHandler } from './middleware/errorHandler.js'; import authRoutes from './modules/auth/routes.js'; import usersRoutes from './modules/users/routes.js'; import departmentsRoutes from './modules/departments/routes.js'; import catalogsRoutes from './modules/catalogs/routes.js'; import projectsRoutes from './modules/projects/routes.js'; import activitiesRoutes from './modules/activities/routes.js'; import tasksRoutes from './modules/tasks/routes.js'; import commentsRoutes from './modules/comments/routes.js'; import attachmentsRoutes from './modules/attachments/routes.js'; import notificationsRoutes from './modules/notifications/routes.js'; import dashboardRoutes from './modules/dashboard/routes.js'; import auditRoutes from './modules/audit/routes.js'; import settingsRoutes from './modules/settings/routes.js'; import companyRoutes from './modules/company/routes.js'; import recurringTasksRoutes from './modules/recurring-tasks/routes.js'; import searchRoutes from './modules/search/routes.js'; import updaterRoutes from './modules/updater/routes.js'; import errorLogsRoutes from './modules/errorLogs/routes.js'; import notesRoutes from './modules/notes/routes.js'; import vaultRoutes from './modules/vault/routes.js'; import devicesRoutes from './modules/devices/routes.js'; import inventoryIngestRoutes from './modules/devices/ingest.js'; import aiRoutes from './modules/ai/routes.js'; export const app = express(); // Produccion (y exilaser) corren detras de Nginx Proxy Manager (un solo salto). Sin esto, // express-rate-limit usa la IP del proxy para TODOS los clientes (un balde compartido en vez // de uno por usuario) y ademas tira un ValidationError que ensucia los logs en cada request. app.set('trust proxy', 1); app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'], fontSrc: ["'self'", 'https://fonts.gstatic.com'], imgSrc: ["'self'", 'data:', 'blob:'], connectSrc: ["'self'"], objectSrc: ["'none'"], baseUri: ["'self'"], frameAncestors: ["'none'"], } } })); app.use(cors({ origin: env.corsOrigin, credentials: true, exposedHeaders: ['X-Vault-Token'] })); // Ingesta del agente GLPI: ANTES del parser JSON (usa cuerpo crudo, sin CORS: la llama el agente). app.use(inventoryIngestRoutes); app.use(express.json({ limit: '2mb' })); app.get('/health', (req, res) => res.json({ success: true, data: { status: 'ok' }, error: null })); app.use('/api/auth', authRoutes); app.use('/api/users', usersRoutes); app.use('/api/departments', departmentsRoutes); app.use('/api/catalogs', catalogsRoutes); app.use('/api/projects', projectsRoutes); app.use('/api/activities', activitiesRoutes); app.use('/api/comments', commentsRoutes); app.use('/api/attachments', attachmentsRoutes); app.use('/api/notifications', notificationsRoutes); app.use('/api/dashboard', dashboardRoutes); app.use('/api/audit', auditRoutes); app.use('/api/settings', settingsRoutes); app.use('/api/company', companyRoutes); app.use('/api/recurring-tasks', recurringTasksRoutes); app.use('/api/search', searchRoutes); app.use('/api/updater', updaterRoutes); app.use('/api/error-logs', errorLogsRoutes); app.use('/api/notes', notesRoutes); app.use('/api/vault', vaultRoutes); app.use('/api/devices', devicesRoutes); app.use('/api/ai', aiRoutes); // Mas generico (mount en /api sin sub-path propio) — SIEMPRE al final de los /api/*, para no // interceptar con su requireAuth interno una ruta que en realidad pertenece a un router mas // especifico registrado despues (ver ESTADO.md, deuda tecnica). app.use('/api', tasksRoutes); app.use(notFoundHandler); app.use(errorHandler);