Skip to main content

update-pim-web

1. Descripción general

Según el pom.xml, el proyecto se describe como "Update PIM Web". Es un microservicio batch (runner) que descarga el catálogo de producto desde SalesLayer (en formato ZIP con 3 CSV), lo transforma en bullets de atributos multilingües (10 idiomas) y actualiza el PIM web mediante peticiones por lotes a la API de SalesLayer PIM.

2. Información técnica

CampoValor
artifactIdupdate-pim-web
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 un único CommandLineRunner (UpdatePimWebRunner).

  • .clientPimHttpClient, SlackHttpClient (interfaces @HttpExchange locales al proyecto).
  • .configPimHttpClientConfiguration, SlackHttpClientConfiguration (wiring de los RestClient).
  • .model — 18 clases modelo (PimProduct con 71 campos vía OpenCSV, PimBullets, PimFrames, y modelos de atributo: PimGender, PimLensColor, PimFrameMaterial, etc.).
  • .utilsUpdatePimWebUtil (transforma filas CSV de bullets en texto multilingüe formateado).
flowchart TD
A[UpdatePimWebRunner] -->|descarga pim.zip| B[SalesLayer API]
A -->|descomprime y parsea 3 CSV| C[Products / Bullets / Frames]
A -->|construye bullets por 10 idiomas| D[Producto PIM multilingüe]
D -->|lotes de 500, PUT| E[PimHttpClient → SalesLayer PIM API]
A -.->|error de descarga o de lote| F[Slack]

Flujo: borra y recrea el directorio de trabajo local, descarga pim.zip desde un endpoint de conector de SalesLayer (URL con un ID de conector hardcodeado en el código fuente, ver hallazgo en la sección 13) y lo descomprime; parsea los 3 CSV (Products, Bullets, Frames) con OpenCSV; construye 14 mapas de bullets multilingües (color de montura, material de montura, género, apariencia/categoría/color/material de lente, polarizado, color de correa, grupo objetivo, color de patilla, blue blocking, talla, monturas); para cada producto y cada uno de los 10 idiomas (en, de, es, es_CL, es_CO, es_MX, fr, el, it, pt) genera 4 bloques de texto (bullets generales, de lente, de montura y de grupo objetivo); agrupa los productos en lotes de 500 y los envía por PUT a la API de PIM; notifica a Slack si un lote falla o si la descarga inicial falla (en este último caso, además, termina el proceso inmediatamente).

4. Dependencias principales

DependenciaPropósito
spring-boot-starterNúcleo de Spring Boot (sin web, es un runner CLI)
spring-webRestClient/@HttpExchange
com.opencsv:opencsvParseo de los 3 ficheros CSV a modelos Java
com.hawkersco:pim-clientModelos de request/response de la API de SalesLayer PIM (PIMBulletProductRequest)
com.hawkersco:slack-clientModelos de notificación de Slack
com.hawkersco:pi-function-commonsDirectoryUtils
LombokGeneración de código boilerplate en los modelos

5. API / Endpoints

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

6. Integraciones externas

SistemaProtocoloDirecciónDetalle
SalesLayer (descarga de catálogo)HTTP (descarga directa de ZIP)EntranteDescarga de pim.zip (Products/Bullets/Frames) mediante un conector configurado
SalesLayer PIM APIHTTP PUT (PimHttpClient)SalienteActualización por lotes (500) de los bullets multilingües de producto
SlackHTTP (SlackHttpClient)SalienteNotificación de error de descarga o de lote fallido

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
pim.client.urlURL de la API de SalesLayer PIM
pim.client.code / .secretKeyCredenciales de autenticación de la API de PIM
slack.client.url / .auth.token / .channel.idConfiguración de Slack

⚠️ Alerta de seguridad

El fichero src/main/resources/application.properties (perfil local) contiene actualmente credenciales reales en texto plano: la clave secreta (secretKey) de la API de SalesLayer PIM, y el token de bot de Slack (el mismo ya señalado en otros proyectos de este ecosistema). Además, el ID del conector de descarga de SalesLayer está hardcodeado directamente en el código fuente Java (UpdatePimWebRunner.URL_DOWNLOAD), no en un fichero de propiedades — no se ha reproducido en este documento. Ninguno de estos valores se ha reproducido. Se recomienda:

  1. Rotar la clave secreta de la API de PIM y el token de Slack.
  2. Mover el ID del conector de SalesLayer de URL_DOWNLOAD a una propiedad de configuración inyectada por variable de entorno, para poder rotarlo sin necesidad de un redeploy de código.
  3. Sustituir los valores hardcodeados de application.properties por credenciales de un entorno de desarrollo aislado.
  4. Revisar el historial de control de versiones, ya que estas credenciales pueden seguir expuestas en commits anteriores.

8. Persistencia

No aplica a este proyecto. No usa base de datos: el catálogo se obtiene íntegramente de los CSV descargados de SalesLayer en cada ejecución, sin persistencia local salvo los ficheros temporales de trabajo.

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 cada 6 horas (schedule: "0 */6 * * *", zona horaria Europe/Madrid, concurrencyPolicy: Forbid, activeDeadlineSeconds: 3600). Único runner, descrito en la sección 3.

10. Ejecución en local

Requisitos previos: JDK 25, Maven, credenciales válidas de SalesLayer PIM y de Slack en application.properties.

# Compilar sin tests
./mvnw clean package -DskipTests

# Compilar con tests
./mvnw clean install

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

# Ejecutar la aplicación localmente
./mvnw spring-boot:run

# Build Docker
docker build -t update-pim-web .

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 SalesLayer PIM.

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/update-pim-web:<tag>.
  • Orquestación: Kubernetes CronJob en el clúster GKE pi-cluster-hw, namespace pi, con credenciales de cuenta de servicio de GCP montadas por volumen (GOOGLE_APPLICATION_CREDENTIALS), ejecutándose cada 6 horas. No se ha encontrado uso de APIs de Google en el código de este proyecto (mismo patrón detectado en showroom-update-stock y theiconic-create-db).
  • CI/CD (Jenkins): pipeline real de 3 etapas — CheckoutBuild & PushDeploy to GKE, consistente con lo descrito en el CLAUDE.md.

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/update-pim-web/

12. Manejo de errores y logging

No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). Un fallo al descargar el ZIP inicial se notifica a Slack y termina el proceso inmediatamente (System.exit), sin intentar procesar el resto del flujo. Un fallo al enviar un lote a la API de PIM se notifica a Slack pero no interrumpe el envío de los lotes restantes. Logging mediante java.util.logging.Logger estándar (consola).

13. Notas y consideraciones

  • ID de conector de SalesLayer hardcodeado en código fuente Java: la constante URL_DOWNLOAD en UpdatePimWebRunner incluye el ID del conector de descarga directamente en el código, no en application.properties. A diferencia de una credencial en fichero de configuración, este valor no puede rotarse sin modificar el código y volver a desplegar — mismo patrón de severidad detectado en pi-generate-credentials y logistic-erp en este ecosistema.
  • CLAUDE.md verificado y consistente con el código: el flujo completo (descarga → descompresión → parseo de 3 CSV → construcción de bullets en 10 idiomas → envío en lotes de 500 → notificación Slack), las clases clave y las dependencias externas coinciden con el código real, verificado directamente en UpdatePimWebRunner.
  • Ver alerta de seguridad en la sección 7 sobre credenciales reales y el ID de conector expuestos en el proyecto.