1e25022630
Modulo clinic (habilitado por usuario): citas de pacientes para medicos con choques bloqueantes (medico, paciente con cualquier medico, quirofano/bloqueos recurrentes y horario de atencion), validados en transaccion con bloqueo de filas para que dos recepcionistas no tomen el mismo hueco. Recepcion (alcance todos) y medico (alcance propio). Vista Dia por columnas de medico, Semana y Lista; pacientes con historial; bloqueos; configuracion de personal, horarios y tipos solo admin/superadmin. Capa de citas en el calendario personal del medico. Migracion 036. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
86 lines
4.2 KiB
JavaScript
86 lines
4.2 KiB
JavaScript
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 { accountEmailRoutes, usersEmailRoutes, publicEmailRoutes } from './modules/email-change/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';
|
|
import meetingsRoutes from './modules/meetings/routes.js';
|
|
import clinicRoutes from './modules/clinic/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/email-change', publicEmailRoutes);
|
|
app.use('/api/account/email-change', accountEmailRoutes);
|
|
app.use('/api/users/email-change-requests', usersEmailRoutes);
|
|
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);
|
|
app.use('/api/meetings', meetingsRoutes);
|
|
app.use('/api/clinic', clinicRoutes);
|
|
// 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);
|