/** * Server Entry Point * MVP Sistema Administración de Obra e INFONAVIT * * @author Backend-Agent * @date 2025-11-20 */ import 'reflect-metadata'; import express, { Application } from 'express'; import cors from 'cors'; import helmet from 'helmet'; import morgan from 'morgan'; import dotenv from 'dotenv'; import { AppDataSource } from './shared/database/typeorm.config'; // Cargar variables de entorno dotenv.config(); const app: Application = express(); const PORT = process.env.APP_PORT || 3000; const API_VERSION = process.env.API_VERSION || 'v1'; /** * Middlewares */ app.use(helmet()); // Seguridad HTTP headers app.use(cors({ origin: process.env.CORS_ORIGIN?.split(',') || '*', credentials: process.env.CORS_CREDENTIALS === 'true', })); app.use(morgan(process.env.LOG_FORMAT || 'dev')); // Logging app.use(express.json()); // Parse JSON bodies app.use(express.urlencoded({ extended: true })); // Parse URL-encoded bodies /** * Health Check */ app.get('/health', (_req, res) => { res.status(200).json({ status: 'ok', timestamp: new Date().toISOString(), environment: process.env.NODE_ENV || 'development', version: API_VERSION, }); }); /** * API Routes */ import { proyectoController, fraccionamientoController, createEtapaController, createManzanaController, createLoteController, createPrototipoController } from './modules/construction/controllers'; import { createAuthController } from './modules/auth/controllers/auth.controller'; import { createUsersController } from './modules/users/controllers/users.controller'; import { createConceptoController, createPresupuestoController } from './modules/budgets/controllers'; import { createAvanceObraController, createBitacoraObraController } from './modules/progress/controllers'; import { createEstimacionController, createAnticipoController, createFondoGarantiaController, createRetencionController } from './modules/estimates/controllers'; import { createPuestoController, createEmployeeController } from './modules/hr/controllers'; import { createCapacitacionController, createIncidenteController } from './modules/hse/controllers'; import { createRequisicionController, createConsumoObraController } from './modules/inventory/controllers'; import { createComparativoController } from './modules/purchase/controllers'; import { createDerechohabienteController, createAsignacionController } from './modules/infonavit/controllers'; import { createInspectionController, createTicketController } from './modules/quality/controllers'; import { createContractController, createSubcontractorController } from './modules/contracts/controllers'; import { createReportController, createDashboardController, createKpiController } from './modules/reports/controllers'; import { createCostCenterController, createAuditLogController, createSystemSettingController, createBackupController } from './modules/admin/controllers'; import { createOpportunityController, createBidController, createBidBudgetController, createBidAnalyticsController } from './modules/bidding/controllers'; // TEMPORARILY DISABLED - Finance module requires structural fixes // import { createAccountingController, createAPController, createARController, createCashFlowController, createBankReconciliationController, createReportsController } from './modules/finance/controllers'; // Root API info app.get(`/api/${API_VERSION}`, (_req, res) => { res.status(200).json({ message: 'API MVP Sistema Administración de Obra', version: API_VERSION, endpoints: { health: '/health', docs: `/api/${API_VERSION}/docs`, auth: `/api/${API_VERSION}/auth`, users: `/api/${API_VERSION}/users`, proyectos: `/api/${API_VERSION}/proyectos`, fraccionamientos: `/api/${API_VERSION}/fraccionamientos`, etapas: `/api/${API_VERSION}/etapas`, manzanas: `/api/${API_VERSION}/manzanas`, lotes: `/api/${API_VERSION}/lotes`, prototipos: `/api/${API_VERSION}/prototipos`, conceptos: `/api/${API_VERSION}/conceptos`, presupuestos: `/api/${API_VERSION}/presupuestos`, avances: `/api/${API_VERSION}/avances`, bitacora: `/api/${API_VERSION}/bitacora`, estimaciones: `/api/${API_VERSION}/estimaciones`, anticipos: `/api/${API_VERSION}/anticipos`, 'fondos-garantia': `/api/${API_VERSION}/fondos-garantia`, retenciones: `/api/${API_VERSION}/retenciones`, puestos: `/api/${API_VERSION}/puestos`, empleados: `/api/${API_VERSION}/empleados`, capacitaciones: `/api/${API_VERSION}/capacitaciones`, incidentes: `/api/${API_VERSION}/incidentes`, requisiciones: `/api/${API_VERSION}/requisiciones`, consumos: `/api/${API_VERSION}/consumos`, comparativos: `/api/${API_VERSION}/comparativos`, derechohabientes: `/api/${API_VERSION}/derechohabientes`, asignaciones: `/api/${API_VERSION}/asignaciones`, inspections: `/api/${API_VERSION}/inspections`, tickets: `/api/${API_VERSION}/tickets`, contracts: `/api/${API_VERSION}/contracts`, subcontractors: `/api/${API_VERSION}/subcontractors`, reports: `/api/${API_VERSION}/reports`, dashboards: `/api/${API_VERSION}/dashboards`, kpis: `/api/${API_VERSION}/kpis`, 'cost-centers': `/api/${API_VERSION}/cost-centers`, 'audit-logs': `/api/${API_VERSION}/audit-logs`, settings: `/api/${API_VERSION}/settings`, backups: `/api/${API_VERSION}/backups`, opportunities: `/api/${API_VERSION}/opportunities`, bids: `/api/${API_VERSION}/bids`, 'bid-budgets': `/api/${API_VERSION}/bid-budgets`, 'bid-analytics': `/api/${API_VERSION}/bid-analytics`, accounting: `/api/${API_VERSION}/accounting`, 'accounts-payable': `/api/${API_VERSION}/accounts-payable`, 'accounts-receivable': `/api/${API_VERSION}/accounts-receivable`, 'cash-flow': `/api/${API_VERSION}/cash-flow`, 'bank-reconciliation': `/api/${API_VERSION}/bank-reconciliation`, 'financial-reports': `/api/${API_VERSION}/financial-reports`, }, }); }); // Construction Module Routes app.use(`/api/${API_VERSION}/proyectos`, proyectoController); app.use(`/api/${API_VERSION}/fraccionamientos`, fraccionamientoController); // Auth y Users Module Routes - Se inicializan después de la conexión a BD let authController: ReturnType; let usersController: ReturnType; /** * 404 Handler */ app.use((req, res) => { res.status(404).json({ error: 'Not Found', message: `Cannot ${req.method} ${req.path}`, }); }); /** * Error Handler */ app.use((err: Error, _req: express.Request, res: express.Response, _next: express.NextFunction) => { console.error('Error:', err); res.status(500).json({ error: 'Internal Server Error', message: process.env.NODE_ENV === 'development' ? err.message : 'Something went wrong', }); }); /** * Inicializar Base de Datos y Servidor */ async function bootstrap() { try { // Conectar a base de datos console.log('🔌 Conectando a base de datos...'); await AppDataSource.initialize(); console.log('✅ Base de datos conectada'); // Inicializar Auth Controller (requiere DataSource) authController = createAuthController(AppDataSource); app.use(`/api/${API_VERSION}/auth`, authController); console.log('🔐 Auth module inicializado'); // Inicializar Users Controller (requiere DataSource) usersController = createUsersController(AppDataSource); app.use(`/api/${API_VERSION}/users`, usersController); console.log('👥 Users module inicializado'); // Inicializar Construction Controllers (requieren DataSource para auth) const etapaController = createEtapaController(AppDataSource); app.use(`/api/${API_VERSION}/etapas`, etapaController); const manzanaController = createManzanaController(AppDataSource); app.use(`/api/${API_VERSION}/manzanas`, manzanaController); const loteController = createLoteController(AppDataSource); app.use(`/api/${API_VERSION}/lotes`, loteController); const prototipoController = createPrototipoController(AppDataSource); app.use(`/api/${API_VERSION}/prototipos`, prototipoController); console.log('🏗️ Construction module inicializado'); // Inicializar Budgets Controllers (requieren DataSource para auth) const conceptoController = createConceptoController(AppDataSource); app.use(`/api/${API_VERSION}/conceptos`, conceptoController); const presupuestoController = createPresupuestoController(AppDataSource); app.use(`/api/${API_VERSION}/presupuestos`, presupuestoController); console.log('💰 Budgets module inicializado'); // Inicializar Progress Controllers (requieren DataSource para auth) const avanceObraController = createAvanceObraController(AppDataSource); app.use(`/api/${API_VERSION}/avances`, avanceObraController); const bitacoraObraController = createBitacoraObraController(AppDataSource); app.use(`/api/${API_VERSION}/bitacora`, bitacoraObraController); console.log('📊 Progress module inicializado'); // Inicializar Estimates Controllers (requieren DataSource para auth) const estimacionController = createEstimacionController(AppDataSource); app.use(`/api/${API_VERSION}/estimaciones`, estimacionController); const anticipoController = createAnticipoController(AppDataSource); app.use(`/api/${API_VERSION}/anticipos`, anticipoController); const fondoGarantiaController = createFondoGarantiaController(AppDataSource); app.use(`/api/${API_VERSION}/fondos-garantia`, fondoGarantiaController); const retencionController = createRetencionController(AppDataSource); app.use(`/api/${API_VERSION}/retenciones`, retencionController); console.log('📝 Estimates module inicializado'); // Inicializar HR Controllers (requieren DataSource para auth) const puestoController = createPuestoController(AppDataSource); app.use(`/api/${API_VERSION}/puestos`, puestoController); const employeeController = createEmployeeController(AppDataSource); app.use(`/api/${API_VERSION}/empleados`, employeeController); console.log('👷 HR module inicializado'); // Inicializar HSE Controllers (requieren DataSource para auth) const capacitacionController = createCapacitacionController(AppDataSource); app.use(`/api/${API_VERSION}/capacitaciones`, capacitacionController); const incidenteController = createIncidenteController(AppDataSource); app.use(`/api/${API_VERSION}/incidentes`, incidenteController); console.log('🦺 HSE module inicializado'); // Inicializar Inventory Controllers (requieren DataSource para auth) const requisicionController = createRequisicionController(AppDataSource); app.use(`/api/${API_VERSION}/requisiciones`, requisicionController); const consumoObraController = createConsumoObraController(AppDataSource); app.use(`/api/${API_VERSION}/consumos`, consumoObraController); console.log('📦 Inventory module inicializado'); // Inicializar Purchase Controllers (requieren DataSource para auth) const comparativoController = createComparativoController(AppDataSource); app.use(`/api/${API_VERSION}/comparativos`, comparativoController); console.log('🛒 Purchase module inicializado'); // Inicializar Infonavit Controllers (requieren DataSource para auth) const derechohabienteController = createDerechohabienteController(AppDataSource); app.use(`/api/${API_VERSION}/derechohabientes`, derechohabienteController); const asignacionController = createAsignacionController(AppDataSource); app.use(`/api/${API_VERSION}/asignaciones`, asignacionController); console.log('🏠 Infonavit module inicializado'); // Inicializar Quality Controllers (requieren DataSource para auth) const inspectionController = createInspectionController(AppDataSource); app.use(`/api/${API_VERSION}/inspections`, inspectionController); const ticketController = createTicketController(AppDataSource); app.use(`/api/${API_VERSION}/tickets`, ticketController); console.log('✅ Quality module inicializado'); // Inicializar Contracts Controllers (requieren DataSource para auth) const contractController = createContractController(AppDataSource); app.use(`/api/${API_VERSION}/contracts`, contractController); const subcontractorController = createSubcontractorController(AppDataSource); app.use(`/api/${API_VERSION}/subcontractors`, subcontractorController); console.log('📄 Contracts module inicializado'); // Inicializar Reports Controllers (requieren DataSource para auth) const reportController = createReportController(AppDataSource); app.use(`/api/${API_VERSION}/reports`, reportController); const dashboardController = createDashboardController(AppDataSource); app.use(`/api/${API_VERSION}/dashboards`, dashboardController); const kpiController = createKpiController(AppDataSource); app.use(`/api/${API_VERSION}/kpis`, kpiController); console.log('📈 Reports module inicializado'); // Inicializar Admin Controllers (requieren DataSource para auth) const costCenterController = createCostCenterController(AppDataSource); app.use(`/api/${API_VERSION}/cost-centers`, costCenterController); const auditLogController = createAuditLogController(AppDataSource); app.use(`/api/${API_VERSION}/audit-logs`, auditLogController); const systemSettingController = createSystemSettingController(AppDataSource); app.use(`/api/${API_VERSION}/settings`, systemSettingController); const backupController = createBackupController(AppDataSource); app.use(`/api/${API_VERSION}/backups`, backupController); console.log('⚙️ Admin module inicializado'); // Inicializar Bidding Controllers (requieren DataSource para auth) const opportunityController = createOpportunityController(AppDataSource); app.use(`/api/${API_VERSION}/opportunities`, opportunityController); const bidController = createBidController(AppDataSource); app.use(`/api/${API_VERSION}/bids`, bidController); const bidBudgetController = createBidBudgetController(AppDataSource); app.use(`/api/${API_VERSION}/bid-budgets`, bidBudgetController); const bidAnalyticsController = createBidAnalyticsController(AppDataSource); app.use(`/api/${API_VERSION}/bid-analytics`, bidAnalyticsController); console.log('📋 Bidding module inicializado'); // TEMPORARILY DISABLED - Finance module requires structural fixes // Inicializar Finance Controllers (requieren DataSource para auth) // const accountingController = createAccountingController(AppDataSource); // app.use(`/api/${API_VERSION}/accounting`, accountingController); // const apController = createAPController(AppDataSource); // app.use(`/api/${API_VERSION}/accounts-payable`, apController); // const arController = createARController(AppDataSource); // app.use(`/api/${API_VERSION}/accounts-receivable`, arController); // const cashFlowController = createCashFlowController(AppDataSource); // app.use(`/api/${API_VERSION}/cash-flow`, cashFlowController); // const bankReconciliationController = createBankReconciliationController(AppDataSource); // app.use(`/api/${API_VERSION}/bank-reconciliation`, bankReconciliationController); // const financialReportsController = createReportsController(AppDataSource); // app.use(`/api/${API_VERSION}/financial-reports`, financialReportsController); console.log('💵 Finance module DISABLED - pending structural fixes'); // Iniciar servidor app.listen(PORT, () => { console.log('🚀 Servidor iniciado'); console.log(`📍 URL: http://localhost:${PORT}`); console.log(`📍 API: http://localhost:${PORT}/api/${API_VERSION}`); console.log(`📍 Health: http://localhost:${PORT}/health`); console.log(`🌍 Entorno: ${process.env.NODE_ENV || 'development'}`); }); } catch (error) { console.error('❌ Error al iniciar servidor:', error); process.exit(1); } } // Iniciar aplicación bootstrap(); export default app;