Este PR introduce el endpoint /api/v1/plans/weight-loss para generar planes calóricos personalizados en NutriPaw. La estructura general es correcta y el modelo Sequelize está bien definido, pero se identificaron 2 hallazgos críticos: ausencia de validación de entrada (permite inyección de datos maliciosos y desbordamiento aritmético) y una consulta SQL construida con interpolación de cadenas que expone el sistema a SQL injection. Adicionalmente, hay un problema de eficiencia por consultas N+1 en el servicio y varios puntos de mantenibilidad. Se recomienda no hacer merge hasta resolver los hallazgos críticos y de severidad alta.
/weight-loss con validación inline incompleta y manejo de errores genérico.Plan con las columnas necesarias; falta índice en pet_id para consultas frecuentes.
Sin validación de entrada — desbordamiento aritmético y datos inválidos.
Los campos current_weight, target_weight y weeks se pasan directamente al servicio sin validar tipo ni rango. Un valor weeks=0 produce una división por cero en el cálculo calórico; valores negativos generan planes incoherentes que podrían dañar al animal.
SQL Injection por interpolación directa de cadenas.
La consulta de historial del paciente se construye con template literals usando pet_id sin escapar. Aunque pet_id pasa por Sequelize en otros lugares, aquí se usa sequelize.query() con interpolación directa, lo que permite SQL injection clásica.
Consultas N+1 — inserción de registros diarios en bucle.
El bucle for (let day = 1; day <= weeks * 7; day++) ejecuta un INSERT por cada día del plan. Para un plan de 12 semanas genera 84 queries individuales. Debe reemplazarse por bulkCreate.
Error genérico expone stack trace en producción.
El bloque catch devuelve res.status(500).json({ error: e.message, stack: e.stack }), exponiendo detalles internos del servidor al cliente. El stack trace es útil en desarrollo pero no debe llegar a producción.
Falta índice en pet_id — degradación de rendimiento en consultas frecuentes.
El modelo no define un índice sobre pet_id, que es la columna más consultada. Sin índice, cada lookup escanea la tabla completa (full table scan) y el rendimiento se degradará a medida que crezca el dataset.
Número mágico en la fórmula calórica.
La fórmula usa el literal 7700 (kcal por kg de grasa) sin explicación. Si los requisitos nutricionales cambian, no hay forma de rastrearlo. Extraer como constante nombrada con comentario JSDoc.
Cobertura de tests insuficiente — solo happy path.
Los tests actuales verifican únicamente el caso de éxito. No hay tests para: weeks=0, current_weight < target_weight, pet_id inexistente, ni cuerpo de request vacío. Estos son los casos que más frecuentemente causan regresiones en producción.
Nombre de función demasiado genérico.
La función del handler se llama handlePlan. Con múltiples tipos de planes en el futuro, el nombre será ambiguo. Renombrar a createWeightLossPlan para mayor claridad.
Import no utilizado: lodash.
Se importa import _ from 'lodash' pero no se usa en el archivo. Eliminar para reducir el bundle y evitar dependencias innecesarias.
Falta timestamps: true en el modelo.
El modelo no especifica explícitamente timestamps. Si la configuración global de Sequelize los desactiva, el modelo no tendrá createdAt/updatedAt, lo que dificulta auditorías. Declararlo explícitamente.
Typo en comentario JSDoc.
El comentario dice "Calcuates the daily caloric deficit" (falta la 'l' en "calculates"). Corregir a "Calculates the daily caloric deficit".
bulkCreate para evitar la degradación de rendimiento en planes de múltiples semanas (hallazgo alto).pet_id no existente. El happy path solo verifica el flujo óptimo.pet_id del modelo Plan y declarar explícitamente los timestamps para consistencia del esquema.