Valoraciones de Producto - bootcamp-uchile-2026/grupo-2-backend GitHub Wiki

Valoraciones de Producto

La funcionalidad Valoraciones de Producto permite mostrar las evaluaciones públicas asociadas a un producto disponible en BuenOrigen.

Esta información puede presentarse dentro del detalle del producto y permite que Frontend y Mobile muestren comentarios y puntuaciones realizadas sobre un producto determinado.

Desde la perspectiva Backend, esta funcionalidad consiste en recibir el identificador de un producto, verificar que exista, consultar sus valoraciones y devolver únicamente aquellas habilitadas para exposición pública.


Objetivo

Proporcionar a Frontend y Mobile las valoraciones públicas asociadas a un producto determinado.


Estado

Implementado

La funcionalidad se encuentra implementada mediante:

ProductosModule
      |
      v
ProductosController
      |
      v
ProductosService
      |
      v
ValoracionDetalleDto[]

Actualmente la funcionalidad permite únicamente:

Consultar valoraciones públicas

La creación, modificación o eliminación de valoraciones permanece pendiente.


Responsabilidad Backend

Actualmente el Backend debe:

  • Recibir el identificador del producto.
  • Transformar productoId a un número entero.
  • Verificar que el producto exista.
  • Consultar las valoraciones asociadas al producto.
  • Seleccionar únicamente las valoraciones cuya propiedad publicada sea true.
  • Entregar el nombre público del autor.
  • Entregar el comentario.
  • Entregar la puntuación.
  • Transformar las valoraciones a ValoracionDetalleDto.
  • Retornar una lista vacía cuando el producto exista pero no tenga valoraciones públicas.
  • Responder 404 Not Found cuando el producto no exista.

Contrato de API

Endpoint

GET /productos/:productoId/valoraciones

Ejemplo:

GET /productos/1/valoraciones

Parámetro de Ruta

productoId

Tipo esperado:

number

DTO de salida

ValoracionDetalleDto[]

La definición general del endpoint se encuentra centralizada en:

Endpoints

La estructura completa del DTO se encuentra documentada en:

DTOs


Parámetro productoId

El Controller recibe el identificador mediante:

@Param('productoId', ParseIntPipe) productoId: number

Los parámetros recibidos mediante HTTP llegan inicialmente como texto.

Por ejemplo:

GET /productos/1/valoraciones

entrega inicialmente:

"1"

ParseIntPipe transforma el valor en:

1

antes de entregarlo al método del Controller.

Conceptualmente:

HTTP
"1"
 |
 v
ParseIntPipe
 |
 v
1
 |
 v
ProductosController

Validación mediante ParseIntPipe

Una solicitud válida:

GET /productos/1/valoraciones

permite transformar correctamente:

"1"

en:

1

Sin embargo:

GET /productos/abc/valoraciones

contiene un identificador que no puede convertirse a un número entero.

En este caso NestJS responde:

400 Bad Request

antes de ejecutar la lógica de ProductosService.

Conceptualmente:

productoId
    |
    v
ParseIntPipe
    |
 +--+--+
 |     |
Sí     No
 |     |
 v     v
number 400 Bad Request
 |
 v
ProductosService

Verificación del Producto

Antes de consultar las valoraciones, el Service verifica que el producto solicitado exista.

Conceptualmente:

Producto[]
    |
    | find()
    v
producto.id === productoId
    |
 +--+--+
 |     |
Sí     No
 |     |
 v     v
Producto  undefined

Si el producto no existe:

NotFoundException

y la API responde:

404 Not Found

Modelo de Valoración

Las valoraciones se mantienen separadas del modelo principal Producto.

Conceptualmente:

Producto
   |
   | id
   |
   v
Valoracion
   |
   +---- id
   +---- productoId
   +---- autor
   +---- comentario
   +---- puntuacion
   +---- publicada

Una representación conceptual corresponde a:

export class Valoracion {
  id: number;
  productoId: number;
  autor: string;
  comentario: string;
  puntuacion: number;
  publicada: boolean;
}

Relación entre Producto y Valoración

Un producto puede poseer múltiples valoraciones.

La relación conceptual es:

Producto 1 -------- N Valoraciones

Cada valoración pertenece a un producto mediante:

productoId: number;

Por ejemplo:

Producto
id = 1
   |
   +---- Valoración 1 → productoId = 1
   |
   +---- Valoración 2 → productoId = 1
   |
   +---- Valoración 3 → productoId = 1

Selección por Producto

El Backend selecciona únicamente las valoraciones pertenecientes al producto solicitado.

Conceptualmente:

Valoracion[]
      |
      | filter()
      v
valoracion.productoId === productoId

Por ejemplo, si existen:

Valoración A → productoId = 1
Valoración B → productoId = 2
Valoración C → productoId = 1

y se consulta:

GET /productos/1/valoraciones

se seleccionan inicialmente:

Valoración A
Valoración C

Valoraciones Públicas

Además de pertenecer al producto solicitado, una valoración debe encontrarse habilitada para exposición pública.

Actualmente esta condición se representa mediante:

publicada: boolean;

Solo se entregan valoraciones cuyo valor sea:

publicada === true

Conceptualmente:

Valoraciones del producto
        |
        +---- Valoración 1
        |       publicada: true
        |             |
        |             v
        |          mostrar
        |
        +---- Valoración 2
        |       publicada: false
        |             |
        |             v
        |         no mostrar
        |
        +---- Valoración 3
                publicada: true
                      |
                      v
                   mostrar

Filtrado Completo

La selección puede representarse conceptualmente como:

Valoracion[]
      |
      | filtrar por productoId
      v
Valoraciones del producto
      |
      | filtrar publicada === true
      v
Valoraciones públicas
      |
      | map()
      v
ValoracionDetalleDto[]

Por lo tanto, una valoración debe cumplir ambas condiciones:

valoracion.productoId === productoId
             +
valoracion.publicada === true
             |
             v
     Valoración pública

ValoracionDetalleDto

Cada valoración pública se transforma a:

ValoracionDetalleDto

con la siguiente estructura:

export class ValoracionDetalleDto {
  id: number;
  autor: string;
  comentario: string;
  puntuacion: number;
}

El endpoint devuelve:

ValoracionDetalleDto[]

Información Expuesta

El contrato de salida contiene:

Campo Tipo Descripción
id number Identificador único de la valoración
autor string Nombre público del autor
comentario string Comentario realizado sobre el producto
puntuacion number Puntuación entregada

La propiedad interna:

productoId

no necesita ser devuelta porque el producto ya está identificado mediante la URL.

La propiedad:

publicada

tampoco necesita exponerse porque se utiliza internamente como criterio de filtrado.

Conceptualmente:

Valoracion
     |
     | productoId → filtrar
     | publicada  → filtrar
     |
     v
ValoracionDetalleDto
     |
     +---- id
     +---- autor
     +---- comentario
     +---- puntuacion

Puntuación

Cada valoración utiliza:

puntuacion: number;

Actualmente se considera conceptualmente una escala:

1 a 5

donde:

1 → Evaluación mínima
2
3
4
5 → Evaluación máxima

Por ejemplo:

{
  "puntuacion": 5
}

Puntuación Individual vs Puntuación Promedio

La propiedad:

puntuacion

de ValoracionDetalleDto corresponde a la evaluación de una valoración individual.

Por ejemplo:

María  → 5
Carlos → 4
Ana    → 5

El endpoint actualmente devuelve cada valoración de forma independiente.

No calcula en esta operación:

promedio
cantidad total
distribución por estrellas

Estas funcionalidades podrán incorporarse posteriormente si son requeridas.


Comentario

Cada valoración posee:

comentario: string;

Por ejemplo:

Muy buen producto y excelente calidad.

Este comentario forma parte de la información pública retornada por la API.


Autor

Cada valoración contiene:

autor: string;

que representa el nombre público utilizado para mostrar la valoración.

Por ejemplo:

{
  "autor": "María"
}

La respuesta no debe incluir información privada del usuario.

Actualmente no se exponen mediante este DTO datos como:

correo electrónico
contraseña
identificador de autenticación
dirección
teléfono

Flujo Completo de la Operación

GET /productos/1/valoraciones
             |
             v
       ParseIntPipe
             |
             v
      productoId: 1
             |
             v
    ProductosController
             |
             v
     ProductosService
             |
             | find()
             v
     ¿Existe producto?
        |
   +----+----+
   |         |
  Sí         No
   |         |
   v         v
Buscar      404
valoraciones Not Found
   |
   | filter productoId
   v
Valoraciones del producto
   |
   | filter publicada
   v
Valoraciones públicas
   |
   | map()
   v
ValoracionDetalleDto[]
   |
   v
 200 OK

Ejemplo de Solicitud

GET /productos/1/valoraciones

Ejemplo de Respuesta

[
  {
    "id": 1,
    "autor": "María",
    "comentario": "Muy buen producto y excelente calidad.",
    "puntuacion": 5
  },
  {
    "id": 2,
    "autor": "Carlos",
    "comentario": "Buena calidad y materiales.",
    "puntuacion": 4
  }
]

Respuesta HTTP:

200 OK

Producto sin Valoraciones Públicas

Si el producto existe pero no posee valoraciones que cumplan:

publicada === true

el Backend devuelve:

[]

con:

200 OK

Esto no se considera un error.

Conceptualmente:

Producto existe
       |
       v
Buscar valoraciones
       |
       v
0 valoraciones públicas
       |
       v
[]
       |
       v
200 OK

Producto con Valoraciones no Publicadas

También puede ocurrir que existan valoraciones asociadas al producto, pero todas tengan:

publicada: false

Por ejemplo:

Valoración A → publicada: false
Valoración B → publicada: false

En ese caso la respuesta pública será igualmente:

[]

con:

200 OK

Diferencia entre Producto Inexistente y Producto sin Valoraciones

Es importante distinguir ambos casos.

Producto no existe
        |
        v
404 Not Found

Mientras que:

Producto existe
pero no posee
valoraciones públicas
        |
        v
200 OK
[]

La ausencia de valoraciones no significa que el producto no exista.


Manejo de Errores

Identificador inválido

Ejemplo:

GET /productos/abc/valoraciones

Respuesta:

400 Bad Request

Gestionado mediante:

ParseIntPipe

Producto inexistente

Ejemplo:

GET /productos/999/valoraciones

Si el producto no existe:

404 Not Found

Respuestas HTTP

Código Situación
200 OK Valoraciones públicas obtenidas correctamente
200 OK con [] El producto existe pero no posee valoraciones públicas
400 Bad Request productoId no corresponde a un entero válido
404 Not Found El producto solicitado no existe

Reglas de Negocio Actuales

Actualmente las reglas implementadas pueden resumirse como:

1. productoId debe poder convertirse a entero.

2. El producto debe existir.

3. Si no existe:
      404 Not Found.

4. Buscar valoraciones asociadas mediante productoId.

5. Considerar únicamente:
      publicada === true.

6. Transformar las valoraciones públicas a:
      ValoracionDetalleDto[].

7. Si no existen valoraciones públicas:
      retornar [].

Consulta vs Registro de Valoraciones

Actualmente la funcionalidad implementada corresponde únicamente a:

CONSULTAR

mediante:

GET /productos/:productoId/valoraciones

Todavía no existe un endpoint como:

POST /productos/:productoId/valoraciones

para crear una nueva valoración.

Por lo tanto:

Consulta pública         Implementada
Creación                 Pendiente
Edición                  Pendiente
Eliminación              Pendiente
Moderación administrativa  Pendiente

Registro de Nuevas Valoraciones

Si posteriormente se implementa la creación de valoraciones, deberán definirse reglas relacionadas con:

  • Usuario autenticado.
  • Compra previa del producto.
  • Cantidad máxima de valoraciones por usuario y producto.
  • Puntuación válida.
  • Comentario obligatorio u opcional.
  • Fecha de publicación.
  • Moderación.
  • Estado de publicación.

Estas reglas no forman parte actualmente del endpoint de consulta.


Moderación

La propiedad:

publicada: boolean;

permite actualmente distinguir entre valoraciones visibles y no visibles.

Sin embargo, la funcionalidad administrativa que modifica este estado todavía no se encuentra implementada.

Conceptualmente podría evolucionar hacia:

Usuario crea valoración
        |
        v
publicada: false
        |
        v
Moderación
        |
    +---+---+
    |       |
Aprobar   Rechazar
    |
    v
publicada: true

Este flujo deberá definirse posteriormente si BuenOrigen incorpora moderación.


Posibles Ampliaciones Futuras

Posteriormente podrá evaluarse incorporar:

  • Creación de valoraciones.
  • Fecha de publicación.
  • Puntuación promedio.
  • Cantidad total de valoraciones.
  • Distribución de puntuaciones.
  • Compra verificada.
  • Identificación del usuario autenticado.
  • Edición de una valoración.
  • Eliminación de una valoración.
  • Moderación.
  • Reporte de comentarios.
  • Paginación.
  • Ordenamiento por fecha.
  • Ordenamiento por puntuación.

Estas funcionalidades no forman parte del contrato actual.


Relación con Detalle de Producto

Las valoraciones corresponden a información ampliada relacionada con:

Detalle de Producto

pero se consultan mediante un endpoint independiente.

Detalle de Producto
        |
        +-----------------------------+
        |                             |
        v                             v
ProductoDetalleDto              Valoraciones
                                      |
                                      v
                           ValoracionDetalleDto[]

Esto permite que Frontend pueda cargar la información de valoraciones independientemente del detalle principal del producto.


Separación de Responsabilidades

La información general del producto se obtiene mediante:

GET /productos/:productoId

y devuelve:

ProductoDetalleDto

Mientras que:

GET /productos/:productoId/valoraciones

devuelve:

ValoracionDetalleDto[]

Conceptualmente:

Producto
   |
   +--> Información principal
   |          |
   |          v
   |   ProductoDetalleDto
   |
   +--> Valoraciones públicas
              |
              v
      ValoracionDetalleDto[]

Documentación Swagger

El endpoint se encuentra documentado mediante decoradores de @nestjs/swagger.

Entre ellos:

@ApiOperation()
@ApiParam()
@ApiOkResponse()
@ApiNotFoundResponse()

El parámetro:

productoId

se documenta como:

Number

La respuesta exitosa corresponde a un arreglo de:

ValoracionDetalleDto

Para mayor información consultar:

OpenAPI y Swagger


Relación con la Arquitectura

La funcionalidad pertenece actualmente al dominio:

Productos

y utiliza:

ProductosModule
      |
      v
ProductosController
      |
      v
ProductosService
      |
      v
ValoracionDetalleDto[]

Páginas relacionadas: