Skip to main content

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

CampoValor
artifactIdlogistic-lenses
groupIdcom.hawkersco
version1.0.25
Java25
Spring Boot4.0.6
Tipo de artefactojar (ejecutable, Spring Boot batch/CLI, spring.main.web-application-type=none)
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 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())RunnerEstado realPropósito
1LogisticLensesGenerateEdiRunnerActivoGenera ficheros EDI de pedidos → sube a SFTP de Cooper Vision + GCS
2LogisticLensesGetFtpInfoRunnerActivoDescarga CSV de estado desde el Outbox SFTP de Cooper Vision → actualiza estados de pedido
2LogisticLensesGetMailInfoRunnerDeshabilitado (@Component comentado)Lectura de confirmaciones de pedido de Cooper Vision por correo (IMAP)
3LogisticLensesAuroRunnerActivo (llama a System.exit() al terminar)Procesa pedidos de lentillas enviados por Auro → genera facturas PDF/Excel
  • .configLogisticLensesConfig (wiring de beans), CooperProperties (configuración específica de Cooper Vision).
  • .utilsCooperParser, 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

DependenciaPropósito
spring-boot-starterNúcleo de Spring Boot (sin web, es un runner CLI)
spring-boot-starter-mailLectura de correo IMAP (usada por el runner deshabilitado)
com.github.mwiede:jschFork mantenido de JSch (SFTP) — sustituye a com.jcraft:jsch, abandonado (comentario explícito en el pom.xml)
org.apache.poi:poi-ooxmlGeneración de informes Excel (plantilla Auro)
com.opencsv:opencsvParseo de CSV de estado de Cooper Vision
com.hawkersco:logistics-commonsEntidades JPA y servicios
com.hawkersco:pi-function-commonsUtilidades compartidas
com.hawkersco:slack-clientNotificaciones 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

SistemaProtocoloDirecciónDetalle
Cooper Vision SFTP (cvediprd.coopervision.com)SFTP (JSch)Entrante/SalienteSubida de EDI (Inbox) y descarga de CSV de estado (Outbox)
SFTP sftp.hawkersco.com (usuario orders-auro)SFTPSalienteSubida de documentación de pedidos Auro
Google Cloud Storage (bucket pi-logistics-segment)API de GCSSalienteArchivado de EDI y facturas
Correo electrónico (IMAP, notificaciones.cooper@saldum.com)IMAPEntranteConfirmaciones de pedido de Cooper Vision (runner deshabilitado)
SlackHTTP (SlackClient)SalienteNotificaciones de error
PostgreSQL (logistics)JDBCEntrante/SalienteLectura 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).

ClaveDescripción
spring.datasource.*Credenciales de la BD logistics
sftp.host / .user / .pass / .portCredenciales 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.listPaí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.idConfiguració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:

  1. 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.properties y del Secret de Kubernetes correspondiente.
  2. 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.
  3. 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 (base eclipse-temurin:25-jre, containerizingMode=packaged, incluye templates/ y plantilla/), publicada en europe-west3-docker.pkg.dev/pi-saldum/pi-repo/logistic-lenses:<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 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 — CheckoutBuild & PushDeploy 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.properties y aprovisionadas en Kubernetes. Es el hallazgo más severo de este documento.
  • LogisticLensesGenerateEdiShopifyRunner no existe en el código actual: el CLAUDE.md lo 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 (dependencia shopify-client incluida) durante una migración a Spring Boot 4 que quedó incompleta a nivel de configuración/secretos.
  • LogisticLensesAuroRunner tiene orden real 3, no 2 como indica CLAUDE.md: la tabla de CLAUDE.md sitúa a LogisticLensesAuroRunner en el mismo orden (2) que LogisticLensesGetFtpInfoRunner, pero el valor real en código es 3 — 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 en CLAUDE.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.