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
| Propiedad | Valor |
|---|---|
artifactId | pim-client |
groupId | com.hawkersco |
version | 1.0.25-SNAPSHOT |
| Java | 25 |
| Spring Boot | 4.0.6 |
| Tipo de artefacto | JAR (librería, no ejecutable) |
| Módulos | Proyecto ú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:
- Genera un entero aleatorio (
unique, 0–99999) y el timestamp actual en segundos. - Calcula
SHA-256(pimClientCode + pimClientSecretKey + timestamp + unique)en hexadecimal (key256). - Reconstruye la URI de la petición añadiendo los query params
code,time,uniqueykey256. - Envuelve la petición original en un
HttpRequestanó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
| Dependencia | Versión | Propó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:lombok | 1.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 cliente | HTTP | Ruta remota | Dirección | Descripción |
|---|---|---|---|---|
updatePim | GET | `` (raíz de pim.client.url, con query params de firma) | Saliente | Enví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)
| Propiedad | Descripción | Ejemplo de valor |
|---|---|---|
pim.client.url | URL base del servicio PIM (activa la autoconfiguración) | ${PIM_CLIENT_URL} |
pim.client.code | Código de cliente usado en la firma de cada petición | ${PIM_CLIENT_CODE} |
pim.client.secretKey | Clave 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 beanPimClientno se registra (condición@ConditionalOnPropertycon las tres claves).
Variables de entorno recomendadas
| Variable | Propiedad mapeada |
|---|---|
PIM_CLIENT_URL | pim.client.url |
PIM_CLIENT_CODE | pim.client.code |
PIM_CLIENT_SECRET_KEY | pim.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:
- Checkout — descarga el código del repositorio.
- Publish to Artifact Registry — ejecuta
mvn deploy -DskipTestspara 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ámetro | Valor |
|---|---|
| JDK | JDK25 (tool Jenkins) |
| Maven | Maven3 (tool Jenkins) |
| Repositorio | europe-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
-
updatePimcombina@GetExchangecon@RequestBody: El métodoupdatePimestá anotado@GetExchangepero declara un parámetro@RequestBody. Enviar un cuerpo en una peticiónGETes 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 valoruniquese genera conMath.random()en lugar de un generador aleatorio criptográficamente seguro (SecureRandom). Dado queuniqueforma 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
PimClientConfigen lugar dePimClientAutoConfiguration, 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.xmlfijaorg.projectlombok:lomboken1.18.42, mientras que elannotationProcessorPathdel compilador usa1.18.46— misma inconsistencia observada enlogisfashion-clientymeli-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.