Productos del Emprendedor - bootcamp-uchile-2026/grupo-2-backend GitHub Wiki
Productos del Emprendedor
La funcionalidad Productos del Emprendedor permite que los usuarios de BuenOrigen consulten los productos asociados a un emprendedor determinado.
Desde la perspectiva Backend, esta funcionalidad consiste en identificar al emprendedor solicitado, verificar que exista y consultar los productos asociados mediante la relación emprendedorId.
La presentación visual de los productos, tarjetas, filtros, paginación y navegación corresponde a Frontend y Mobile.
Objetivo
Proporcionar a Frontend y Mobile el listado de productos pertenecientes a un emprendedor específico.
Estado
Implementado
La funcionalidad se encuentra implementada mediante:
EmprendedoresModule
|
v
EmprendedoresController
|
v
EmprendedoresService
|
v
ProductosService
|
v
ProductoResumenDto[]
Responsabilidad Backend
Actualmente el Backend debe:
- Recibir el identificador del emprendedor solicitado.
- Transformar el parámetro
emprendedorIda número. - Verificar que el emprendedor exista.
- Consultar los productos asociados al emprendedor.
- Seleccionar únicamente productos cuyo
emprendedorIdcorresponda al emprendedor solicitado. - Transformar los productos a
ProductoResumenDto. - Informar mediante
404 Not Foundcuando el emprendedor no exista. - Entregar una lista vacía cuando el emprendedor exista pero no posea productos asociados.
Contrato de API
Endpoint
GET /emprendedores/:emprendedorId/productos
Ejemplo:
GET /emprendedores/2/productos
Parámetro de Ruta
emprendedorId
Tipo esperado:
number
DTO de salida
ProductoResumenDto[]
La definición general del endpoint se encuentra centralizada en:
La estructura del DTO se encuentra documentada en:
Parámetro emprendedorId
El Controller recibe el identificador mediante:
@Param('emprendedorId', ParseIntPipe) emprendedorId: number
Los parámetros de una URL llegan originalmente como texto.
Por ejemplo:
GET /emprendedores/2/productos
entrega inicialmente:
"2"
ParseIntPipe lo transforma en:
2
Conceptualmente:
HTTP
"2"
|
v
ParseIntPipe
|
v
2
|
v
EmprendedoresController
Validación del Identificador
Si el parámetro no puede convertirse a un número entero:
GET /emprendedores/abc/productos
ParseIntPipe genera:
400 Bad Request
antes de que la solicitud llegue al Service.
Conceptualmente:
emprendedorId
|
v
ParseIntPipe
|
+----+----+
| |
válido inválido
| |
v v
number 400
| Bad Request
v
Service
Verificación del Emprendedor
Antes de buscar los productos, EmprendedoresService comprueba que el emprendedor exista.
Conceptualmente:
const emprendedorEncontrado = this.emprendedores.find(
(emprendedor) => emprendedor.id === emprendedorId,
);
Si no existe:
if (!emprendedorEncontrado) {
throw new NotFoundException('Emprendedor no encontrado');
}
Por lo tanto:
emprendedorId
|
v
Buscar emprendedor
|
+----+----+
| |
Existe No existe
| |
v v
Buscar 404
productos Not Found
Relación entre Emprendedor y Producto
Un emprendedor puede tener múltiples productos asociados.
Conceptualmente:
Emprendedor
|
| 1
|
| N
v
Producto
La relación se representa actualmente mediante:
emprendedorId: number;
dentro del modelo Producto.
Por ejemplo:
{
id: 10,
emprendedorId: 2,
nombre: 'Bolsa Reutilizable'
}
indica que el producto pertenece al emprendedor:
id = 2
Búsqueda de Productos
La búsqueda de productos no se realiza directamente dentro de EmprendedoresService.
Después de verificar que el emprendedor exista, se utiliza:
ProductosService
mediante:
this.productosService.obtenerProductosPorEmprendedor(
emprendedorId,
);
Conceptualmente:
EmprendedoresService
|
| emprendedorId
v
ProductosService
|
| filter()
v
Producto.emprendedorId === emprendedorId
|
v
ProductoResumenDto[]
Separación de Responsabilidades
La responsabilidad de comprobar que el emprendedor exista pertenece actualmente a:
EmprendedoresService
Mientras que la lógica de consultar productos pertenece a:
ProductosService
Conceptualmente:
EmprendedoresService
|
| verifica
v
Emprendedor
|
| solicita productos
v
ProductosService
|
| filtra
v
Producto[]
Esto evita duplicar lógica relacionada con productos dentro del dominio Emprendedores.
Comunicación entre Módulos
Para que EmprendedoresService pueda utilizar ProductosService, existe una relación entre ambos módulos.
Conceptualmente:
EmprendedoresModule
|
| imports
v
ProductosModule
ProductosModule exporta:
ProductosService
permitiendo que pueda ser utilizado desde EmprendedoresService.
La dependencia se recibe mediante inyección de dependencias:
constructor(
private readonly productosService: ProductosService,
) {}
Filtrado por emprendedorId
Dentro de ProductosService, los productos se seleccionan mediante su relación con el emprendedor.
Conceptualmente:
const productosEmprendedor = this.productos.filter(
(producto) => producto.emprendedorId === emprendedorId,
);
Por ejemplo, si existen:
Producto A → emprendedorId = 1
Producto B → emprendedorId = 2
Producto C → emprendedorId = 2
Producto D → emprendedorId = 3
y se consulta:
GET /emprendedores/2/productos
se seleccionan:
Producto B
Producto C
DTO de Salida
La operación utiliza:
ProductoResumenDto
con la siguiente estructura:
export class ProductoResumenDto {
id: number;
marca: string;
nombre: string;
precio: number;
imagenUrl: string;
}
Por lo tanto, la respuesta del endpoint corresponde a:
ProductoResumenDto[]
ProductoResumenDto como DTO Reutilizable
Esta funcionalidad inicialmente consideró la creación de:
ProductoEmprendedorDto
Sin embargo, esa estructura duplicaba información que podía representarse mediante un DTO resumido reutilizable.
Por esta razón, actualmente se utiliza:
ProductoResumenDto
Conceptualmente:
ANTES
Productos del Emprendedor
|
v
ProductoEmprendedorDto[]
ACTUALMENTE
Productos del Emprendedor
|
v
ProductoResumenDto[]
Esto permite utilizar un contrato genérico para representar productos resumidos sin crear un DTO exclusivamente por el contexto donde aparece.
Modelo vs DTO
El modelo Producto contiene más información que la necesaria para esta operación.
Por ejemplo:
id
subcategoriaId
emprendedorId
marca
nombre
descripcion
precio
precioOferta
imagenUrl
imagenes
stock
puntuacion
ventasUltimoMes
fechaCreacion
colores
tallas
Sin embargo, la respuesta solamente necesita:
id
marca
nombre
precio
imagenUrl
Conceptualmente:
Producto
|
| filter por emprendedorId
v
Productos del Emprendedor
|
| map()
v
ProductoResumenDto[]
Flujo Completo de la Operación
GET /emprendedores/2/productos
|
v
ParseIntPipe
|
v
emprendedorId: number
|
v
EmprendedoresController
|
v
EmprendedoresService
|
| find()
v
¿Existe emprendedor?
|
+----+----+
| |
Sí No
| |
v v
Productos 404
Service Not Found
|
| filter()
v
Productos con
emprendedorId = 2
|
| map()
v
ProductoResumenDto[]
|
v
200 OK
Ejemplo de Solicitud
GET /emprendedores/2/productos
Ejemplo de Respuesta
[
{
"id": 10,
"marca": "EcoRaíz",
"nombre": "Bolsa Reutilizable de Algodón",
"precio": 5990,
"imagenUrl": "https://ejemplo.cl/imagenes/bolsa-algodon.jpg"
},
{
"id": 15,
"marca": "EcoRaíz",
"nombre": "Set de Bolsas para Compras",
"precio": 8990,
"imagenUrl": "https://ejemplo.cl/imagenes/set-bolsas.jpg"
}
]
Respuesta HTTP:
200 OK
Emprendedor sin Productos
Si el emprendedor existe pero ningún producto posee su emprendedorId, el resultado de:
filter()
será:
[]
Por lo tanto, el Backend responde:
[]
con:
200 OK
Esto no se considera un error.
Conceptualmente:
Emprendedor existe
|
v
Buscar productos
|
v
0 coincidencias
|
v
[]
|
v
200 OK
Manejo de Errores
Identificador inválido
Ejemplo:
GET /emprendedores/abc/productos
Respuesta:
400 Bad Request
Gestionado por:
ParseIntPipe
Emprendedor inexistente
Ejemplo:
GET /emprendedores/999/productos
Si el emprendedor no existe:
404 Not Found
Ejemplo conceptual:
{
"statusCode": 404,
"message": "Emprendedor no encontrado",
"error": "Not Found"
}
Respuestas HTTP
| Código | Situación |
|---|---|
200 OK |
Productos obtenidos correctamente |
200 OK con [] |
El emprendedor existe pero no posee productos |
400 Bad Request |
emprendedorId no corresponde a un entero válido |
404 Not Found |
El emprendedor solicitado no existe |
Relación con el Perfil de Emprendedor
Desde Perfil de Emprendedor, Frontend y Mobile pueden solicitar los productos asociados mediante:
GET /emprendedores/:emprendedorId/productos
Conceptualmente:
Perfil de Emprendedor
|
v
GET /emprendedores/:emprendedorId
|
v
EmprendedorDetalleDto
y de manera independiente:
Perfil de Emprendedor
|
v
GET /emprendedores/:emprendedorId/productos
|
v
ProductoResumenDto[]
De esta forma, el perfil y los productos utilizan contratos independientes.
Documentación Swagger
El endpoint se encuentra documentado mediante:
@ApiOperation()
@ApiParam()
@ApiOkResponse()
@ApiNotFoundResponse()
El parámetro:
emprendedorId
se documenta como:
Number
La respuesta exitosa corresponde a:
ProductoResumenDto[]
y se documenta como arreglo mediante:
@ApiOkResponse({
type: ProductoResumenDto,
isArray: true,
})
Para mayor información consultar:
Reglas de Negocio Actuales
Actualmente las reglas pueden resumirse como:
1. emprendedorId debe ser un entero válido.
2. El emprendedor debe existir.
3. Si no existe:
404 Not Found.
4. Si existe:
buscar productos mediante ProductosService.
5. Seleccionar productos cuyo:
producto.emprendedorId === emprendedorId.
6. Transformarlos a:
ProductoResumenDto[].
7. Si no existen productos:
retornar [].
Reglas que Actualmente no se Aplican
La implementación actual no filtra todavía productos según:
stock
estadoActivo
estadoPublicacion
fechaPublicacion
disponibilidad
Por lo tanto, actualmente el criterio utilizado es:
producto.emprendedorId === emprendedorId
Posibles Mejoras Futuras
Posteriormente podrán evaluarse:
- Excluir productos sin stock.
- Incorporar estado activo o publicado.
- Incorporar paginación.
- Ordenar por precio.
- Ordenar por popularidad.
- Ordenar por fecha de creación.
- Incorporar filtros.
- Permitir búsqueda dentro de los productos del emprendedor.
Estas mejoras deberán incorporarse únicamente cuando sean requeridas por las reglas de negocio de BuenOrigen.
Relación con la Arquitectura
La funcionalidad cruza dos dominios:
Emprendedores
+
Productos
y utiliza:
EmprendedoresModule
|
v
EmprendedoresController
|
v
EmprendedoresService
|
v
ProductosService
|
v
ProductoResumenDto[]
Páginas relacionadas: