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
| Campo | Valor |
|---|---|
artifactId | trustpilot-catalog-updater |
groupId | com.hawkersco |
version | 1.0.25 |
| Java | 25 |
| Spring Boot | 4.0.6 |
| Tipo de artefacto | jar (ejecutable, Spring Boot batch/CLI) |
| Módulos | No 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.
| Orden | Runner | Marca |
|---|---|---|
| 1 | TrustpilotCatalogUpdaterHwRunner | Hawkers Co (hawkersco.com) |
| 2 | TrustpilotCatalogUpdaterNwRunner | Northweek (northweek.com), llama a System.exit() al terminar |
.config—PiDbProperties(conexión JDBC directa a la BD del catálogo),TrustpilotProperties(@ConfigurationProperties, credenciales y business unit ID por marca)..models—ProductSfcc(modelo del JSON crudo almacenado en la tablaproducts)..utils—TrustpilotCatalogUpdaterUtils(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
| Dependencia | Propósito |
|---|---|
spring-boot-starter | Núcleo de Spring Boot (sin web, es un runner CLI) |
org.postgresql:postgresql | Driver JDBC (usado directamente, sin JPA/Hikari) |
com.hawkersco.connectors:api-connectors | TrustpilotProductsClient y modelos (Products, Product) para la API de Trustpilot |
org.apache.commons:commons-lang3 | Utilidades varias |
com.fasterxml.jackson.core:jackson-annotations | Soporte 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
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
| Trustpilot Product Reviews API | HTTP (TrustpilotProductsClient, librería api-connectors) | Saliente | Upsert 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) | Entrante | Lectura 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).
| Clave | Descripción |
|---|---|
pi.db.server / .name / .user / .password / .port | Conexión JDBC a la BD web_product_catalog |
trustpilot.username / .password | Credenciales de autenticación de Trustpilot |
trustpilot.apikey / .apisecret | Credenciales de API de Trustpilot |
trustpilot.businessunitid.hw / .nw | ID 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:
- Rotar la contraseña de BD y las credenciales de Trustpilot.
- Sustituir los valores hardcodeados de
application.propertiespor credenciales de un entorno de desarrollo aislado. - 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(baseeclipse-temurin:25-jre,containerizingMode=packaged), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/trustpilot-catalog-updater:<tag>. - Orquestación: Kubernetes
CronJoben el clúster GKEpi-cluster-hw, namespacepi, contenedor no privilegiado, ejecutándose diariamente a las 11:00 (Europe/Madrid). - CI/CD (Jenkins): pipeline real de 3 etapas —
Checkout→Build & Push→Deploy to GKE. ElCLAUDE.mddescribe un pipeline conKICS security scan,SonarQube analysisyTestque no existen en elJenkinsfileactual (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
TrustpilotCatalogUpdaterHwRunnerniTrustpilotCatalogUpdaterNwRunneraplican ningún filtro de marca a la consultaSELECT rawdata FROM products— ambos leen la tabla completa y solo difieren en el dominio usado para construir el enlace del producto y en elbusinessUnitIdde destino. ElCLAUDE.mdno aclara si la tablaproductsya 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 siupsertProductsInBatchesinterpreta una lista vacía como "sin productos" (comportamiento de la libreríaapi-connectorsno 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
DriverManagery 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.