# 📘 DOCUMENTACIÓN TÉCNICA — Sistema Hotel Hacienda San Angel > **Versión:** 1.0 > **Fecha:** 2026-06-09 > **Proyecto:** `/home/Hotel` > **Autor:** Análisis automático del codebase --- ## 1. RESUMEN EJECUTIVO Este es un **sistema administrativo financiero y operativo** para un hotel ("Hacienda San Angel"). Gestiona: - **Ingresos** (Little Hotelier, Stripe, facturas electrónicas, Horux) - **Gastos** (aprovisionamiento, pagos mensuales, aprobaciones) - **Nómina** (empleados, contratos, asistencia) - **Inventario** (productos, ajustes, salidas, descartes) - **P&L** (Hotel y Restaurante) - **Configuraciones** (habitaciones, propiedades, catálogos) **Arquitectura:** Monolito clásico. Backend liviano en Express que **delega casi toda la lógica de negocio a PostgreSQL mediante funciones SQL**. Frontend SPA en React con Vite. **⚠️ Advertencia crítica:** No hay ORM. Los controllers solo orquestan llamadas a funciones SQL. Si modificas algo en el backend sin conocer la función PostgreSQL correspondiente, romperás el sistema. --- ## 2. STACK TECNOLÓGICO ### Backend (`/home/Hotel/backend/hotel_hacienda/`) | Capa | Tecnología | Versión | |------|-----------|---------| | Runtime | Node.js | — | | Framework | Express.js | ^5.1.0 | | Base de datos | PostgreSQL | — | | Driver DB | `pg` (node-postgres) | ^8.16.3 | | ORM | **NINGUNO** | — | | HTTP client | Axios | ^1.13.2 | | Email | Nodemailer | ^7.0.12 | | Pagos | Stripe SDK | ^20.1.0 | | Excel/CSV | `xlsx`, `csv-parser` | ^0.18.5, ^3.2.0 | | Validación | `express-validator` | ^7.2.1 | | Dev | Nodemon | ^3.1.10 | ### Frontend (`/home/Hotel/frontend/Frontend-Hotel/`) | Capa | Tecnología | Versión | |------|-----------|---------| | Framework | React | ^19.1.1 | | Build tool | Vite | ^7.1.2 | | Router | `react-router-dom` | ^7.8.2 | | Estilos | Tailwind CSS + Bootstrap 5 + CSS puro | ^4.1.13, ^5.3.8 | | Forms | `react-hook-form` + Yup | ^7.66.1, ^1.7.1 | | HTTP | Axios + `fetch` nativo | ^1.11.0 | | Estado global | React Context API | — | | Excel export | `xlsx` | ^0.18.5 | | Íconos | `react-icons` | ^5.5.0 | --- ## 3. ESTRUCTURA DE CARPETAS ### Backend ``` hotel_hacienda/ ├── index.js # Solo requiere src/server.js ├── src/ │ ├── server.js # Levanta servidor en PORT │ ├── app.js # Config Express, CORS, monta rutas /api/* │ ├── db/ │ │ └── connection.js # Pool de PostgreSQL (pg) │ ├── middlewares/ │ │ ├── handleValidation.js │ │ └── validators.js # Solo valida login por ahora │ ├── routes/ # 16 archivos de rutas │ ├── controllers/ # 18 archivos de controllers │ └── services/ │ └── mailService.js # Transporte Nodemailer ``` ### Frontend ``` Frontend-Hotel/ ├── index.html ├── vite.config.js ├── src/ │ ├── main.jsx # Entry point (AuthProvider > LangProvider > BrowserRouter) │ ├── App.jsx # Definición de todas las rutas │ ├── index.css # Tailwind directives + estilos base │ ├── constants/ │ │ └── menuconfig.js # Menú de navegación con permisos │ ├── context/ │ │ ├── AuthContext.jsx # Estado de usuario (rol en localStorage) │ │ └── LenguageContext.jsx # Idioma EN/ES │ ├── components/ │ │ ├── Layout2.jsx # Layout activo (Sidebar + Topbar + Outlet) │ │ ├── Sidebar.jsx │ │ ├── Table/ │ │ │ └── HotelTable.jsx │ │ ├── ExcelExportButton.jsx │ │ ├── SummaryCard.jsx │ │ ├── Modals/ # Confirmaciones genéricas │ │ └── ... │ ├── pages/ # ~50+ páginas por dominio │ │ ├── Login.jsx │ │ ├── Dashboard/ │ │ ├── Expenses/ │ │ ├── Inventory/ │ │ ├── Payroll/ │ │ ├── Income/ │ │ ├── Settings/ │ │ └── ... │ ├── services/ │ │ ├── api.js # Instancia axios (infrautilizada) │ │ └── ...Service.js # Algunos con URLs hardcodeadas a localhost │ └── styles/ # CSS puro por página ``` --- ## 4. BASE DE DATOS — EL CORAZÓN DEL SISTEMA **⚠️ ESTO ES LO MÁS IMPORTANTE:** El backend NO tiene lógica de negocio en JavaScript. Los controllers llaman directamente a **funciones SQL de PostgreSQL**. ### Patrón general de un controller ```javascript const pool = require('../db/connection'); const algunaFuncion = async (req, res) => { try { const { param1, param2 } = req.body; const result = await pool.query( 'SELECT nombrefuncionsql($1, $2) AS status', [param1, param2] ); const status = result.rows[0].status; res.json({ message: 'OK', status }); } catch (error) { console.error(error); res.status(500).json({ message: 'Error' }); } }; ``` ### Conexión a PostgreSQL ```javascript // src/db/connection.js const { Pool } = require('pg'); const pool = new Pool({ host: process.env.DB_HOST, port: process.env.DB_PORT, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME }); ``` ### Funciones SQL conocidas (mapeo por dominio) > **Nota:** Esta lista se deriva de las llamadas en controllers. Si necesitas modificar lógica de negocio, DEBES revisar primero la función en PostgreSQL. #### Auth - `validarusuario(name_mail_user, user_pass)` → Devuelve `{status, rol, user_id, user_name}` - `createuser(name_user, id_rol, email, user_pass)` → Devuelve `status` - `reppassuser(user_mail, new_pass)` → Devuelve `status` #### Empleados - `getemployees()` → Lista con paginación manual (LIMIT/OFFSET) - `activeemployeesnumber()` → Total de activos - `getoneemployee(rfcEmployee)` → Un empleado - `newemployee(...12 params...)` → Inserta empleado - `updateemployee(...12 params...)` → Actualiza empleado - `getattendance()` → Registros de asistencia #### Contratos - `getcontracts()`, `getinfocontract(id)`, `neartoend()` - `newcontract(...)`, `updatecontract(...)` - `positions()`, `areas()`, `bosses()` - `reportempcontract()`, `disabledcontract()` #### Productos / Inventario - `getproducts()`, `newproduct(...)`, `update_product(...)` - `productcategory()`, `producttype()`, `suppliers()` - `stockadjusment()`, `stockadjusmentset(...)` - `discardproduct(...)`, `gdiscardproducts()` - `newconsumptionstock(...)`, `getconsumptionstockreport()` - `newsuplier(...)`, `updatesupplier(...)` #### Gastos - `pendingapproval()`, `approvedexpenses()`, `rejectedexpenses()` - `newexpense(...)`, `updateexpense(...)` - `mainsupplier()`, `getexpense(id)`, `gettaxes()` - `reportexpenses()`, `reportpayments()`, `monthlypayments()` - `countpending()`, `totalapproved()` #### Status / Aprobaciones - `approveupdate(id)`, `paymentupdate(id)` - `penapppayments()`, `countdelaypay()`, `totalspent()` #### Pagos Mensuales - `newexpmonthly(...)`, `refreshmonthly()` - `paymentstatusmonthly(id)`, `updateexpmonthly(...)` - `onemothlyexpense(id)`, `needtorefresh(id)` #### Configuraciones - `newroom(...)`, `newproperty(...)` - `reportrooms()`, `reportproperties()` - `approveby()`, `requestby()`, `categoryexpense()` - `currency()`, `units()`, `recurrence()` #### Emails (envío limitado por tabla `endpoint_logs`) - `validateendpoint(endpoint_name)` → Controla ejecución 1 vez por mes - `nearexpiring()`, `paymentdelay()`, `expensesneartodeadline()` - `expensesspecial()`, `birthdays()`, `contractexpired()` - `expiredcontractsmonth()` #### Ingresos (Little Hotelier + Horux) - `getincomes(...)`, `totalincomes(...)`, `channelscards(...)` - `loadincomes(...)`, `loadproductsales(...)`, `loadchequesdetalle(...)` - `reportincomes(...)`, `countticket(...)`, `efectivo(...)`, `otros(...)` - `propinas(...)`, `tarjeta(...)`, `vales(...)`, `sumatotal(...)`, `ticketpromedio(...)` #### Horux / Facturas / Stripe - `addhoruxdata(jsonb)` → Inserta facturas masivamente - `getcategoryincome()`, `getinvoiceincome()`, `getaccountincome()` - `getincomehorux()`, `gettotalincome()`, `getoneincome(id)` - `newincome(...)`, `updateincome(...)` - `addstripedatav2(jsonb)` → Inserta datos de Stripe #### Hotel P&L / Restaurant P&L - `cogs(...)`, `ebitda(...)`, `employeeshare(...)` - `grossprofit(...)`, `tips(...)`, `totalrevenue(...)` - `weightedCategoriesCost(...)` #### Tipo de cambio - `consultexchange(...)`, `getexchanges()` #### Compras - `getpurchases()`, `entry(id)` --- ## 5. MAPA COMPLETO DE ENDPOINTS (Backend) Prefijo base: `/api` ### Auth → `/api/auth` | Método | Ruta | Controller | Función SQL | |--------|------|------------|-------------| | POST | `/login` | `auth.controller.js` | `validarusuario($1,$2)` | | POST | `/createuser` | `auth.controller.js` | `createuser($1,$2,$3,$4)` | | POST | `/recoverpass` | `auth.controller.js` | `reppassuser($1,$2)` | ### Empleados → `/api/employees` | Método | Ruta | Notas | |--------|------|-------| | GET | `/` | Paginación manual (`?page=&limit=`) | | GET | `/activeEmployees` | | | GET | `/getattendance` | | | GET | `/gradeofstudy` | Tabla directa `degreeofstudy` | | GET | `/relationship` | Tabla directa `relationship_employee` | | POST | `/employee` | Obtiene un empleado por RFC | | POST | `/newemployee` | 12 parámetros | | POST | `/updateemployee` | 12 parámetros | ### Contratos → `/api/contracts` | Método | Ruta | Notas | |--------|------|-------| | GET | `/` | | | GET | `/getinfocontract/:id` | | | GET | `/neartoend` | | | GET | `/positions` | | | GET | `/areas` | | | GET | `/bosses` | | | GET | `/reportempcontract` | | | GET | `/disabledcontract` | | | POST | `/newcontract` | | | PUT | `/updatecontract/:id` | | ### Reporte Contratos → `/api/reportcontracts` | Método | Ruta | |--------|------| | GET | `/` | ### Productos → `/api/products` | Método | Ruta | Notas | |--------|------|-------| | GET | `/` | | | GET | `/productcategory` | | | GET | `/producttype` | | | GET | `/suppliers` | | | GET | `/gdiscardproducts` | | | GET | `/reportinventory` | | | GET | `/stockadjusment` | | | GET | `/gethousekeeper` | | | GET | `/getproducts` | | | GET | `/getconsumptionstockreport` | | | POST | `/newsupplier` | | | POST | `/newproduct` | | | POST | `/stockadjusmentset` | | | POST | `/newconsumptionstock` | | | POST | `/disableSupplier` | | | PUT | `/update_product/:id` | | | PUT | `/discardproduct/:id` | | | PUT | `/product/:id` | | | PUT | `updatesupplier/:id` | ⚠️ **Falta `/` inicial en la ruta** | ### Gastos → `/api/expenses` | Método | Ruta | Notas | |--------|------|-------| | GET | `/pendingapproval` | | | GET | `/approvedexpenses` | | | GET | `/rejectedexpenses` | | | GET | `/mainsupplier` | | | PUT | `/getexpense/:id` | ⚠️ Es PUT pero debería ser GET | | GET | `/getinfo` | | | GET | `/reportexpenses` | | | POST | `/countpending` | | | GET | `/reportpayments` | | | GET | `/monthlypayments` | | | POST | `/newexpense` | | | POST | `/totalapproved` | | | PUT | `/updateexpense/:id` | | | GET | `/gettaxes` | | ### Status → `/api/status` | Método | Ruta | |--------|------| | PUT | `/approveupdate/:id` | | PUT | `/paymentupdate/:id` | | GET | `/penapppayments` | | GET | `/countdelaypay` | | GET | `/totalspent` | ### Pagos Mensuales → `/api/payment` | Método | Ruta | |--------|------| | POST | `/newexpmonthly` | | GET | `/refreshmonthly` | | PUT | `/paymentstatusmonthly/:id` | | PUT | `/updateexpmonthly/:id` | | GET | `/onemothlyexpense/:id` | | PUT | `/needtorefresh/:id` | ### Settings → `/api/settings` | Método | Ruta | |--------|------| | POST | `/newroom` | | POST | `/newproperty` | | GET | `/reportrooms` | | GET | `/reportproperties` | | GET | `/approveby` | | GET | `/requestby` | | GET | `/categoryexpense` | | GET | `/currency` | | GET | `/units` | | GET | `/recurrence` | ### Emails → `/api/emails` | Método | Ruta | Notas | |--------|------|-------| | POST | `/nearexpiring` | Validado 1x/mes por `endpoint_logs` | | POST | `/paymentdelay` | Validado 1x/mes | | POST | `/expensesneartodeadline` | Validado 1x/mes | | POST | `/expensesspecial` | Validado 1x/mes | | POST | `/birthdays` | Validado 1x/mes | | POST | `/contractexpired` | Validado 1x/mes | | POST | `/expiredcontractsmonth` | Validado 1x/mes | ### Ingresos (Little Hotelier) → `/api/incomes` | Método | Ruta | Notas | |--------|------|-------| | POST | `/getincomes` | Recibe filtros de fecha en body | | POST | `/totalincomes` | | | POST | `/channelscards` | | | POST | `/loadincomes` | Carga masiva desde CSV/XLSX | | POST | `/loadproductsales` | | | POST | `/loadchequesdetalle` | | | POST | `/reportincomes` | | | POST | `/countticket` | | | POST | `/efectivo` | | | POST | `/otros` | | | POST | `/propinas` | | | POST | `/tarjeta` | | | POST | `/vales` | | | POST | `/sumatotal` | | | POST | `/ticketpromedio` | | | GET | `/getproductsales` | | | GET | `/getdetallecheque` | | ### Compras → `/api/purchases` | Método | Ruta | |--------|------| | GET | `/getpurchases` | | PUT | `/entry/:id` | ### Tipo de Cambio → `/api/exchange` | Método | Ruta | Notas | |--------|------|-------| | POST | `/consultexchange` | Llama API Banxico | | GET | `/getexchanges` | | ### Hotel P&L → `/api/hotelpl` | Método | Ruta | |--------|------| | POST | `/cogs` | | POST | `/ebitda` | | POST | `/employeeshare` | | POST | `/grossprofit` | | POST | `/tips` | | POST | `/totalrevenue` | | POST | `/weightedCategoriesCost` | ### Restaurant P&L → `/api/restaurantpl` | Método | Ruta | |--------|------| | POST | `/cogs` | | POST | `/ebitda` | | POST | `/grossprofit` | | POST | `/totalrevenue` | | POST | `/weightedCategoriesCost` | ### Ingresos Horux → `/api/incomeshrx` | Método | Ruta | Notas | |--------|------|-------| | GET | `/accountincome` | | | GET | `/categoryincome` | | | GET | `/invoiceIncome` | | | GET | `/totalIncome` | | | GET | `/incomehorux` | | | GET | `/oneincomehorux/:id` | | | GET | `/stripedata/` | Obtiene transfers de Stripe y las guarda | | POST | `/stripedatademo/` | Crea transfer demo en Stripe | | POST | `/insertinvoice` | Descarga facturas de API externa y las inserta | | POST | `/newincome` | | | PUT | `/updateincome/:id` | | --- ## 6. INTEGRACIONES EXTERNAS ### 6.1 Banxico (Tipo de cambio USD/MXN) - **Endpoint:** `https://www.banxico.org.mx/SieAPIRest/service/v1/series/SF43718/datos/...` - **Token:** `process.env.BANXICO_TOKEN` - **Uso:** `exchange.controller.js` ### 6.2 Stripe - **Secret Key:** `process.env.STRIPE_SECRET_KEY` - **Operaciones:** - Listar transfers (`stripe.transfers.list()`) - Insertar en DB mediante `addstripedatav2(jsonb)` - Crear transfers demo (`stripe.transfers.create()`) - **Uso:** `incomehrx.controller.js` ### 6.3 API de Facturas (México) - **URL:** `process.env.FACTURAS_API_URL` - **Parámetros:** `issuerRfc`, `type`, `initialDate`, `finalDate` - **Auth:** Bearer token (`FACTURAS_API_TOKEN`) - **Uso:** Descarga facturas del año actual y las inserta vía `addhoruxdata(jsonb)` ### 6.4 Nodemailer - **Host:** Configurable por env (`EMAIL_HOST`, `EMAIL_PORT`, `EMAIL_USER`, `EMAIL_PASS`) - **From:** `soporte@horuxfin.com` - **Uso:** Recuperación de contraseña, emails programáticos (cumpleaños, contratos por vencer, etc.) --- ## 7. SISTEMA DE AUTENTICACIÓN Y ROLES ### Backend - **NO usa JWT**. El login devuelve `{rol, user_id, user_name, message}`. - **NO hay middleware de autorización** en las rutas. Cualquiera puede llamar a cualquier endpoint si conoce la URL. - La función `validarusuario(name_mail_user, user_pass)` valida contra PostgreSQL. ### Frontend - El rol se guarda en `localStorage` bajo la clave `"rol"`. - Los permisos son **numéricos y hardcodeados** en `Layout2.jsx`: | Rol | Nombre implícito | Acceso | |-----|-----------------|--------| | 1 | Admin | Todo | | 2 | Supervisor limitado | Dashboards, Expenses (solo Report/Monthly Report), Payroll (Report/Attendance/Employees/Contracts), Expenses to be approved | | 3 | — | Similar a supervisor (según rangos) | | 4 | — | Payroll, Income | | 5 | Compras/Proveedores | Solo: New Expense, Purchase Entries, New Suppliers (en Expenses) | | 6 | Housekeeper | Forzado a español. Solo sección "Housekeeper" → Outcomes | ### Lógica de permisos en `Layout2.jsx` ```javascript section.label === "Dashboards" ? (user >= 1 && user <= 2 ? false : true) : section.label === "Expenses to be approved" ? (user === 1 || user === 2 ? false : true) : section.label === "Expenses" ? (user >= 1 && user <= 5 ? false : true) : section.label === "Inventory" ? (user >= 1 && user <= 5 ? false : true) : section.label === "Payroll" ? (user >= 1 && user <= 4 ? false : true) : section.label === "Hotel" ? (user === 1 ? false : true) : section.label === "Income" ? (user >= 1 && user <= 4 ? false : true) : section.label === "Housekeeper" ? (user === 6 ? false : true) : false ``` --- ## 8. FLUJOS DE DATOS CRÍTICOS ### 8.1 Carga de Ingresos desde Little Hotelier 1. Se sube archivo CSV o XLSX a `src/resources/littleHotelier/` 2. Endpoints `POST /api/incomes/loadincomes`, `/loadproductsales`, `/loadchequesdetalle` 3. Los controllers leen el archivo, lo parsean y llaman funciones SQL que reciben `jsonb` 4. PostgreSQL procesa e inserta los datos masivamente ### 8.2 Sincronización de Facturas (Horux) 1. Endpoint `POST /api/incomeshrx/insertinvoice` 2. Controller calcula fechas: inicio de año → hoy 3. Llama API externa de facturas con esas fechas 4. Recibe JSON y lo pasa a `addhoruxdata($1::jsonb)` 5. PostgreSQL inserta/actualiza facturas ### 8.3 Sincronización de Stripe 1. Endpoint `GET /api/incomeshrx/stripedata/` 2. Llama `stripe.transfers.list()` 3. Serializa a JSON y pasa a `addstripedatav2($1::jsonb)` 4. PostgreSQL inserta transacciones ### 8.4 Emails Programáticos 1. Los endpoints en `/api/emails/*` tienen lógica de "una ejecución por mes" 2. Usan la función `validateendpoint(endpoint_name)` en PostgreSQL 3. Esta consulta una tabla `endpoint_logs` para ver si ya se ejecutó 4. Si es válido, genera el email (consultando otras funciones SQL) y envía vía Nodemailer --- ## 9. VARIABLES DE ENTORNO ### Backend (`/home/Hotel/backend/hotel_hacienda/.env`) ```env PORT=3000 URL_CORS=https://tudominio.com # Sin slash al final DB_HOST=localhost DB_PORT=5432 DB_USER=postgres DB_PASSWORD=****** DB_NAME=hotel_hacienda EMAIL_HOST=smtp.tudominio.com EMAIL_PORT=587 EMAIL_USER=soporte@horuxfin.com EMAIL_PASS=****** STRIPE_SECRET_KEY=sk_****** FACTURAS_API_URL=https://api.facturas.com/... FACTURAS_ISSUER_RFC=RFC_EMISOR FACTURAS_TYPE=I # o E FACTURAS_API_TOKEN=token_aqui BANXICO_TOKEN=token_banxico ``` ### Frontend (`/home/Hotel/frontend/Frontend-Hotel/.env`) ```env VITE_API_BASE_URL=http://localhost:4000/api ``` ### Frontend dev server - Puerto: `5172` (hardcodeado en `vite.config.js`) - Hosts permitidos: `hacienda.consultoria-as.com`, `hotel.consultoria-as.com` --- ## 10. BUGS Y DEUDA TÉCNICA CONOCIDA ### 🔴 Críticos 1. **Sin autenticación en endpoints backend** - Cualquiera puede llamar a cualquier API si conoce la URL. - **Impacto:** Seguridad. No modifiques datos sensibles sin agregar al menos un middleware de API key o JWT. 2. **`useAuth` no existe pero se intenta importar** - `AuthContext.jsx` NO exporta `useAuth`. - `ProtectedRoute.jsx` y `Navbar.jsx` intentan importarlo. - **Impacto:** Crash si se renderizan esos componentes. 3. **Ruta malformada en backend** - `product.routes.js`: `router.put('updatesupplier/:id', ...)` le falta `/` inicial. - **Impacto:** Ese endpoint nunca funcionará correctamente. 4. **URLs hardcodeadas en services del frontend** - `incomeService.js`, `contractService.js`, `userService.js`, `employeeService.js` apuntan a `http://localhost:3000` o `http://localhost:4000`. - **Impacto:** Rompen en producción. 5. **Método HTTP incorrecto** - `expense.routes.js`: `PUT /getexpense/:id` debería ser `GET`. ### 🟡 Medios 6. **No hay `ProtectedRoute` activo en `App.jsx`** - Todas las rutas internas son accesibles sin login. 7. **Mezcla de `fetch` y `axios`** - No hay estándar. Algunas páginas usan `fetch`, otras `axios`, otras la instancia `api.js`. 8. **Código comentado masivo** - `Layout.jsx` tiene ~300 líneas comentadas. - Varios controllers y páginas tienen versiones antiguas comentadas. - **Impacto:** Dificulta lectura y aumenta bundle size innecesariamente. 9. **`multer` en frontend** - Es un middleware de Node.js, no tiene sentido en React. Debería estar solo en backend. 10. **Paginación manual en controllers** - Se hace `COUNT(*)` + `LIMIT/OFFSET` manual en cada controller. - **Riesgo:** Si dos personas agregan paginación de forma distinta, la API se vuelve inconsistente. ### 🟢 Leves 11. **No hay tests** (ni unitarios ni e2e). 12. **No hay TypeScript** — riesgo de errores de tipo en runtime. 13. **Tailwind instalado pero poco usado** — la mayoría de estilos son CSS puro o Bootstrap. 14. **No hay manejo de estado de servidor** (TanStack Query, SWR) — cada componente maneja su propio `useEffect + fetch`. --- ## 11. REGLAS DE ORO PARA NO ROMPER INTEGRIDAD ### Antes de tocar cualquier archivo, pregúntate: 1. **¿Es un cambio de lógica de negocio?** - Si SÍ → Revisa la **función SQL correspondiente** en PostgreSQL ANTES de tocar el controller. - Los controllers solo orquestan. La lógica vive en la base de datos. 2. **¿Es un nuevo endpoint?** - Sigue el patrón existente: `route` → `controller` → `pool.query('SELECT funcion_sql($1)')`. - Usa queries parametrizadas (`$1`, `$2`) para evitar SQL Injection. - AGREGA la ruta en `app.js` con el prefijo `/api/`. 3. **¿Es un cambio en el frontend que consume datos?** - Verifica si la página usa `fetch`, `axios` o la instancia `api.js`. - Si usas `fetch`, usa `import.meta.env.VITE_API_BASE_URL`. - NO hardcodees `localhost`. 4. **¿Es un cambio en roles/permisos?** - Hay DOS lugares donde tocar: - `frontend/src/components/Layout2.jsx` (permisos del menú sidebar) - `frontend/src/constants/menuconfig.js` (estructura del menú) - Si agregas una nueva ruta en `App.jsx`, agrega su lógica de detección en `activeSection` de `Layout2.jsx`. 5. **¿Es un cambio en la base de datos?** - Si modificas una función SQL, verifica TODOS los controllers que la llaman. - Si cambias la firma de una función (nuevos parámetros), debes actualizar TODOS los `pool.query(...)` que la usan. - Los controllers pasan arrays/objetos como `JSON.stringify()` para parámetros `jsonb`. 6. **¿Es un cambio en emails?** - Los endpoints de email tienen validación de frecuencia (`validateendpoint`). - Si quieres probar un email múltiples veces, necesitas limpiar la tabla `endpoint_logs` o modificar la función SQL. 7. **¿Es un cambio en integraciones externas (Stripe, Facturas, Banxico)?** - Verifica las variables de entorno. - Los endpoints de Stripe y Facturas son destructivos (insertan masivamente). - Prueba en ambiente de desarrollo primero. --- ## 12. CHECKLIST ANTES DE HACER UN CAMBIO ### Backend - [ ] ¿Agregué la ruta en `src/app.js` con `app.use('/api/...', ...)`? - [ ] ¿Usé `pool.query` con parámetros `$1, $2`? - [ ] ¿Si creé una función SQL nueva, la probé directamente en PostgreSQL? - [ ] ¿No rompí la firma de una función SQL existente? - [ ] ¿El método HTTP es coherente? (GET para leer, POST para crear, PUT para actualizar) - [ ] ¿El response mantiene la estructura esperada por el frontend? ### Frontend - [ ] ¿Agregué la ruta en `src/App.jsx`? - [ ] ¿Agregué la entrada en `menuconfig.js` si es una nueva sección? - [ ] ¿Actualicé `Layout2.jsx` para detectar la nueva ruta en `activeSection`? - [ ] ¿Usé `import.meta.env.VITE_API_BASE_URL` en vez de `localhost`? - [ ] ¿Agregué la traducción EN/ES si es texto visible? - [ ] ¿Verifiqué que el rol apropiado pueda ver la nueva página? ### Base de datos - [ ] ¿La función SQL compila y ejecuta correctamente? - [ ] ¿Los tipos de parámetros coinciden con lo que envía el controller? - [ ] ¿Si modifico una tabla, revisé las funciones que dependen de ella? --- ## 13. GUÍA DE CAMBIOS POR ÁREA ### "Quiero agregar un nuevo campo a un formulario existente" 1. **Frontend:** Modifica la página JSX donde está el formulario. 2. **Backend:** Modifica el controller para recibir el nuevo campo en `req.body`. 3. **Base de datos:** Modifica la función SQL para aceptar el nuevo parámetro. 4. **Verificación:** Busca con `grep` todos los lugares donde se llama esa función SQL. ### "Quiero agregar una nueva página" 1. Crea el componente en `src/pages/[dominio]/Nombre.jsx`. 2. Agrégalo en `src/App.jsx` dentro de `}>`. 3. Si va en el menú: - Agrégalo en `menuconfig.js` en la sección correspondiente. - Verifica permisos en `Layout2.jsx`. - Agrega detección de ruta en `activeSection` de `Layout2.jsx`. 4. Crea el endpoint backend si es necesario. ### "Quiero modificar la lógica de un reporte" 1. **NO modifiques el controller** para cambiar lógica de filtrado/agrupación. 2. Modifica la **función SQL** que genera el reporte. 3. El controller solo pasa parámetros (fechas, filtros) y devuelve lo que PostgreSQL responda. ### "Quiero cambiar quién ve qué" 1. Edita `Layout2.jsx`, líneas ~18-36. 2. Los permisos usan números de rol. Asegúrate de entender qué número corresponde a qué usuario. 3. Si quieres ocultar un submenú específico, usa la lógica de `submenu.map(...)`. --- ## 14. NOTAS DE DESPLIEGUE ### Backend ```bash cd /home/Hotel/backend/hotel_hacienda npm install node src/server.js # o nodemon para dev ``` ### Frontend ```bash cd /home/Hotel/frontend/Frontend-Hotel npm install npm run dev # Puerto 5172 npm run build # Genera dist/ ``` ### Proxy / CORS - El backend permite CORS desde `URL_CORS` (definido en `.env`). - Si el frontend y backend están en dominios distintos, asegúrate de que `URL_CORS` incluya el dominio del frontend. --- ## 15. HALLAZGOS ESPECIALES ### JSONB como patrón de intercambio Muchos endpoints que manejan datos complejos (facturas, Stripe, productos con categorías) usan `JSON.stringify()` en el controller y funciones SQL que aceptan `jsonb`: ```javascript const categoriesJson = categories ? JSON.stringify(categories) : '[]'; await pool.query('SELECT newincome($1,$2,$3,$4,$5,$6::jsonb)', [...params, categoriesJson]); ``` **Consecuencia:** Si cambias la estructura del JSON en el frontend, DEBES actualizar la función PostgreSQL para parsearla correctamente. ### Paginación manual consistente El patrón usado es: ```javascript const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 500; const offset = (page - 1) * limit; // Query principal con LIMIT $1 OFFSET $2 // Query COUNT(*) para total // Respuesta: { page, limit, total, totalPages, data } ``` Si agregas paginación a un endpoint nuevo, sigue EXACTAMENTE esta estructura de respuesta para que `HotelTable.jsx` u otros componentes la entiendan. --- ## 16. PRÓXIMOS PASOS RECOMENDADOS (NO URGENTES) Si el usuario quiere mejorar la salud del proyecto, priorizaría: 1. **Unificar HTTP client:** Estandarizar todo en `api.js` (axios) con interceptores para errores. 2. **Eliminar código comentado:** Especialmente `Layout.jsx` y páginas grandes. 3. **Arreglar `useAuth`:** Exportar un hook `useAuth` desde `AuthContext.jsx`. 4. **Arreglar ruta malformada:** `updatesupplier/:id` → `/updatesupplier/:id`. 5. **Eliminar `multer` del frontend** y mover lógica de upload al backend si es necesario. 6. **Agregar middleware de autenticación** mínimo (API key o JWT) en rutas sensibles. 7. **Documentar funciones SQL:** Este documento lista las funciones conocidas, pero no sus firmas exactas en PostgreSQL. --- > **Fin del documento.** Si realizas cambios significativos en el sistema, actualiza este archivo para mantenerlo vivo.