showroom-flash-create-db
1. Descripción general
El pom.xml de este proyecto conserva la descripción genérica por defecto de Spring Initializr ("Demo project for Spring Boot"), que no refleja su propósito real (ver hallazgo en la sección 13). Según su CLAUDE.md y el código, es un microservicio batch (runner) ETL, hermano de showroom-create-db, que sincroniza pedidos del marketplace Showroom Flash (plataforma Mirakl) con la base de datos de logística: acepta automáticamente pedidos pendientes de aceptación con más de 1 hora de antigüedad, y persiste como nuevos pedidos internos los que ya están en estado de envío (SHIPPING).
2. Información técnica
| Campo | Valor |
|---|---|
artifactId | showroom-flash-create-db |
groupId | com.hawkersco.showroomflashcreatedb |
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 | Propósito |
|---|---|---|
| 1 | ShowroomFlashCreateDbWaitingRunner | Pedidos WAITING_ACCEPTANCE con más de 1h → auto-aceptación en Mirakl |
| 2 | ShowroomFlashCreateDbRunner | Pedidos SHIPPING → transformación y persistencia en BD logistics |
.config—ShowroomCreateDbConfig(beans de servicios delogistics-commons+PersistenceManagedTypes)..utils—ShowroomFlashCreateDbUtils(toda la lógica de creación de entidades:saveMarketplace,saveCustomer,saveOrder,saveOrderLine,saveShipment,saveOrderShipmentStatus).
flowchart TD
A["1. ShowroomFlashCreateDbWaitingRunner<br/>WAITING_ACCEPTANCE > 1h"] -->|acceptOrder| B[Mirakl Showroom Flash API]
A -.->|fallo al aceptar| C[Slack]
D["2. ShowroomFlashCreateDbRunner<br/>SHIPPING, paginado 100"] -->|getOrderListWithStatus| B
D -->|si no existe ya, fuente 72| E[(logistics · Order/OrderMarketplace)]
Flujo: el runner 1 pagina los pedidos en WAITING_ACCEPTANCE (esperando 10s entre páginas), calcula la antigüedad de cada uno y acepta (acceptOrder) los que superan 1 hora, notificando a Slack si la aceptación falla o si la API responde sin éxito. El runner 2 pagina los pedidos en SHIPPING desde hace 5 días, comprueba que no existan ya en BD (por SHOWROOM_SOURCE_ID=72 y cdOrderExternal), genera un nombre de pedido interno ("MKSHOF" + ceros de relleno + idOrder, 7 caracteres numéricos), y persiste cliente, pedido, líneas y envío. Ambos runners usan un cliente HTTP específico de Flash (ShowroomFlashClient), distinto del ShowroomClient genérico usado por showroom-create-db, aunque ambos provienen de la misma librería showroom-client.
4. Dependencias principales
| Dependencia | Propósito |
|---|---|
spring-boot-starter | Núcleo de Spring Boot (sin web, es un runner CLI) |
spring-web | RestClient/@HttpExchange |
com.hawkersco:showroom-client | Cliente @HttpExchange para la API de Mirakl Showroom Flash (ShowroomFlashClient), incluye tipos de request/response |
com.hawkersco:logistics-commons | Entidades JPA (Order, OrderMarketplace, Customer, etc.) y servicios |
com.hawkersco:pi-function-commons | DateUtils y utilidades compartidas |
com.hawkersco:slack-client | Cliente @HttpExchange para notificaciones (SlackClient) |
spring-boot-starter-test (test) | JUnit 5 + Spring Test |
5. API / Endpoints
No aplica a este proyecto. Es un batch/runner sin capa REST.
6. Integraciones externas
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
| Mirakl Showroom Flash API | HTTP REST (ShowroomFlashClient) | Entrante/Saliente | Lectura de pedidos por estado y aceptación de pedidos pendientes |
| Slack | HTTP (SlackClient) | Saliente | Alertas de fallo de aceptación |
PostgreSQL (logistics) | JDBC | Saliente | Persistencia de clientes, pedidos, líneas y envíos |
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), pese a que el CLAUDE.md afirma que este fichero está en .gitignore.
| Clave | Descripción |
|---|---|
spring.datasource.* | Credenciales de la BD logistics (mismo host que showroom-create-db) |
showroom-flash.credentials.url / .key | Credenciales de la API de Mirakl Showroom Flash |
showroom.credentials.url / .key | Presentes pero vacías en ambos perfiles; sin uso aparente en este proyecto (ver sección 13) |
slack.client.url / .auth.token / .channel.id / .channel-whs-not.id | Configuración de Slack |
⚠️ 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 logistics (la misma ya señalada como expuesta en showroom-create-db), clave de la API de Mirakl Showroom Flash (además de una clave comentada de un entorno de desarrollo de Mirakl), y token de bot de Slack (el mismo ya señalado en showroom-create-db). Ninguno de estos valores se ha reproducido en este documento. Se recomienda:
- Rotar la contraseña de BD, la clave de Mirakl Showroom Flash y el token de Slack.
- 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 logistics (esquema externo, no gestionado por este proyecto: spring.jpa.hibernate.ddl-auto=none). Entidades relevantes (definidas en logistics-commons, escaneadas vía PersistenceManagedTypesScanner): Order, OrderMarketplace, Customer, CustomerSource, OrderLine, Shipment, ShipmentLine, OrderShipmentStatus. 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 cada hora (schedule: "0 * * * *", concurrencyPolicy: Forbid, activeDeadlineSeconds: 3600). 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 logistics y credenciales válidas de la API de Mirakl Showroom Flash.
# Compilar sin tests
./mvnw -B -DskipTests clean install
# Ejecutar tests
./mvnw test
# Ejecutar la aplicación localmente
./mvnw spring-boot:run
# Ejecutar un test concreto
./mvnw test -Dtest=ShowroomFlashCreateDbApplicationTests
Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o los pedidos reflejados en la BD logistics.
11. Despliegue
- Imagen: construida con
jib-maven-plugin(baseeclipse-temurin:25-jre,containerizingMode=packaged), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/showroom-flash-create-db:<tag>. ElCLAUDE.mdmenciona una imagen baseeclipse-temurin:25-jdk-alpine, que no coincide con la configuración real vía Jib delpom.xmlactual (mismo patrón detectado enshowroom-create-db). - Orquestación: Kubernetes
CronJoben el clúster GKEpi-cluster-hw, namespacepi, contenedor no privilegiado (allowPrivilegeEscalation: false,capabilities: drop: ALL), ejecutándose cada hora. - CI/CD (Jenkins): pipeline de 3 etapas —
Checkout→Build & Push(sustituyeapplication-pro.propertiesporapplication.properties,mvn clean package jib:build) →Deploy to GKE(kubectl delete cronjob+kubectl apply).
Job de Jenkins: https://jenkins-pi.hawkersco.net/job/showroom-flash-create-db/
12. Manejo de errores y logging
No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). ShowroomFlashCreateDbRunner captura ParseException por pedido, registrando un warning sin interrumpir el resto del lote. ShowroomFlashCreateDbWaitingRunner captura RestClientResponseException al aceptar un pedido, notificando a Slack y registrando Level.SEVERE; si la API responde sin éxito 2xx, también notifica a Slack sin lanzar excepción. Logging mediante java.util.logging.Logger estándar (consola).
13. Notas y consideraciones
descriptiondelpom.xmlno actualizada: conserva el texto genérico de Spring Initializr ("Demo project for Spring Boot") en lugar de una descripción real del propósito del proyecto, a diferencia de la mayoría de proyectos hermanos de este ecosistema.- Propiedades
showroom.*vacías y sin uso aparente: tantoapplication.propertiescomoapplication-pro.propertiesdeclaranshowroom.credentials.url/.keyvacíos (además de una URL/clave de Mirakl de desarrollo comentada); no se ha encontrado ninguna referencia ashowroom.credentials.*en el código de este proyecto. Es el mismo patrón de restos de copia/pegado detectado de forma recíproca enshowroom-create-db(que a su vez tieneshowroom-flash.*vacías sin uso) — ambos proyectos comparten un origen común y probablemente se clonó uno a partir del otro sin limpiar las propiedades del marketplace contrario. CLAUDE.mdafirma queapplication.propertiesestá en.gitignore("Dev: application.properties (gitignored — contains real credentials)"), pero el fichero está presente y con credenciales reales legibles directamente en el repositorio de trabajo — no se ha podido confirmar si existe una entrada de.gitignoreque simplemente no se está respetando, o si la afirmación es incorrecta.- El resto de la arquitectura descrita en
CLAUDE.md(flujo de los 2 runners,SHOWROOM_SOURCE_ID=72, prefijo de nombreMKSHOF, grupos de país, uso deShowroomFlashClient) coincide con el código real, verificado directamente enShowroomFlashCreateDbRunneryShowroomFlashCreateDbWaitingRunner. - Ver alerta de seguridad en la sección 7 sobre credenciales reales expuestas en
application.properties, compartidas parcialmente conshowroom-create-db.