logistic-eu
1. Descripción general
Según el pom.xml, el proyecto se describe como "Orders send to logistic from Europa". Es un microservicio batch (runner) que recoge pedidos europeos (y de otros orígenes agrupados aquí, ver sección 13) pendientes de envío desde la base de datos de logística y los envía al almacén operado por Auro, generando factura en PDF cuando corresponde, gestionando cancelaciones, corrección de errores de teléfono y reintentos.
2. Información técnica
| Campo | Valor |
|---|---|
artifactId | logistic-eu |
groupId | com.hawkersco |
version | 1.0.25 |
| Java | 25 |
| Spring Boot | 4.0.6 |
| Tipo de artefacto | jar (ejecutable, Spring Boot batch/CLI, spring.main.web-application-type=none) |
| 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 7 CommandLineRunner, todos activos, ejecutados en el orden real verificado en el código (que difiere del descrito en CLAUDE.md, ver hallazgo en la sección 13):
Orden real (getOrder()) | Runner | Propósito |
|---|---|---|
| 1 | LogisticEuEciRunner | Pedidos de El Corte Inglés (id_source=62) |
| 1 | LogisticEuMpRunner | Pedidos de marketplace genérico (findByOrdersNoProcessedMpEu) — mismo valor de orden que LogisticEuEciRunner (ver hallazgo) |
| 2 | LogisticEuRunner | Pedidos directos EU principales (id_source en 8,17,36,58,61) |
| 3 | LogisticEuPrivaliaRunner | Pedidos de Privalia (id_source=44) |
| 4 | LogisticEuErrorRunner | Corrige errores de teléfono tras 5 días; cancela pedidos atascados >15 días a las 11:00 |
| 5 | LogisticEuBrRunner | Pedidos vía findByOrdersNoProcessedBr — runner completo no documentado en absoluto en CLAUDE.md (ver hallazgo) |
| 6 | LogisticEuCancelledRunner | Envía solicitudes de cancelación a Auro (id_source=45 + CANCELLED_BY_USER), y llama a System.exit() al terminar |
.config—LogisticEuConfiguration,LogisticEuOldConf,PDFThymeleafConfiguration(motor de plantillas para las facturas)..models—ProductSend..utils—LogisticEuAuroUtils(construcción del JSONOrderAuroRequest, generación de factura PDF, comprobación de stock, embalaje, líneas creativas/personalización, envío a tienda),LogisticEuUtils(validación/corrección de código postal, generación de PDF, adjuntos de correo),LogisticEuConst(constantes centrales: listas deid_source, cadenas de estado, formato de zona horaria).
flowchart TD
A["1. Eci / Mp Runners"] -->|PENDING_SHIPMENT| B[(logistics · Order)]
C["2. LogisticEuRunner"] --> B
D["3. LogisticEuPrivaliaRunner"] --> B
E["4. LogisticEuErrorRunner"] -->|corrige teléfono / cancela >15 días| B
F["5. LogisticEuBrRunner"] --> B
A -->|postDocumentos| G[Auro Warehouse API]
C --> G
D --> G
F --> G
G -->|éxito| H[GCS response/ok/]
G -->|error| I[GCS response/ko/]
A -.->|factura PDF| J[SFTP /src/invoices/]
K["6. LogisticEuCancelledRunner"] -->|cancelaDoc, luego System.exit| G
4. Dependencias principales
| Dependencia | Propósito |
|---|---|
spring-boot-starter | Núcleo de Spring Boot (sin web, es un runner CLI) |
spring-boot-starter-mail | Envío de correo (Andorra → equipo legal) |
spring-boot-starter-thymeleaf | Plantillas HTML para generación de factura PDF |
org.apache.poi:poi / poi-ooxml | Manejo de hojas de cálculo (soporte auxiliar) |
com.sun.xml.bind:jaxb-core / jaxb-impl | Procesamiento XML |
commons-fileupload, commons-io | Utilidades de fichero |
com.googlecode.json-simple:json-simple | Parseo JSON auxiliar |
com.hawkersco:auro-client | Cliente @HttpExchange para la API del almacén Auro (postDocumentos, cancelaDoc, getFotoInventario) |
com.hawkersco:logistics-commons | DAOs y servicios compartidos (Order, OrderLine, Country, OrderError, etc.) |
com.hawkersco:pi-function-commons | DateUtils, StorageUtils, SftpUtils, SeveralUtils, DirectoryUtils |
com.hawkersco:slack-client | Notificaciones de Slack |
5. API / Endpoints
No aplica a este proyecto. Es un batch/runner sin capa REST.
6. Integraciones externas
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
| Auro Warehouse API | HTTP REST (AuroClient) | Saliente | Envío (postDocumentos), cancelación (cancelaDoc) y consulta de foto de inventario |
Google Cloud Storage (bucket pi-logistics-segment) | API de GCS | Saliente | Almacenamiento de respuestas de la API Auro en `logistic-eu/response/ok |
Servidor SFTP (sftp.hawkersco.com) | SFTP | Saliente | Subida de facturas PDF (/src/invoices/) y de pedidos a Auro (/src/orders/, credenciales de FTP independientes) |
| Slack | HTTP (SlackClient) | Saliente | Alertas en 3 canales: general, ATC y almacén |
| Correo electrónico (SMTP) | spring-boot-starter-mail | Saliente | Notificación al equipo legal para pedidos con destino Andorra |
PostgreSQL (logistics) | JDBC | Entrante/Saliente | Lectura de pedidos pendientes y actualización de su estado |
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).
| Clave | Descripción |
|---|---|
spring.datasource.* | Credenciales de la BD logistics |
gcs.bucket.name | Bucket de GCS para respuestas de Auro |
auro.auth.client.url / .app / .username / .password | Credenciales de autenticación de la API Auro |
logisticeu.ftp.* | Credenciales SFTP para subida de facturas |
logisticeu.auro.ftp.* | Credenciales SFTP independientes para subida de pedidos a Auro |
hawkers.order.invoice.countrycode.list / .provincecode.list | Países/provincias que requieren factura |
hawkers.orders.test | Marcador de pedidos de prueba (lahermanadeaxel) |
hw.regex.source / nw.regex.source | Expresiones regulares para distinguir pedidos Hawkers/Northweek |
creatives.skus | SKUs considerados líneas creativas/personalización |
slack.client.url / .auth.token / .channel.id / .channel-whs-not.id / .channel-atc.id | Configuración de Slack (3 canales) |
⚠️ 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 múltiples proyectos de este ecosistema), la contraseña de autenticación de la API Auro, dos contraseñas SFTP independientes (una para subida de facturas, otra para subida de pedidos a Auro), y el token de bot de Slack. Ninguno de estos valores se ha reproducido en este documento. Se recomienda:
- Rotar la contraseña de BD, la contraseña de Auro, ambas contraseñas SFTP 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 (spring.jpa.hibernate.ddl-auto=none). Entidades relevantes: Order, OrderLine, OrderError, Country. 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 5 minutos (schedule: "0/5 * * * *", concurrencyPolicy: Forbid) — el CLAUDE.md indica una periodicidad de 10 minutos, que no coincide con el manifiesto real. Se ejecutan en orden los 7 runners de la tabla de la sección 3.
10. Ejecución en local
Requisitos previos: JDK 25, Maven, acceso a la BD logistics, credenciales válidas de la API Auro y de ambos servidores SFTP.
# Compilar con tests
./mvnw clean install
# Compilar sin tests
./mvnw -DskipTests clean install
No existen tests en este repositorio (src/test/ está vacío). Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o el estado de los pedidos en la BD logistics.
11. Despliegue
- Imagen: construida con
jib-maven-plugin(baseeclipse-temurin:25-jre,containerizingMode=packaged, incluye directorios extratemplates/yplantilla/para las facturas), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/logistic-eu:<tag>. - Orquestación: Kubernetes
CronJoben el clúster GKEpi-cluster-hw, namespacepi, con credenciales de cuenta de servicio de GCP montadas por volumen, ejecutándose cada 5 minutos. - CI/CD (Jenkins): pipeline real de 3 etapas —
Checkout→Build & Push→Deploy to GKE.
Job de Jenkins: https://jenkins-pi.hawkersco.net/job/logistic-eu/
12. Manejo de errores y logging
No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). Cada runner envuelve el procesamiento de cada pedido individual en su propio try/catch, notificando a Slack y continuando con el resto del lote. Tras 4 reintentos fallidos (nm_send_logistic >= MAX_RETRIES), el pedido se marca como error definitivo (OrderError persistido) y se notifica al canal de ATC con un enlace directo a infranete.hawkersco.net. Logging mediante java.util.logging.Logger estándar (consola).
13. Notas y consideraciones
LogisticEuBrRunnerno está documentado en absoluto enCLAUDE.md: existe como séptimo runner activo (@Order(5)), con una lógica de construcción y envío del documento Auro casi idéntica a la deLogisticEuRunner/LogisticEuPrivaliaRunner(misma generación de factura PDF vía Thymeleaf, misma subida SFTP a/src/invoices/, mismo mecanismo de reintento y alerta a Slack tras 4 fallos), pero alimentado por una consulta distinta (findByOrdersNoProcessedBr). ElCLAUDE.mdno lo menciona en su tabla de arquitectura ni en ningún otro punto del documento — es la omisión más significativa encontrada en este proyecto.- Tabla de orden de ejecución de
CLAUDE.mddesactualizada: además de omitirLogisticEuBrRunner, asigna aLogisticEuEciRunnerel orden0(el valor real en código es1, empatado conLogisticEuMpRunner) y aLogisticEuCancelledRunnerel orden5(el valor real es6). El orden de ejecución real, verificado directamente en el código, es: Eci/Mp (ambos en 1) → Runner (2) → Privalia (3) → Error (4) → Br (5) → Cancelled (6). LogisticEuEciRunneryLogisticEuMpRunnercomparten el mismo valor degetOrder()(1): al ser beans de tipos distintos con el mismo valor de orden, Spring no garantiza un desempate estable entre ambos — el orden relativo de ejecución entre estos dos runners concretos depende de un criterio no especificado (típicamente el orden de descubrimiento del classpath). No representa un riesgo funcional grave porque ambos procesan orígenes de pedido disjuntos (ECI vs. marketplace genérico), pero es una inconsistencia de diseño que convendría corregir asignando valores de orden únicos.- Periodicidad del CronJob distinta de la documentada: ver hallazgo en la sección 9 (
CLAUDE.mddice 10 minutos, el manifiesto real usa 5 minutos). - El resto de la arquitectura descrita en
CLAUDE.md(ciclo de vida del pedido, detección de pedidos de prueba/fraudulentos, lentes de contacto, DOM/TOM de Francia, reglas de generación de factura) coincide con las utilidades compartidas (LogisticEuUtils,LogisticEuAuroUtils,LogisticEuConst) usadas de forma consistente por todos los runners. - Ver alerta de seguridad en la sección 7 sobre credenciales reales expuestas en
application.properties.