justeat-update-stock
1. Descripción general
Según el pom.xml, el proyecto se describe como "Update Stock JustEat". Es un microservicio batch (runner) que sincroniza la disponibilidad de stock desde Dynamics 365 (ERP) hacia la plataforma JustEat/Flyt, enviando eventos AVAILABLE/UNAVAILABLE por SKU y tienda para ~50 almacenes físicos habilitados como puntos de venta.
2. Información técnica
| Campo | Valor |
|---|---|
artifactId | justeat-update-stock |
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 un único CommandLineRunner activo (JustEatUpdateStockRunner) y un segundo runner deshabilitado.
| Runner | Estado | Propósito |
|---|---|---|
JustEatUpdateStockRunner (@Order(1)) | Activo | Envía eventos AVAILABLE/UNAVAILABLE a JustEat por tienda y SKU |
JusteatCreateMenuRunner | Deshabilitado (@Component comentado) | Construcción de menú/carta para una tienda concreta (T348), sin persistir ni enviar nada realmente (ver hallazgo en la sección 13) |
.config—JusteatUpdateStockConfig(beans de servicios dedynamics-commons).
flowchart TD
A[JustEatUpdateStockRunner] -->|carga| B[justeat-total-sku-list.json]
A -->|findDistinctInventoryWarehouseIdByDataAreaId dataAreaId=60| C[(dynamics-pro · ProductDynamics)]
C --> D{almacén en<br/>allowlist de ~50 tiendas?}
D -->|sí| E[Productos con stock ≥ 4]
E -->|match directo + match lente| F[Lista SKUs disponibles]
F -->|AVAILABLE| G[JustEat Flyt API]
F -->|resto del catálogo| H[UNAVAILABLE → JustEat Flyt API]
A -.->|error| I[Slack]
Flujo: carga la lista completa de SKUs gestionados por JustEat desde un recurso JSON del classpath; consulta en Dynamics los almacenes distintos con DataAreaId=60; para cada almacén presente en una allowlist estática de ~50 códigos (formato 60STO###), consulta los productos con stock disponible ≥ 4 unidades, construye la lista de SKUs disponibles combinando coincidencia directa (ItemNumber) y coincidencia de lentes (clave compuesta ItemNumber+ProductStyleId, ≥10 caracteres), envía un evento AVAILABLE con esos SKUs y un evento UNAVAILABLE con el resto del catálogo JustEat no disponible en esa tienda. Cualquier error durante la ejecución completa se notifica a Slack.
4. Dependencias principales
| Dependencia | Propósito |
|---|---|
spring-boot-starter | Núcleo de Spring Boot (sin web, es un runner CLI) |
org.json:json | Parseo de los ficheros JSON de recursos con las listas de SKU |
commons-io | Lectura de los recursos JSON del classpath |
com.hawkersco:justeat-client | Cliente @HttpExchange para la API de JustEat Flyt (itemAvailability) |
com.hawkersco:dynamics-commons | ProductDynamicsService, entidad ProductDynamics |
com.hawkersco:slack-client | Notificaciones de error |
5. API / Endpoints
No aplica a este proyecto. Es un batch/runner sin capa REST.
6. Integraciones externas
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
JustEat Flyt API (api.flytplatform.com) | HTTP REST (JustEatClient) | Saliente | Eventos de disponibilidad de stock por tienda/SKU (itemAvailability) |
PostgreSQL (dynamics-pro) | JDBC | Entrante | Consulta de almacenes y stock disponible por producto |
| Slack | HTTP (SlackClient) | Saliente | Notificación de error de la ejecución completa |
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 dynamics-pro |
justeat.credentials.url / .key | Credenciales de la API de JustEat Flyt |
slack.client.url / .auth.token / .channel.id | Configuración de Slack |
spring.main.allow-circular-references | Fijado a true, requerido por la librería interna dynamics-commons |
⚠️ 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 dynamics-pro (la misma ya señalada como expuesta en múltiples proyectos de este ecosistema), la clave de la API de JustEat Flyt, 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 clave de JustEat 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
No hay base de datos propia gestionada por este proyecto: se consulta en modo solo lectura la BD dynamics-pro a través de dynamics-commons (entidad ProductDynamics), sin persistir ningún dato localmente. No hay Flyway/Liquibase.
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). Único runner activo, descrito en la sección 3.
10. Ejecución en local
Requisitos previos: JDK 25, Maven, acceso a la BD dynamics-pro y credenciales válidas de la API de JustEat.
# Compilar
mvn clean install
# Compilar sin tests
mvn -B -DskipTests clean install
# Ejecutar la aplicación localmente
mvn spring-boot:run
# Ejecutar el JAR
java -jar target/justeat-update-stock-1.0.25.jar
No existe directorio /src/test en este repositorio. Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o el estado de disponibilidad reflejado en el panel de JustEat.
11. Despliegue
- Imagen: construida con
jib-maven-plugin(baseeclipse-temurin:25-jre,containerizingMode=packaged), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/justeat-update-stock:<tag>. ElCLAUDE.mdmenciona una imagen baseeclipse-temurin:25-jdk-alpine, que no coincide con la configuración real vía Jib (mismo patrón detectado en varios proyectos hermanos). - Orquestación: Kubernetes
CronJoben el clúster GKEpi-cluster-hw, namespacepi, con credenciales de cuenta de servicio de GCP montadas por volumen (GOOGLE_APPLICATION_CREDENTIALS), sin uso aparente de APIs de Google en el código (mismo patrón detectado en otros proyectos de este lote), ejecutándose cada hora. - CI/CD (Jenkins): pipeline real de 3 etapas —
Checkout→Build & Push→Deploy to GKE. ElCLAUDE.mddescribe un pipeline conKICS scan,SonarQubeyTestque no existen en elJenkinsfileactual (mismo patrón detectado en varios proyectos hermanos de este lote).
Job de Jenkins: https://jenkins-pi.hawkersco.net/job/justeat-update-stock/
12. Manejo de errores y logging
No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). Todo el run() de JustEatUpdateStockRunner está envuelto en un único try/catch genérico que notifica a Slack y registra Level.SEVERE ante cualquier error, sin distinguir entre fallos de un almacén concreto o de toda la ejecución. Cada llamada individual a la API de JustEat captura RestClientResponseException y notifica a Slack sin interrumpir el resto de tiendas. Logging mediante java.util.logging.Logger estándar (consola).
13. Notas y consideraciones
justeat-sku-lens-list.jsonno se usa realmente para el mapeo de lentes: elCLAUDE.mdafirma que las lentes se mapean "víajusteat-sku-lens-list.json", peroJustEatUpdateStockRunner.buildLensSkuListno lee ese fichero en ningún momento — construye la coincidencia de lentes filtrando directamente la listajustEatTotalSkuList(cargada dejusteat-total-sku-list.json) por longitud y subcadenas. El ficherojusteat-sku-lens-list.jsonexiste físicamente ensrc/main/resources/pero no tiene ninguna referencia en el código Java de este proyecto — mismo patrón de recurso huérfano detectado enupdate-stock(aliexpress-sku.json).JusteatCreateMenuRunnerdeshabilitado y, además, no completo: aparte de estar desactivado (@Componentcomentado), su lógica interna nunca añade losItemconstruidos a ninguna colección delMenu/Category(itemse crea y se rellena pero no se agrega a ninguna lista), por lo que aunque se reactivara tal cual, no enviaría ningún ítem de menú real. Su métodotransform()además lanzaIllegalArgumentExceptionante un formato de almacén inválido, mientras que el método homónimo del runner activo devuelve una cadena vacía — comportamiento inconsistente entre ambas clases, aunque sin impacto actual al estar deshabilitado.- Pipeline de Jenkins e imagen base más simples de lo documentado: ver hallazgos en la sección 11.
- El resto de la arquitectura descrita en
CLAUDE.md(allowlist de ~50 tiendas, umbral de stock ≥4, flujo AVAILABLE/UNAVAILABLE) coincide con el código real, verificado directamente enJustEatUpdateStockRunner. - Ver alerta de seguridad en la sección 7 sobre credenciales reales expuestas en
application.properties.