Productos más Populares - bootcamp-uchile-2026/grupo-2-backend GitHub Wiki
Productos más Populares
La funcionalidad Productos más Populares permite mostrar en la página de inicio de BuenOrigen una selección de los productos con mayor nivel de ventas.
Desde la perspectiva Backend, esta funcionalidad consiste en ordenar los productos según la cantidad de ventas registradas durante el último mes y devolver únicamente la cantidad solicitada por Frontend o Mobile.
Objetivo
Proporcionar a Frontend y Mobile una selección de los productos más vendidos para ser presentada en la página de inicio de BuenOrigen.
Estado
Implementado
La funcionalidad se encuentra implementada mediante:
ProductosModule
|
v
ProductosController
|
v
ProductosService
|
v
ProductoMasVendidoDto[]
Responsabilidad Backend
Actualmente el Backend debe:
- Recibir la cantidad de productos solicitados.
- Transformar el Query Parameter
cantidada un número entero. - Consultar los productos disponibles.
- Ordenar los productos según
ventasUltimoMes. - Presentar primero los productos con mayor cantidad de ventas.
- Limitar los resultados según
cantidad. - Transformar cada producto a
ProductoMasVendidoDto. - Devolver los resultados a Frontend o Mobile.
Contrato de API
Endpoint
GET /productos/mas-vendidos
Query Parameter
cantidad
El parámetro es obligatorio.
Ejemplo:
GET /productos/mas-vendidos?cantidad=5
DTO de salida
ProductoMasVendidoDto[]
Página relacionada:
La definición general del endpoint se encuentra centralizada en:
La estructura completa del DTO se encuentra documentada en:
Query Parameter cantidad
El endpoint recibe:
cantidad
mediante:
@Query('cantidad', ParseIntPipe) cantidad: number
Esto significa que el valor recibido originalmente desde HTTP debe poder convertirse correctamente a un número entero.
Por ejemplo:
GET /productos/mas-vendidos?cantidad=5
HTTP entrega inicialmente:
"5"
y ParseIntPipe lo transforma en:
5
antes de entregarlo al método del Controller.
Conceptualmente:
HTTP
"5"
|
v
ParseIntPipe
|
v
5
|
v
ProductosController
Validación de cantidad
Actualmente ParseIntPipe permite validar que el parámetro pueda interpretarse como un número entero.
Por ejemplo:
GET /productos/mas-vendidos?cantidad=abc
no corresponde a una cantidad válida y NestJS responde con:
400 Bad Request
También se espera que el parámetro sea enviado porque está definido como obligatorio.
Sin embargo, actualmente no existe una regla adicional como:
cantidad >= 1
Por lo tanto, la validación de valores positivos podrá mejorarse posteriormente.
Una posible evolución podría utilizar:
ParseIntPipe
+
validación de mínimo
para impedir cantidades como:
0
-1
-5
Criterio de Popularidad Actual
Actualmente el criterio utilizado para determinar qué productos son más populares es:
ventasUltimoMes
Cada producto posee esta propiedad dentro del modelo.
Por ejemplo:
{
id: 1,
nombre: 'Bolsa reutilizable',
ventasUltimoMes: 150
}
La lógica ordena los productos desde el valor más alto al más bajo.
Conceptualmente:
Producto A → 35 ventas
Producto B → 120 ventas
Producto C → 75 ventas
después del ordenamiento:
Producto B → 120
Producto C → 75
Producto A → 35
Ordenamiento
El Service utiliza un orden descendente:
(a, b) => b.ventasUltimoMes - a.ventasUltimoMes
Conceptualmente:
Productos
|
| sort()
v
Mayor ventasUltimoMes
|
v
Menor ventasUltimoMes
De esta forma, los productos con mayor nivel de ventas aparecen primero.
Período de Ventas
Actualmente no se calcula dinámicamente el número de ventas desde un historial de pedidos.
El modelo Producto posee directamente la propiedad:
ventasUltimoMes: number;
Por lo tanto, el criterio actual es:
ventasUltimoMes
y no:
ventas históricas
ventas totales
promedio de puntuación
cantidad de favoritos
Conceptualmente:
Producto
|
v
ventasUltimoMes
|
v
Criterio de popularidad
En una futura implementación conectada a una base de datos o a un dominio de ventas/pedidos, este valor podrá obtenerse dinámicamente.
Limitación de Resultados
Después de ordenar los productos, el Service utiliza:
slice(0, cantidad)
para seleccionar únicamente la cantidad solicitada.
Por ejemplo, si existen:
1. Producto A
2. Producto B
3. Producto C
4. Producto D
5. Producto E
y Frontend solicita:
GET /productos/mas-vendidos?cantidad=3
el Backend devolverá:
Producto A
Producto B
Producto C
Flujo de la Operación
Conceptualmente:
GET /productos/mas-vendidos?cantidad=5
|
v
ParseIntPipe
|
v
cantidad: number
|
v
ProductosController
|
v
ProductosService
|
| sort()
v
Ordenar por ventasUltimoMes
|
| slice()
v
Limitar por cantidad
|
| map()
v
ProductoMasVendidoDto[]
|
v
200 OK
Procesamiento en ProductosService
La operación principal corresponde a:
obtenerProductosMasVendidos(
cantidad: number,
): ProductoMasVendidoDto[]
El proceso puede dividirse conceptualmente en tres etapas:
1. Ordenar
|
v
productosOrdenados
2. Limitar
|
v
productosLimitados
3. Transformar
|
v
ProductoMasVendidoDto[]
DTO de Salida
La operación utiliza:
ProductoMasVendidoDto
con la siguiente estructura:
export class ProductoMasVendidoDto {
id: number;
marca: string;
nombre: string;
precio: number;
puntuacion: number | null;
imagenUrl: string;
}
El Backend no devuelve directamente el modelo completo Producto.
Conceptualmente:
Producto
|
| seleccionar campos necesarios
v
ProductoMasVendidoDto
|
v
Frontend / Mobile
Puntuación
El DTO incluye:
puntuacion: number | null;
Esto permite representar productos que todavía no poseen una puntuación.
Por ejemplo:
{
"puntuacion": null
}
continúa siendo una respuesta válida.
La puntuacion se entrega como información visual del producto, pero actualmente no se utiliza para determinar cuáles productos son más vendidos.
El criterio de ordenamiento continúa siendo:
ventasUltimoMes
Ejemplo de Solicitud
GET /productos/mas-vendidos?cantidad=3
Ejemplo de Respuesta
[
{
"id": 1,
"marca": "EcoWear",
"nombre": "Polera de Algodón Orgánico",
"precio": 12990,
"puntuacion": 4.8,
"imagenUrl": "https://ejemplo.cl/imagenes/productos/polera.jpg"
},
{
"id": 2,
"marca": "EcoRaíz",
"nombre": "Bolsa Reutilizable",
"precio": 5990,
"puntuacion": 4.5,
"imagenUrl": "https://ejemplo.cl/imagenes/productos/bolsa.jpg"
},
{
"id": 3,
"marca": "Verde Hogar",
"nombre": "Set de Utensilios Sustentables",
"precio": 8990,
"puntuacion": null,
"imagenUrl": "https://ejemplo.cl/imagenes/productos/utensilios.jpg"
}
]
Respuesta HTTP:
200 OK
Cantidad Mayor al Número de Productos
Si el cliente solicita una cantidad superior al número de productos disponibles:
GET /productos/mas-vendidos?cantidad=100
slice() devolverá todos los productos disponibles sin producir un error.
Por ejemplo:
Productos disponibles: 5
Cantidad solicitada: 100
resultado:
5 productos
Resultado sin Productos
Si el catálogo no contiene productos, la operación devolverá:
[]
con:
200 OK
Respuestas HTTP
| Código | Situación |
|---|---|
200 OK |
Productos más vendidos obtenidos correctamente |
200 OK con [] |
No existen productos disponibles |
400 Bad Request |
cantidad no puede transformarse correctamente a un número entero |
Documentación Swagger
El endpoint se encuentra documentado mediante:
@ApiOperation()
@ApiQuery()
@ApiOkResponse()
El Query Parameter se documenta como:
cantidad
de tipo:
Number
y:
required: true
La respuesta exitosa corresponde a:
ProductoMasVendidoDto[]
Para mayor información consultar:
Regla de Negocio Actual
La regla puede resumirse de la siguiente forma:
Productos
|
v
Ordenar por ventasUltimoMes DESC
|
v
Tomar los primeros "cantidad"
|
v
ProductoMasVendidoDto[]
Por lo tanto, actualmente:
Popularidad = mayor cantidad de ventasUltimoMes
Posibles Mejoras Futuras
Posteriormente podrán evaluarse mejoras como:
- Validar que
cantidadsea mayor que cero. - Definir un máximo permitido para
cantidad. - Calcular
ventasUltimoMesdesde pedidos reales. - Permitir distintos períodos de ventas.
- Incorporar ventas semanales.
- Incorporar ventas históricas.
- Incorporar otros criterios de popularidad.
- Incorporar paginación.
Estas mejoras deberán agregarse únicamente cuando sean requeridas por las reglas de negocio de BuenOrigen.
Relación con la Página de Inicio
Página de Inicio
|
v
Productos más Populares
|
v
GET /productos/mas-vendidos
|
v
ProductosController
|
v
ProductosService
|
v
ProductoMasVendidoDto[]
|
v
Frontend / Mobile
Relación con la Arquitectura
La funcionalidad pertenece al dominio:
Productos
y utiliza:
ProductosModule
|
v
ProductosController
|
v
ProductosService
|
v
ProductoMasVendidoDto[]
Páginas relacionadas: