Skip to main content

logistics-status-process

1. Descripción general

Según el pom.xml, el proyecto se describe como "Process logistics states". Es un microservicio batch (runner) que sincroniza los estados de envío de pedidos entre múltiples proveedores logísticos externos y las bases de datos internas de Hawkers, y a continuación propaga esos estados actualizados a las APIs de los marketplaces correspondientes (Meli, Miravia, Showroom, TheBradery, El Corte Inglés, TheIconic, Decathlon). Orquesta hasta 17 procesadores asíncronos independientes.

2. Información técnica

CampoValor
artifactIdlogistics-status-process
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 CommandLineRunner coordinador (LogisticsStatusProcessCoordinator) que orquesta en paralelo hasta 17 runners asíncronos (@Async, CompletableFuture<Void>), no los 8+9=17 descritos de forma inexacta en CLAUDE.md (ver hallazgo en la sección 13).

CategoríaRunners (verificados en el código)
GCS → BD (9, no 8)Auro, Cubbo, Logsolutions, NPF, Sarmed, Servientrega, SprintLogistics y SprintLogisticsGb (dos runners distintos, no uno solo), TimesLogistics
BD → Marketplace (8, no 9)Auro, AuroTheBradery, Cubbo, Logsolutions, NPF, Servientrega, SprintLogistics, Times

No existe un runner de tipo "BD → Marketplace" para Sarmed (solo GCS → BD) — Sarmed no propaga estados a ningún marketplace en el código actual.

LogisticsStatusProcessCoordinator lee futures.async.runners ("All" o el nombre de una clase concreta) para decidir qué runners ejecutar, los lanza todos como CompletableFuture async, espera con CompletableFuture.allOf, y llama a SpringApplication.exit() (con código de salida 1 si algún runner falló).

  • .configDynamicsDbConfig (@Primary, BD dynamics-pro), DynamicsDbGoldConfig (BD dynamics-gold), LogisticsDbConfig (BD logistics), LogisticsStatusProcessConfig.
  • .models — modelos de estado por transportista (StatusOrderCubbo, StatusOrderSarmed, StatusOrderServientrega, StatusOrderSprintLogistics, StatusOrdersAuro, StatusOrderNpf, StatusOrderLogiscore, etc.), más EbayShippingFulfillmentRequest (ver hallazgo en la sección 13).
  • .utilsLogisticsStatusProcessGcPToDbUtils (operaciones GCS compartidas), UpdateDecathlonUtil, UpdateElCorteInglesUtils, UpdateMeliUtil, UpdateMiraviaUtil, UpdateShowroomUtil, UpdateTheBraderyUtils, UpdateTheIconicUtil (lógica de llamada a cada marketplace).
flowchart TD
A[LogisticsStatusProcessCoordinator] -->|futures.async.runners| B{"All / runner concreto"}
B --> C[9 runners GCS→BD]
B --> D[8 runners BD→Marketplace]
C -->|descarga y parsea| E[GCS pi-logistics-segment]
C -->|escribe estado| F[(dynamics-pro / dynamics-gold / logistics)]
D -->|lee estado pendiente| F
D -->|push estado| G[APIs de marketplace: Meli, Miravia, Showroom, TheBradery, ECI, TheIconic, Decathlon]

4. Dependencias principales

DependenciaPropósito
spring-boot-starter, spring-boot-starter-data-jpaNúcleo Spring Boot + JPA
com.zaxxer:HikariCPPool de conexiones para el triple datasource
org.apache.poi:poi / poi-ooxmlParseo de ficheros Excel
org.eclipse.angus:angus-mailEnvío de correo (Jakarta Mail)
com.hawkersco:dynamics-commons / dynamics-clientAcceso a Dynamics 365
com.hawkersco:logistics-commonsEntidades JPA y servicios de logística
com.hawkersco:logsolution-client, decathlon-client, theiconic-client, miravia-client, meli-client, liverpool-client, eci-client, showroom-client, bradery-clientClientes @HttpExchange de cada marketplace/transportista
com.miravia:miraviaSDK oficial de Miravia
com.hawkersco:pi-generate-credentials-clientCliente del servicio interno de credenciales
com.hawkersco:slack-clientNotificaciones de error

No existe dependencia tiktok-client en el pom.xml, pese a que CLAUDE.md la cita como dependencia interna y application.properties contiene credenciales reales de TikTok sin ningún uso en el código (ver hallazgo crítico en la sección 13 — mismo patrón ya detectado en pi-generate-credentials).

5. API / Endpoints

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

6. Integraciones externas

SistemaProtocoloDirecciónDetalle
Google Cloud Storage (bucket pi-logistics-segment)API de GCSEntranteLectura de ficheros de estado por transportista
Meli, Miravia, Showroom, TheBradery, El Corte Inglés, TheIconic, DecathlonHTTP REST (clientes @HttpExchange)SalientePropagación de estados de envío actualizados
SlackHTTP (SlackClient)SalienteNotificaciones de error
PostgreSQL (dynamics-pro, dynamics-gold, logistics)JDBC (triple datasource)Entrante/SalienteLectura/escritura de estados de pedido
Correo electrónico (SMTP)angus-mailSalienteNotificaciones relacionadas con TheBradery

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 una cantidad muy elevada de valores reales hardcodeados (ver alerta de seguridad).

ClaveDescripción
spring.datasource.* / dynamicsgold.datasource.* / logistics.datasource.*Credenciales de las tres BD
futures.async.runnersControla qué runners se ejecutan
decathlon.credentials.key / decathlon-au.credentials.keyCredenciales de Decathlon (España/Australia)
theiconic.api.keyCredencial de The Iconic
miravia.client.appkey / .appsecretCredenciales OAuth de Miravia
meli.credentials.clientsecretCredencial de Mercado Libre
liverpool.credentials.key, qliverpool.api.keyCredenciales de Liverpool (con una clave adicional comentada)
eci.credentials.keyCredencial de El Corte Inglés
showroom.credentials.key, showroom-flash.credentials.keyCredenciales de Showroom Privé (estándar y Flash)
ebay.credentials.granttype / .refresh.tokenCredenciales OAuth de eBay
aliexpress.app.key / .secret / .generated.secretCredenciales de AliExpress
cdiscount.credentials.token.* / .ocpaimsubkeyCredenciales OAuth de Cdiscount (Octopia)
ninenineminutes.client.secret.prodCredencial de 99minutos
tiktok.app-key / .app-secretCredenciales de TikTok — sin ningún uso en el código actual (ver hallazgo crítico)
email.utils.bradery.passwordContraseña de la cuenta de correo de TheBradery
slack.auth.tokenToken de bot de Slack

🛑 Alerta de seguridad — volumen muy elevado de credenciales reales, incluyendo un juego huérfano de TikTok

El fichero src/main/resources/application.properties (perfil local) contiene credenciales reales de al menos 13 sistemas externos distintos: tres bases de datos PostgreSQL (la misma contraseña compartida, ya señalada como expuesta en múltiples proyectos de este ecosistema), Decathlon (x2), The Iconic, Miravia, Mercado Libre, Liverpool (x2), El Corte Inglés, Showroom (x2), eBay (token de refresco OAuth), AliExpress, Cdiscount/Octopia, 99minutos, TikTok, y la contraseña de una cuenta de correo. Ninguna se ha reproducido en este documento.

En particular, tiktok.app-key/tiktok.app-secret no tienen ningún uso en el código de este proyecto (no hay dependencia tiktok-client en el pom.xml, ni ninguna referencia a "tiktok" en el código Java) — son credenciales reales, huérfanas, del mismo tipo de integración "TikTok Shop" ya señalada como ficticia/no implementada en el proyecto pi-generate-credentials de este mismo ecosistema. Es posible que ambos proyectos compartan el mismo origen de credenciales de una integración de TikTok que nunca llegó a completarse.

Se recomienda con prioridad alta:

  1. Rotar todas las credenciales listadas, dado el volumen y la antigüedad probable de exposición.
  2. Confirmar si la integración de TikTok Shop sigue teniendo sentido; si no, eliminar tiktok.app-key/.app-secret de este fichero y del correspondiente Secret de Kubernetes (cruzar con el mismo hallazgo en pi-generate-credentials).
  3. Sustituir los valores hardcodeados de application.properties por credenciales de un entorno de desarrollo aislado.

8. Persistencia

Tres bases de datos PostgreSQL independientes (dynamics-pro @Primary, dynamics-gold, logistics), cada una con su propio EntityManagerFactory/TransactionManager (HikariCP, pool máx. 5 / mín. 2). 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 10 minutos (schedule: "0/10 * * * *", activeDeadlineSeconds: 43200 — 12 horas). En producción se ejecutan todos los runners (futures.async.runners=All) en paralelo.

10. Ejecución en local

Requisitos previos: JDK 25, Maven, acceso a las tres BD y credenciales válidas de los marketplaces/transportistas relevantes.

# Compilar
mvn clean install

# Ejecutar en desarrollo
mvn spring-boot:run

# Ejecutar solo un runner concreto
mvn spring-boot:run -Dfutures.async.runners=LogisticsStatusProcessAuroRunner

# Ejecutar tests
mvn test

# Ejecutar el JAR de producción
java -Xmx4g -jar target/logistics-status-process-1.0.25.jar

Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o el estado reflejado en las 3 BD y en los paneles de cada marketplace.

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/logistics-status-process:<tag>. El CLAUDE.md menciona una imagen base eclipse-temurin:25-jdk-alpine, que no coincide con la configuración real vía Jib.
  • Orquestación: Kubernetes CronJob en el clúster GKE pi-cluster-hw, namespace pi, ejecutándose cada 10 minutos con un plazo de actividad de 12 horas.
  • CI/CD (Jenkins): pipeline real de 3 etapas — CheckoutBuild & PushDeploy to GKE. El CLAUDE.md describe un pipeline con KICS security scan y SonarQube que no aparecen en el Jenkinsfile actual (mismo patrón detectado en varios proyectos hermanos de este lote).

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/logistics-status-process/

12. Manejo de errores y logging

No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). El coordinador recoge los resultados de todos los CompletableFuture y, si alguno falló, sale con código de estado 1 en lugar de 0. Cada runner individual gestiona sus propios errores de API/BD, típicamente notificando a Slack. Logging mediante java.util.logging.Logger/SLF4J según la clase.

13. Notas y consideraciones

  • CLAUDE.md cuenta mal sus propios runners: afirma "GCP-to-DB Runners (8)" y los lista sin incluir la variante específica de Reino Unido de SprintLogistics (LogisticsStatusProcessSprintLogisticsGbGcpToDbRunner), que sí existe en el código — el número real es 9. Además, el propio encabezado "Marketplace Runners (9)" es inconsistente con su propia lista adjunta, que enumera solo 8 nombres — y el código confirma que son 8, no 9.
  • Credenciales de TikTok huérfanas: ver alerta de seguridad crítica en la sección 7 — mismo patrón que la integración ficticia de TikTok ya detectada en pi-generate-credentials en este ecosistema.
  • EbayShippingFulfillmentRequest presente en .models sin runner ni utilidad Update* asociada visible: existe el modelo pero no se ha encontrado un runner o clase de utilidad dedicada a eBay entre los ficheros de este proyecto, pese a que application.properties sí contiene credenciales OAuth completas de eBay — podría tratarse de una integración parcialmente implementada o en curso, pendiente de confirmar con el equipo.
  • Pipeline de Jenkins e imagen base más simples de lo documentado: ver hallazgo en la sección 11.
  • El resto de la arquitectura descrita en CLAUDE.md (patrón coordinador/runners asíncronos, triple datasource, filtrado por futures.async.runners) coincide con el código real, verificado directamente en LogisticsStatusProcessCoordinator.