Skip to main content

trustpilot-catalog-updater

1. Descripción general

Según el pom.xml, el proyecto se describe como "Trustpilot Catalog Updater". Es un microservicio batch (runner) que lee el catálogo de producto almacenado en PostgreSQL (web_product_catalog) y lo sincroniza con Trustpilot (módulo de reseñas de producto), ejecutándose una vez para la marca Hawkers Co y otra para Northweek.

2. Información técnica

CampoValor
artifactIdtrustpilot-catalog-updater
groupIdcom.hawkersco
version1.0.25
Java25
Spring Boot4.0.6
Tipo de artefactojar (ejecutable, Spring Boot batch/CLI)
MódulosNo aplica (proyecto de módulo único)

3. Arquitectura y diseño

No es una API REST: es una aplicación Spring Boot CLI con 2 CommandLineRunner, ambos activos.

OrdenRunnerMarca
1TrustpilotCatalogUpdaterHwRunnerHawkers Co (hawkersco.com)
2TrustpilotCatalogUpdaterNwRunnerNorthweek (northweek.com), llama a System.exit() al terminar
  • .configPiDbProperties (conexión JDBC directa a la BD del catálogo), TrustpilotProperties (@ConfigurationProperties, credenciales y business unit ID por marca).
  • .modelsProductSfcc (modelo del JSON crudo almacenado en la tabla products).
  • .utilsTrustpilotCatalogUpdaterUtils (lectura JDBC + transformación a modelo Trustpilot).
flowchart TD
A["1. TrustpilotCatalogUpdaterHwRunner"] -->|SELECT rawdata FROM products| B[(web_product_catalog · products)]
C["2. TrustpilotCatalogUpdaterNwRunner"] --> B
A -->|createTrustPilotProduct, dominio hawkersco.com| D[TrustpilotProductsClient]
C -->|createTrustPilotProduct, dominio northweek.com| D
D -->|upsertProductsInBatches, lotes de 500| E[Trustpilot API · business unit HW/NW]

Flujo (idéntico en ambos runners, solo cambia el dominio del enlace y el businessUnitId): consulta vía JDBC directo (DriverManager, sin pool de conexiones) todas las filas de la tabla products, deserializa el campo rawdata (JSON) a ProductSfcc; por cada producto, construye un Product de Trustpilot (SKU, marca y EAN desde los atributos de sistema, nombre desde los atributos localizados, e imagen principal eligiendo variantes -f./_f. —frontal— sobre -l./_l. —grande—); finalmente sube el catálogo completo a Trustpilot en lotes de 500 mediante upsertProductsInBatches.

4. Dependencias principales

DependenciaPropósito
spring-boot-starterNúcleo de Spring Boot (sin web, es un runner CLI)
org.postgresql:postgresqlDriver JDBC (usado directamente, sin JPA/Hikari)
com.hawkersco.connectors:api-connectorsTrustpilotProductsClient y modelos (Products, Product) para la API de Trustpilot
org.apache.commons:commons-lang3Utilidades varias
com.fasterxml.jackson.core:jackson-annotationsSoporte de anotaciones Jackson
com.google.code.gson:gson (transitiva)Deserialización del JSON crudo de producto
Lombok (annotation processor)Generación de código boilerplate

5. API / Endpoints

No aplica a este proyecto. Es un batch/runner sin capa REST.

6. Integraciones externas

SistemaProtocoloDirecciónDetalle
Trustpilot Product Reviews APIHTTP (TrustpilotProductsClient, librería api-connectors)SalienteUpsert por lotes (500) del catálogo, una vez por business unit (HW y NW)
PostgreSQL (web_product_catalog)JDBC directo (DriverManager, sin datasource de Spring)EntranteLectura completa de la tabla products

7. Configuración

En producción (application-pro.properties) las credenciales llegan por variables de entorno inyectadas como Secret de Kubernetes; en local (application.properties) el repositorio contiene actualmente valores reales hardcodeados (ver alerta de seguridad).

ClaveDescripción
pi.db.server / .name / .user / .password / .portConexión JDBC a la BD web_product_catalog
trustpilot.username / .passwordCredenciales de autenticación de Trustpilot
trustpilot.apikey / .apisecretCredenciales de API de Trustpilot
trustpilot.businessunitid.hw / .nwID de business unit de Trustpilot por marca

⚠️ Alerta de seguridad

El fichero src/main/resources/application.properties (perfil local) contiene actualmente credenciales reales en texto plano: contraseña de la base de datos PostgreSQL web_product_catalog, y credenciales completas de la API de Trustpilot (usuario, contraseña, API key y API secret). Ninguno de estos valores se ha reproducido en este documento. Se recomienda:

  1. Rotar la contraseña de BD y las credenciales de Trustpilot.
  2. Sustituir los valores hardcodeados de application.properties por credenciales de un entorno de desarrollo aislado.
  3. Revisar el historial de control de versiones, ya que estas credenciales pueden seguir expuestas en commits anteriores.

8. Persistencia

Base de datos PostgreSQL web_product_catalog, tabla products (columna rawdata con el JSON completo del producto). El acceso es JDBC directo vía DriverManager (no JPA, no Hikari, sin pool de conexiones — se abre y cierra una conexión por ejecución). No hay Flyway/Liquibase en este repositorio.

9. Procesos programados y mensajería

No hay @Scheduled ni listeners de colas: la periodicidad la impone el CronJob de Kubernetes (k8s/cronjob.yaml), que ejecuta el contenedor una vez al día a las 11:00 (schedule: "00 11 * * *", zona horaria Europe/Madrid). Se ejecutan en orden los 2 runners de la tabla de la sección 3.

10. Ejecución en local

Requisitos previos: JDK 25, Maven, acceso a la BD web_product_catalog y credenciales válidas de la API de Trustpilot.

# Compilar
./mvnw clean install

# Compilar sin tests
./mvnw clean package -DskipTests

# Ejecutar tests
./mvnw test

# Ejecutar un test concreto
./mvnw test -Dtest=TrustpilotCatalogUpdaterApplicationTests

Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o el catálogo reflejado en el panel de Trustpilot Business.

11. Despliegue

  • Imagen: construida con jib-maven-plugin (base eclipse-temurin:25-jre, containerizingMode=packaged), publicada en europe-west3-docker.pkg.dev/pi-saldum/pi-repo/trustpilot-catalog-updater:<tag>.
  • Orquestación: Kubernetes CronJob en el clúster GKE pi-cluster-hw, namespace pi, contenedor no privilegiado, ejecutándose diariamente a las 11:00 (Europe/Madrid).
  • CI/CD (Jenkins): pipeline real de 3 etapas — CheckoutBuild & PushDeploy to GKE. El CLAUDE.md describe un pipeline con KICS security scan, SonarQube analysis y Test que no existen en el Jenkinsfile actual (mismo patrón detectado en varios proyectos hermanos de este lote).

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/trustpilot-catalog-updater/

12. Manejo de errores y logging

No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). getProductSfccList captura cualquier excepción de la consulta JDBC, registra Level.SEVERE y devuelve una lista vacía en lugar de propagar el error — si la consulta falla, el runner sube un catálogo vacío a Trustpilot sin que la ejecución falle explícitamente (ver hallazgo en la sección 13). Logging mediante java.util.logging.Logger estándar (consola).

13. Notas y consideraciones

  • Ambos runners suben exactamente el mismo catálogo, sin filtrar por marca: ni TrustpilotCatalogUpdaterHwRunner ni TrustpilotCatalogUpdaterNwRunner aplican ningún filtro de marca a la consulta SELECT rawdata FROM products — ambos leen la tabla completa y solo difieren en el dominio usado para construir el enlace del producto y en el businessUnitId de destino. El CLAUDE.md no aclara si la tabla products ya contiene únicamente productos de una marca por fila (con un campo de marca ignorado en la consulta) o si de verdad se está subiendo el catálogo completo de ambas marcas a los dos business units de Trustpilot indistintamente. Pendiente de verificar con el equipo si esto es el comportamiento esperado.
  • Fallo silencioso en la lectura de BD: si la consulta JDBC falla (p. ej. caída de conexión), getProductSfccList() captura la excepción, la registra y devuelve una lista vacía; el runner continúa y ejecuta un upsert de un catálogo vacío en Trustpilot en lugar de detener la ejecución con error. Esto podría vaciar accidentalmente los productos ya publicados en Trustpilot si upsertProductsInBatches interpreta una lista vacía como "sin productos" (comportamiento de la librería api-connectors no verificable desde este repositorio).
  • Acceso a BD por JDBC directo, no JPA: a diferencia de la mayoría de proyectos de este ecosistema (que usan Spring Data JPA + HikariCP), este runner abre la conexión manualmente con DriverManager y no usa pool de conexiones — aceptable para un batch de una única consulta por ejecución, pero un patrón distinto al resto de proyectos hermanos.
  • Pipeline de Jenkins más simple de lo documentado: ver hallazgo en la sección 11.
  • Ver alerta de seguridad en la sección 7 sobre credenciales reales expuestas en application.properties.