Showroom Client
1. Descripción general
showroom-client es una librería cliente reutilizable (JAR) que encapsula la comunicación con el marketplace Showroom (Showroomprivé). 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 aceptar pedidos, consultar ofertas, actualizar tracking/envío e importar ficheros de stock en Showroom.
La librería implementa un patrón de cliente dual: dos beans (ShowroomClient y ShowroomFlashClient) que comparten exactamente el mismo contrato de operaciones (ShowroomOperations) pero se configuran con URL y API key independientes, para cubrir el canal estándar y el canal "Flash" (ventas flash) de Showroom respectivamente.
2. Información técnica
| Propiedad | Valor |
|---|---|
artifactId | showroom-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.showroomclient
├── ShowroomClientApplication.java # Clase @SpringBootApplication (residual, sin lógica)
├── client/
│ ├── ShowroomOperations.java # Interfaz @HttpExchange con las 7 operaciones de negocio (contrato común)
│ ├── ShowroomClient.java # Interfaz marcadora que extiende ShowroomOperations (canal estándar)
│ └── ShowroomFlashClient.java # Interfaz marcadora que extiende ShowroomOperations (canal Flash)
├── config/
│ ├── ShowroomConfig.java # @AutoConfiguration de ShowroomClient (prefijo showroom.credentials)
│ └── ShowroomFlashConfig.java # @AutoConfiguration de ShowroomFlashClient (prefijo showroom-flash.credentials)
├── request/
│ ├── AcceptOrderShowroomRequest.java # Aceptación/rechazo de líneas de pedido
│ └── TrackingShowroomRequest.java # Datos de transportista y número de seguimiento
└── response/
├── OrdersShowroomResponse.java # Respuesta de listado de pedidos
└── OffersShowroomResponse.java # Respuesta de listado de ofertas
Flujo principal (patrón dual)
sequenceDiagram
participant Consumidor as Microservicio consumidor
participant Client as ShowroomClient / ShowroomFlashClient
participant API as API Showroom (estándar o Flash)
Consumidor->>Client: acceptOrder / getOrderList / updateTracking / importStockFile / ...
Client->>API: request + header Authorization: <apiKey>
API-->>Client: ResponseEntity<T>
Client-->>Consumidor: ResponseEntity<T>
ShowroomOperations define las siete operaciones de negocio como interfaz @HttpExchange; ShowroomClient y ShowroomFlashClient son interfaces vacías que únicamente extienden ShowroomOperations — este patrón de "interfaz marcadora" permite que HttpServiceProxyFactory genere dos beans Spring de tipo distinto (necesario para que Spring pueda diferenciarlos por tipo al inyectarlos) a partir del mismo contrato de métodos, evitando duplicar las anotaciones @HttpExchange en dos interfaces separadas.
ShowroomConfig (@ConditionalOnProperty sobre showroom.credentials.url/key) construye el RestClient de ShowroomClient con la cabecera Authorization fijada al valor de la API key. ShowroomFlashConfig (@ConditionalOnProperty sobre showroom-flash.credentials.url/key) hace lo mismo para ShowroomFlashClient, añadiendo además Content-Type: application/json como cabecera por defecto (diferencia menor respecto a ShowroomConfig, que no la fija).
El registro de ambas autoconfiguraciones 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 / soporte multipart |
com.google.code.gson:gson | 2.14.0 | Anotaciones @SerializedName en los modelos (soporte dual con Jackson) |
com.fasterxml.jackson.core:jackson-databind | (gestionada SB4) | Serialización/deserialización Jackson en los modelos |
org.projectlombok:lombok | 1.18.46 | Generación de boilerplate en los modelos (@Data, getters, setters) |
spring-boot-starter-test | (gestionada SB4) | Testing (scope test) |
5. API / Endpoints
No aplica a este proyecto. showroom-client es una librería cliente JAR que no expone endpoints REST propios. Las operaciones que encapsula sobre la API de Showroom se detallan en la sección 6.
6. Integraciones externas
API de Showroom (ShowroomOperations, común a ambos canales)
| Método | HTTP | Ruta remota | Descripción |
|---|---|---|---|
acceptOrder | PUT | /api/orders/{orderId}/accept | Acepta un pedido especificando qué líneas se aceptan |
getOrderListWithStatus | GET | /api/orders?order_state_codes&start_date&max&offset | Lista pedidos paginados filtrados por estado y fecha de inicio |
getOrderList | GET | /api/orders?start_date&max&offset | Lista pedidos paginados desde una fecha de inicio, sin filtro de estado |
getOffers | GET | /api/offers?max&offset | Lista ofertas paginadas |
updateOffers | POST | /api/offers | Actualiza ofertas mediante un payload JSON crudo |
updateTracking | PUT | /api/orders/{orderId}/tracking | Actualiza la información de tracking de un pedido |
updateShip | PUT | /api/orders/{orderId}/ship | Marca un pedido como enviado |
importStockFile | POST | /api/offers/stock/imports | Importa niveles de stock desde un fichero (multipart) |
Ejemplo de payload acceptOrder (AcceptOrderShowroomRequest):
{
"order_lines": [
{ "id": "ORDLINE-001", "accepted": true },
{ "id": "ORDLINE-002", "accepted": false }
]
}
Ejemplo de payload updateTracking (TrackingShowroomRequest):
{
"carrier_code": "DHL",
"carrier_name": "DHL Express",
"carrier_url": "https://dhl.example/tracking",
"tracking_number": "1234567890"
}
Protocolo: HTTPS REST (JSON; multipart/form-data para importStockFile). Autenticación: cabecera estática Authorization con la API key correspondiente a cada canal (estándar o Flash), sin flujo de token/refresh.
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
| Propiedad | Descripción | Ejemplo de valor |
|---|---|---|
showroom.credentials.url | URL base del canal estándar de Showroom (activa ShowroomConfig) | ${SHOWROOM_URL} |
showroom.credentials.key | API key del canal estándar (cabecera Authorization) | ${SHOWROOM_API_KEY} |
showroom-flash.credentials.url | URL base del canal Flash de Showroom (activa ShowroomFlashConfig) | ${SHOWROOM_FLASH_URL} |
showroom-flash.credentials.key | API key del canal Flash (cabecera Authorization) | ${SHOWROOM_FLASH_API_KEY} |
Importante: Cada bean se activa de forma independiente; un consumidor puede usar solo el canal estándar, solo el Flash, o ambos, según qué pares
url/keydeclare.
Variables de entorno recomendadas
| Variable | Propiedad mapeada |
|---|---|
SHOWROOM_URL | showroom.credentials.url |
SHOWROOM_API_KEY | showroom.credentials.key |
SHOWROOM_FLASH_URL | showroom-flash.credentials.url |
SHOWROOM_FLASH_API_KEY | showroom-flash.credentials.key |
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
showroom-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 sin tests
./mvnw -B -DskipTests clean install
# Compilar con tests
./mvnw clean install
# Ejecutar tests
./mvnw test
Uso como dependencia en un microservicio consumidor
<dependency>
<groupId>com.hawkersco</groupId>
<artifactId>showroom-client</artifactId>
<version>1.0.25-SNAPSHOT</version>
</dependency>
Cada uno de los dos beans (ShowroomClient/ShowroomFlashClient) se activa independientemente según las propiedades declaradas por el consumidor.
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 documenta un pipeline de tres etapas (Build, SonarQube, Clean) vía scripts (jenkins/scripts/mvn.sh/clean.sh), que no se corresponde con el Jenkinsfile actual del repositorio (dos etapas: Checkout y Publish to Artifact Registry). Se documenta el Jenkinsfile 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/showroom-client/
12. Manejo de errores y logging
La librería no implementa ninguna estrategia propia de manejo de excepciones ni logging estructurado. Ningún método de ShowroomOperations declara throws explícito; las excepciones de red o HTTP propagadas por RestClient (como RestClientResponseException) son responsabilidad del servicio consumidor. No hay configuración de logback ni de niveles de log específicos en la librería.
13. Notas y consideraciones
-
Parámetro
offersDecathlonResponseenupdateOffers: El métodoupdateOffersdeShowroomOperationsrecibe un parámetro llamadooffersDecathlonResponse(@RequestBody String), un nombre que referencia claramente a Decathlon, no a Showroom — indicio de que este método fue copiado desde un cliente similar para Decathlon (decathlon-client) y el nombre del parámetro no se actualizó. No afecta al comportamiento (el nombre del parámetro no forma parte del contrato HTTP), pero es una inconsistencia de legibilidad a corregir. -
importStockFileno documentado enCLAUDE.md: La tabla de operaciones deCLAUDE.mdno incluyeimportStockFile(POST /api/offers/stock/imports, multipart), pese a estar presente enShowroomOperations— documentación heredada incompleta respecto al código actual. -
Patrón de interfaz marcadora (
ShowroomClient/ShowroomFlashClientvacías): Ambas interfaces no añaden ningún método propio; existen únicamente para permitir que Spring registre dos beans de tipos distintos con el mismo conjunto de operaciones. Quien mantenga este código debe recordar que cualquier cambio de contrato se hace enShowroomOperations, no en las interfaces concretas. -
Diferencia menor entre
ShowroomConfigyShowroomFlashConfig: SoloShowroomFlashConfigfija explícitamenteContent-Type: application/jsoncomo cabecera por defecto delRestClient;ShowroomConfigno lo hace (aunque los métodos con@RequestBodyque especificancontentTypeen su propia anotación no se ven afectados). Pendiente de verificar si esta asimetría es intencional o un descuido al escribirShowroomFlashConfiga partir deShowroomConfig. -
@SuppressWarnings("unused")enAcceptOrderShowroomRequest: La anotación sugiere que en algún momento el compilador/IDE marcó campos como no utilizados (probablemente porque Lombok genera los accesores en tiempo de compilación y algunas herramientas de análisis estático no lo detectan) — no indica un problema funcional real. -
Sin tests implementados: No se ha encontrado directorio
src/test/en el proyecto. -
ShowroomClientApplication.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.