Skip to main content

PIM Client

1. Descripción general

pim-client es una librería cliente reutilizable (JAR) que encapsula la comunicación con un servicio PIM (Product Information Management) externo, usado para actualizar contenido de producto (bullet points/puntos destacados en múltiples idiomas y categorías: general, lente, montura y público objetivo). El proyecto no expone ningún endpoint REST propio; se publica en el registro de artefactos Maven interno y es consumido por otros microservicios del ecosistema Hawkers que necesiten sincronizar esta información hacia el PIM.

Cada petición saliente se firma añadiendo parámetros de query calculados con SHA-256 a partir del código de cliente, la clave secreta, un timestamp y un valor aleatorio, replicando un esquema de autenticación por firma habitual en integraciones PIM/PXM.

2. Información técnica

PropiedadValor
artifactIdpim-client
groupIdcom.hawkersco
version1.0.25-SNAPSHOT
Java25
Spring Boot4.0.6
Tipo de artefactoJAR (librería, no ejecutable)
MódulosProyecto único (no multi-módulo)

3. Arquitectura y diseño

Estructura del proyecto:

com.hawkersco.pimclient
├── PimClientApplication.java # Clase @SpringBootApplication (residual, sin lógica)
├── client/
│ └── PimClient.java # Interfaz @HttpExchange con la operación updatePim
├── config/
│ └── PimClientConfig.java # @AutoConfiguration principal (firma SHA-256 vía interceptor)
└── request/
└── PIMBulletProductRequest.java # POJO de request: InputData → List<Product> con bullets multi-idioma

Flujo principal

sequenceDiagram
participant Consumidor as Microservicio consumidor
participant Client as PimClient
participant API as Servicio PIM

Consumidor->>Client: updatePim(PIMBulletProductRequest)
Client->>Client: interceptor genera unique + timestamp + SHA-256(code+secretKey+timestamp+unique)
Client->>API: GET (con body JSON) ?code=...&time=...&unique=...&key256=...
API-->>Client: ResponseEntity<String>
Client-->>Consumidor: ResponseEntity<String>

La autoconfiguración (PimClientConfig, anotada @AutoConfiguration pese a no llevar el sufijo AutoConfiguration en su nombre de clase) se activa condicionalmente con @ConditionalOnProperty(prefix = "pim.client", name = {"url", "code", "secretKey"}). Registra el bean PimClient con un RestClient cuyo requestInterceptor:

  1. Genera un entero aleatorio (unique, 0–99999) y el timestamp actual en segundos.
  2. Calcula SHA-256(pimClientCode + pimClientSecretKey + timestamp + unique) en hexadecimal (key256).
  3. Reconstruye la URI de la petición añadiendo los query params code, time, unique y key256.
  4. Envuelve la petición original en un HttpRequest anónimo con la nueva URI, delegando el resto de la ejecución.

El registro de la autoconfiguración se realiza mediante el fichero estándar de Spring Boot:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

4. Dependencias principales

DependenciaVersiónPropósito
spring-boot-starter(gestionada SB4)Base de Spring Boot (contexto, autoconfiguración)
spring-web(gestionada SB4)RestClient + @HttpExchange / HttpServiceProxyFactory
com.fasterxml.jackson.core:jackson-annotations(gestionada SB4)Anotaciones @JsonProperty en PIMBulletProductRequest
com.google.code.gson:gson(gestionada SB4)Anotaciones @SerializedName en PIMBulletProductRequest (soporte dual con Jackson)
org.projectlombok:lombok1.18.42 (dependencia; annotationProcessorPath del compilador usa 1.18.46)Generación de boilerplate en el POJO de request
spring-boot-starter-test(gestionada SB4)Testing (scope test)

5. API / Endpoints

No aplica a este proyecto. pim-client es una librería cliente JAR que no expone endpoints REST propios. La operación que encapsula sobre el servicio PIM se detalla en la sección 6.

6. Integraciones externas

Servicio PIM (actualización de bullet points de producto)

Método clienteHTTPRuta remotaDirecciónDescripción
updatePimGET`` (raíz de pim.client.url, con query params de firma)SalienteEnvía la actualización de bullet points de uno o varios productos

Nota: updatePim está anotado con @GetExchange pero recibe un @RequestBody — combinación atípica (un GET normalmente no lleva cuerpo). Ver detalle en sección 13.

Ejemplo de payload PIMBulletProductRequest (resumido; el modelo real incluye variantes por idioma — de, es, es_CL, es_CO, es_MX, fr, it, pt, el — para cada una de las categorías Bullets, Lens Bullets, Frame Bullets y Target Bullets):

{
"input_data": {
"products": [
{
"Referencia de producto": "SKU-001",
"Bullets": "Producto premium",
"Bullets:es": "Producto premium",
"Bullets:fr": "Produit premium",
"Lens Bullets:es": "Lente polarizada",
"Frame Bullets:es": "Montura ligera",
"Target Bullets:es": "Unisex"
}
]
}
}

Los nombres de campo JSON usan literalmente espacios y mayúsculas en español/inglés mixto (p. ej. "Referencia de producto", "Lens Bullets:es_MX"), dictados por el contrato del servicio PIM remoto.

Protocolo: HTTP (JSON, contentType = application/json). Autenticación: firma SHA-256 por petición vía query params (code, time, unique, key256), sin cabeceras de autenticación ni token OAuth.

7. Configuración

No se incluye ningún application.properties/application.yml en la librería. Las propiedades deben ser inyectadas por la aplicación consumidora.

Propiedades requeridas (prefijo pim.client)

PropiedadDescripciónEjemplo de valor
pim.client.urlURL base del servicio PIM (activa la autoconfiguración)${PIM_CLIENT_URL}
pim.client.codeCódigo de cliente usado en la firma de cada petición${PIM_CLIENT_CODE}
pim.client.secretKeyClave secreta usada en la firma SHA-256 de cada petición${PIM_CLIENT_SECRET_KEY}

Importante: Si falta cualquiera de las tres propiedades (pim.client.url, pim.client.code, pim.client.secretKey), el bean PimClient no se registra (condición @ConditionalOnProperty con las tres claves).

Variables de entorno recomendadas

VariablePropiedad mapeada
PIM_CLIENT_URLpim.client.url
PIM_CLIENT_CODEpim.client.code
PIM_CLIENT_SECRET_KEYpim.client.secretKey

8. Persistencia

No aplica a este proyecto. La librería no accede a ninguna base de datos ni mantiene estado en memoria.

9. Procesos programados y mensajería

No aplica a este proyecto. No existen jobs @Scheduled, listeners de colas/topics ni runners batch.

10. Ejecución en local

pim-client es una librería JAR, no una aplicación ejecutable. No tiene servidor embebido ni endpoint de health.

Requisitos previos

  • Java 25
  • Maven 3.x
  • Acceso al registro de artefactos Maven interno (europe-west3-maven.pkg.dev/pi-saldum/pi-repo-maven) para resolver/publicar dependencias.

Compilar e instalar en repositorio local

# Compilar e instalar
./mvnw clean install

# Empaquetar JAR
./mvnw clean package

# Compilar sin tests
./mvnw clean install -DskipTests

# Ejecutar tests
./mvnw test

Uso como dependencia en un microservicio consumidor

<dependency>
<groupId>com.hawkersco</groupId>
<artifactId>pim-client</artifactId>
<version>1.0.25-SNAPSHOT</version>
</dependency>

La autoconfiguración se activa automáticamente al declarar pim.client.url, pim.client.code y pim.client.secretKey en la aplicación consumidora.

11. Despliegue

El pipeline de Jenkins (Jenkinsfile) consta de dos etapas:

  1. Checkout — descarga el código del repositorio.
  2. Publish to Artifact Registry — ejecuta mvn deploy -DskipTests para publicar el JAR en Google Artifact Registry.

CLAUDE.md menciona sudo mvn -B -DskipTests clean install como comando de CI, que difiere ligeramente del mvn deploy -DskipTests presente en el Jenkinsfile actual del repositorio (se documenta este último por ser el realmente presente).

ParámetroValor
JDKJDK25 (tool Jenkins)
MavenMaven3 (tool Jenkins)
Repositorioeurope-west3-maven.pkg.dev/pi-saldum/pi-repo-maven (Artifact Registry GCP)

No existe Dockerfile ni despliegue como servicio independiente; el artefacto es un JAR publicado en el registro Maven.

Job de Jenkins:

https://jenkins-pi.hawkersco.net/job/pim-client/

12. Manejo de errores y logging

La librería no implementa ninguna estrategia propia de manejo de excepciones ni logging estructurado. Las excepciones de red o HTTP propagadas por RestClient (como RestClientResponseException) son responsabilidad del servicio consumidor, ya que updatePim no declara ningún throws explícito. Si generateSHA256 fallara por ausencia del algoritmo SHA-256 (NoSuchAlgorithmException), el método devuelve null en lugar de propagar la excepción, lo que generaría una petición con key256=null en la query string en vez de fallar explícitamente — escenario improductivo en la práctica dado que SHA-256 es un algoritmo JCA estándar siempre disponible en la JVM. No hay configuración de logback ni de niveles de log específicos en la librería.

13. Notas y consideraciones

  • updatePim combina @GetExchange con @RequestBody: El método updatePim está anotado @GetExchange pero declara un parámetro @RequestBody. Enviar un cuerpo en una petición GET es un patrón atípico y no estandarizado uniformemente entre clientes HTTP/servidores (algunos lo ignoran, otros lo rechazan). Pendiente de verificar contra el contrato real del servicio PIM si esto funciona como se espera o si debería ser un @PostExchange.

  • Firma con Math.random(): El valor unique se genera con Math.random() en lugar de un generador aleatorio criptográficamente seguro (SecureRandom). Dado que unique forma parte del material firmado (no es un secreto en sí, solo aporta variabilidad para evitar repetición de firmas), el impacto de seguridad es limitado, pero es una desviación de las prácticas recomendadas para valores usados en esquemas de firma.

  • Nombre de clase inconsistente con el patrón del ecosistema: La autoconfiguración se llama PimClientConfig en lugar de PimClientAutoConfiguration, a diferencia de la convención de nombres seguida por el resto de clientes del ecosistema documentados hasta ahora.

  • Versión de Lombok inconsistente: El pom.xml fija org.projectlombok:lombok en 1.18.42, mientras que el annotationProcessorPath del compilador usa 1.18.46 — misma inconsistencia observada en logisfashion-client y meli-client.

  • Claves JSON con espacios y mayúsculas mixtas: Los nombres de campo en PIMBulletProductRequest (p. ej. "Referencia de producto", "Lens Bullets:es_MX") replican literalmente las columnas/etiquetas del sistema PIM origen, en lugar de un formato JSON convencional (snake_case/camelCase) — dictado por el contrato externo, no modificable sin romper la integración.

  • Sin tests implementados: No existe directorio src/test/ en el proyecto.

  • PimClientApplication.java: Clase principal de Spring Boot en el paquete raíz, sin funcionalidad operativa. Artefacto residual de la generación inicial del proyecto con Spring Initializr, mismo patrón observado en otros clientes del ecosistema.