logistic-lenses
1. Descripción general
Según el pom.xml, el proyecto se describe como "Logistic contact lenses". Es un microservicio batch (runner) que gestiona la logística de lentes de contacto de Hawkers Group: genera ficheros EDI de pedidos para Cooper Vision, procesa los estados de envío recibidos por SFTP, y gestiona la facturación (PDF/Excel) de pedidos de lentillas enviados vía Auro.
2. Información técnica
| Campo | Valor |
|---|---|
artifactId | logistic-lenses |
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 4 CommandLineRunner, 3 activos y 1 deshabilitado. El paquete raíz del código (com.hawkersco.sfcccatalog) conserva el nombre de un proyecto anterior/plantilla y no se ha renombrado a algo relacionado con lentes de contacto.
Orden real (getOrder()) | Runner | Estado real | Propósito |
|---|---|---|---|
| 1 | LogisticLensesGenerateEdiRunner | Activo | Genera ficheros EDI de pedidos → sube a SFTP de Cooper Vision + GCS |
| 2 | LogisticLensesGetFtpInfoRunner | Activo | Descarga CSV de estado desde el Outbox SFTP de Cooper Vision → actualiza estados de pedido |
| 2 | LogisticLensesGetMailInfoRunner | Deshabilitado (@Component comentado) | Lectura de confirmaciones de pedido de Cooper Vision por correo (IMAP) |
| 3 | LogisticLensesAuroRunner | Activo (llama a System.exit() al terminar) | Procesa pedidos de lentillas enviados por Auro → genera facturas PDF/Excel |
.config—LogisticLensesConfig(wiring de beans),CooperProperties(configuración específica de Cooper Vision)..utils—CooperParser,CooperOrderCsv,CooperOrderLine,CooperOrderLimits,CooperOrdersStatusUpdater,CooperMailReader,SFTPUploader,GoogleUploader,LogisticLensesUtils,SimpleOrderLine.
flowchart TD
A["1. LogisticLensesGenerateEdiRunner"] -->|genera EDI| B[SFTP Cooper Vision Inbox]
A -->|archiva| C[GCS pi-logistics-segment]
D["2. LogisticLensesGetFtpInfoRunner"] -->|descarga CSV estado| E[SFTP Cooper Vision Outbox]
D -->|actualiza| F[(logistics · Order)]
G["3. LogisticLensesAuroRunner"] -->|factura PDF/Excel| H[SFTP orders-auro]
G -->|System.exit al terminar| I[Fin del proceso]
Flujo: el runner 1 genera los ficheros EDI de los pedidos de lentillas pendientes y los sube al Inbox SFTP de Cooper Vision, archivando copia en GCS; el runner 2 descarga del Outbox SFTP los CSV de confirmación de estado y actualiza los pedidos correspondientes en la BD; el runner 3 procesa los pedidos de lentillas gestionados por Auro, genera la documentación (PDF/Excel, con plantilla plantilla_auro.xlsx) y finaliza el proceso. El runner de lectura de correo (Cooper Vision, IMAP) está deshabilitado.
4. Dependencias principales
| Dependencia | Propósito |
|---|---|
spring-boot-starter | Núcleo de Spring Boot (sin web, es un runner CLI) |
spring-boot-starter-mail | Lectura de correo IMAP (usada por el runner deshabilitado) |
com.github.mwiede:jsch | Fork mantenido de JSch (SFTP) — sustituye a com.jcraft:jsch, abandonado (comentario explícito en el pom.xml) |
org.apache.poi:poi-ooxml | Generación de informes Excel (plantilla Auro) |
com.opencsv:opencsv | Parseo de CSV de estado de Cooper Vision |
com.hawkersco:logistics-commons | Entidades JPA y servicios |
com.hawkersco:pi-function-commons | Utilidades compartidas |
com.hawkersco:slack-client | Notificaciones de error |
No existe dependencia shopify-client en el pom.xml pese a que tanto CLAUDE.md como el propio manifiesto de Kubernetes describen/aprovisionan una integración extensa con Shopify (ver hallazgo crítico en la sección 13).
5. API / Endpoints
No aplica a este proyecto. Es un batch/runner sin capa REST.
6. Integraciones externas
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
Cooper Vision SFTP (cvediprd.coopervision.com) | SFTP (JSch) | Entrante/Saliente | Subida de EDI (Inbox) y descarga de CSV de estado (Outbox) |
SFTP sftp.hawkersco.com (usuario orders-auro) | SFTP | Saliente | Subida de documentación de pedidos Auro |
Google Cloud Storage (bucket pi-logistics-segment) | API de GCS | Saliente | Archivado de EDI y facturas |
Correo electrónico (IMAP, notificaciones.cooper@saldum.com) | IMAP | Entrante | Confirmaciones de pedido de Cooper Vision (runner deshabilitado) |
| Slack | HTTP (SlackClient) | Saliente | Notificaciones de error |
PostgreSQL (logistics) | JDBC | Entrante/Saliente | Lectura de pedidos y actualización de 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 una cantidad muy elevada de valores reales hardcodeados (ver alerta de seguridad crítica).
| Clave | Descripción |
|---|---|
spring.datasource.* | Credenciales de la BD logistics |
sftp.host / .user / .pass / .port | Credenciales SFTP de Cooper Vision |
cooper.* | Más de 30 propiedades de configuración de negocio específicas de Cooper Vision (tipos de lente, prefijos SKU, códigos de artículo, prefijos telefónicos válidos) |
email.utils.cooper.* | Credenciales de la cuenta de correo IMAP de notificaciones |
logisticlenses.auro.ftp.* | Credenciales SFTP para subida de documentación a Auro |
hawkers.order.invoice.countrycode.list / .provincecode.list | Países/provincias que requieren factura |
*.shopify.api.name / .url / .key / .password (~20 storefronts) | Credenciales de la API Admin de Shopify — huérfanas, sin ningún uso en el código actual (ver hallazgo crítico) |
slack.client.url / .auth.token / .channel.id / .channel-logistic.id / .channel-atc.id | Configuración de Slack |
🛑 Alerta de seguridad crítica — decenas de credenciales reales de Shopify expuestas y sin uso
El fichero src/main/resources/application.properties (perfil local) contiene credenciales completas de la API Admin de Shopify (API key + password/token) para unas 20 tiendas distintas: Hawkers (Europa, Australia, Colombia, México, Reino Unido, USA, Vista, Desarrollo), Bratleboro (Europa, México, Colombia), Northweek (Europa, Colombia, México), Hawkers Lens (ES, DE, FR, PT, IT, Internacional) y Miss Hamptons Europa. El manifiesto de Kubernetes (k8s/cronjob.yaml) también aprovisiona todas estas credenciales como variables de entorno desde secretos (shopifyUsers, shopifyPass, shopifyHosts, shopifyLocationIds, y decenas de variables individuales por tienda).
Ninguna de estas credenciales se usa actualmente en el código: el pom.xml no declara la dependencia shopify-client, no existe ninguna clase LogisticLensesGenerateEdiShopifyRunner en el árbol de código (aunque el CLAUDE.md la documenta como "disabled"), y el único rastro de la integración es un comentario en LogisticLensesApplication.java que indica que "shopify-client... must be migrated to SB4" — es decir, la migración de esta integración se abandonó a medio camino, eliminando el código y la dependencia, pero sin limpiar ni rotar las credenciales, que siguen residiendo en texto plano en el repositorio y aprovisionadas activamente en Kubernetes.
Esto representa el hallazgo de seguridad más severo detectado hasta ahora en este ecosistema por volumen: decenas de credenciales reales, de múltiples tiendas de producción de varias marcas del grupo, expuestas sin ningún propósito funcional actual. Ninguna se ha reproducido en este documento. Se recomienda con prioridad alta:
- Confirmar si la integración Shopify de este proyecto está realmente descontinuada; si es así, rotar todas las credenciales de Shopify listadas (dado que han estado expuestas en texto plano) y eliminarlas de
application.properties,application-pro.propertiesy delSecretde Kubernetes correspondiente. - Si la integración se planea retomar, migrar estas credenciales a un almacén de secretos gestionado y no reintroducirlas en ficheros de propiedades versionados.
- Revisar el historial de control de versiones para determinar desde cuándo estas credenciales están expuestas.
Además, el fichero contiene la contraseña real de la BD logistics (compartida con otros proyectos de este ecosistema), la contraseña SFTP de Cooper Vision, la contraseña de la cuenta de correo IMAP, la contraseña SFTP de subida a Auro, y el token de bot de Slack — todas ellas tampoco reproducidas aquí y sujetas a la misma recomendación de rotación.
8. Persistencia
Base de datos PostgreSQL logistics (spring.jpa.hibernate.ddl-auto=none). Entidades relevantes gestionadas vía logistics-commons. 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 20 minutos (schedule: "*/20 * * * *", concurrencyPolicy: Forbid). Se ejecutan en orden los runners activos descritos en la sección 3.
10. Ejecución en local
Requisitos previos: JDK 25, Maven, acceso a la BD logistics, credenciales SFTP de Cooper Vision y de Auro.
# Compilar sin tests
./mvnw -B -DskipTests clean install
# Ejecutar la aplicación localmente
./mvnw spring-boot:run
No existen tests unitarios activos en este repositorio. Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o los ficheros generados en las carpetas de trabajo (csv/, orders/, pdf/).
11. Despliegue
- Imagen: construida con
jib-maven-plugin(baseeclipse-temurin:25-jre,containerizingMode=packaged, incluyetemplates/yplantilla/), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/logistic-lenses:<tag>. ElCLAUDE.mdmenciona una imagen baseeclipse-temurin:25-jdk-alpine, que no coincide con la configuración real vía Jib. - Orquestación: Kubernetes
CronJoben el clúster GKEpi-cluster-hw, namespacepi, ejecutándose cada 20 minutos. El manifiesto aprovisiona un número muy elevado de variables de entorno (más de 60), la mayoría correspondientes a credenciales de Shopify sin uso actual (ver hallazgo crítico en la sección 7). - CI/CD (Jenkins): pipeline real de 3 etapas —
Checkout→Build & Push→Deploy to GKE.
Job de Jenkins: https://jenkins-pi.hawkersco.net/job/logistic-lenses/
12. Manejo de errores y logging
No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). Cada runner gestiona sus propios errores de fichero/SFTP con try/catch puntuales, notificando a Slack en los flujos que lo tienen integrado. Logging mediante java.util.logging.Logger/SLF4J según la clase.
13. Notas y consideraciones
- Ver alerta de seguridad crítica en la sección 7: decenas de credenciales reales de Shopify, huérfanas de una integración retirada del código, siguen expuestas en
application.propertiesy aprovisionadas en Kubernetes. Es el hallazgo más severo de este documento. LogisticLensesGenerateEdiShopifyRunnerno existe en el código actual: elCLAUDE.mdlo describe como runner "disabled", pero no hay ningún fichero con ese nombre en el árbol de código — coherente con que la integración Shopify fue eliminada del código (dependenciashopify-clientincluida) durante una migración a Spring Boot 4 que quedó incompleta a nivel de configuración/secretos.LogisticLensesAuroRunnertiene orden real 3, no 2 como indicaCLAUDE.md: la tabla deCLAUDE.mdsitúa aLogisticLensesAuroRunneren el mismo orden (2) queLogisticLensesGetFtpInfoRunner, pero el valor real en código es3— no hay empate de orden entre runners activos, a diferencia de lo que sugiere el documento existente.- Paquete Java heredado sin renombrar: todo el código vive en
com.hawkersco.sfcccatalog, nombre de un proyecto distinto (posiblemente relacionado con catálogo SFCC), no renombrado tras adaptarse a la logística de lentillas — coincide con lo ya documentado enCLAUDE.md, pero merece mención como deuda técnica. - El resto de la arquitectura descrita en
CLAUDE.md(flujo EDI/Outbox/Auro, runner de correo deshabilitado, directorios de trabajo en runtime) coincide con el código real, verificado directamente en los 4 runners.