Skip to main content

infranete-api

1. Descripción general

Según el pom.xml, el proyecto se describe como "Infranete Api". Es la API backend central del ecosistema de microservicios Hawkers PI: expone más de 30 controladores REST organizados por dominio (pedidos, logística, marketplaces, feeds, cupones, paneles, reportes, stock) y actúa como punto de integración con múltiples marketplaces internacionales (Shopee, Decathlon, Miravia, TheIconic, Zalando, AliExpress), con Dynamics 365, y con Salesforce Commerce Cloud (SFCC). Es, con diferencia, el proyecto más grande y con más superficie de integración documentado en esta serie.

2. Información técnica

CampoValor
artifactIdinfranete-api
groupIdcom.hawkersco
version1.0.25
Java25 (maven.compiler.release=25)
Spring Boot4.0.6
Tipo de artefactojar (ejecutable, API web de larga duración)
MódulosNo aplica (proyecto de módulo único, pero con más de 100 clases)

3. Arquitectura y diseño

API REST clásica sobre 5 bases de datos PostgreSQL independientes, con seguridad OAuth2/JWT (Auth0) condicionada por entorno, más tres jobs de sincronización que también se ejecutan una vez al arrancar la aplicación (además de por cron).

Paquetes principales bajo com.hawkersco.infraneteapi:

  • controller/ — 31 controladores REST (.DS_Store aparte) organizados en subpaquetes: raíz, coupons/, dynamics/, feeds/, logistics/, marketplaces/, orders/, panels/, reports/, stock/, web/.
  • service/ — capa de servicio, organizada en los mismos dominios que sus repositorios (logistics, marketplaces, sunajager, dynamics, feeds, commons, asyncmethods).
  • respository/ (sic, con el typo intencional documentado en CLAUDE.md) — repositorios Spring Data JPA, uno por base de datos: logistics, marketplaces, sunajager, dynamics, feeds.
  • dao/ — entidades JPA, organizadas igual que los repositorios.
  • config/LogisticsDbConfig (primario), MarketplacesDbConfig, SunaJagerDbConfig, DynamicsDbConfig, FeedsDbConfig, SecurityConfig, AudienceValidator, AppConfig.
  • job/ — 8 clases de sincronización/limpieza programada.
  • utils/ — utilidades de negocio (parseo Cooper, feeds, stock por marketplace, Google Drive, etc.).
  • model/ — DTOs de request/response.
  • Raíz — InfraneteApiApplication, InfraneteApiRunner (activo), CleanApiRunner (desactivado, ver hallazgo crítico en la sección 13).
flowchart TD
A[Cliente / Frontend interno] -->|JWT Auth0| B[SecurityConfig]
B --> C[Controladores REST por dominio]
C --> D[Servicios]
D --> E1[(logistics)]
D --> E2[(marketplaces)]
D --> E3[(sunajager)]
D --> E4[(dynamics-pro)]
D --> E5[(feeds)]
D --> F[Clientes de marketplace:<br/>Shopee, Decathlon, Miravia,<br/>TheIconic, Zalando, SFCC, Dynamics]
G[InfraneteApiRunner al arrancar] --> H[OriginalFeedsSync / OrderLinesSync / ImagesFeedsSync]
I["Jobs @Scheduled"] --> H

Multi-datasource (5 bases de datos PostgreSQL)

Config classPrefijo de propiedadRepositoriosDAO
LogisticsDbConfig (@Primary)spring.datasourcerespository.logisticsdao.logistics
MarketplacesDbConfigmarketplaces.datasourcerespository.marketplacesdao.marketplaces
SunaJagerDbConfigsunajager.datasourcerespository.sunajagerdao.sunajager
DynamicsDbConfigdynamics.datasourcerespository.dynamicsdao.dynamics
FeedsDbConfigfeeds.datasourcerespository.feedsdao.feeds

4. Dependencias principales

DependenciaPropósito
spring-boot-starter-webAPI REST
spring-boot-starter-security + spring-boot-starter-oauth2-resource-serverAutenticación/autorización JWT (Auth0)
spring-boot-starter-data-jpa + postgresql:42.7.5Persistencia sobre las 5 bases de datos
org.apache.poi / poi-ooxml:5.3.0Generación de ficheros Excel (reportes/catálogos)
com.google.apis:google-api-services-sheetsIntegración con Google Sheets (generación de catálogos SFCC, DANE, etc.)
com.google.api-client / google-oauth-client-jettyCliente Google genérico
org.json:jsonUtilidades JSON
com.hawkersco:pi-function-commonsUtilidades comunes
com.hawkersco:shopee-client, sfcc-client, sfcc-commons, decathlon-client, miravia-client, zalando-client, theiconic-client, dynamics-client, sprintlogistics-clientClientes de marketplace/ERP
com.hawkersco:slack-clientNotificaciones de error
com.hawkersco:pi-generate-credentials-clientGeneración de credenciales para otros servicios
spring-boot-devtools (runtime, opcional)Recarga en caliente en desarrollo
commons-lang3Utilidades varias

5. API / Endpoints

Más de 30 controladores agrupados por dominio (rutas verificadas contra el código actual):

DominioPaqueteControladores reales
Núcleocontroller/InfraneteApiController, JobsController
Pedidoscontroller/orders/OrdersCommonController, OrdersInfoController, OrderLinesCommonController, CountryController, FraudulentEmailController, OrdersNonStockController, OrdersZipErrorController, OrdersPhoneErrorController, OrdersDaneErrorController, OrdersAddressErrorController, Orders99minErrorController, OrdersAuroOnHoldController, OrdersDecathlonController
Marketplacescontroller/marketplaces/MarketplacesCommonController, ZalandoController
Dynamicscontroller/dynamics/DynamicsController
Feedscontroller/feeds/GoogleFeedsController, ImagesFeedsController, RedirectFeedsController
Logísticacontroller/logistics/LogisticsUpdateFileController, LogisticsUpdateStockController, SfccShippingMethodsController
Cuponescontroller/coupons/DiscountCodeGeneratorApiController
Panelescontroller/panels/PanelsOrdersController, PanelsStatusController
Reportescontroller/reports/ReportsCommonController
Stockcontroller/stock/DrStockController
Web/SFCCcontroller/web/JsonSeoPlpGenerateController, StockSfccController

Reglas de autorización por scope (ver SecurityConfig, entorno pro): SCOPE_commons (búsquedas comunes de pedidos/países), SCOPE_orders (edición/creación/cancelación de pedidos, facturas, no-stock, errores de dirección/teléfono/DANE, emails fraudulentos), SCOPE_logistics (sfccsm, dr-stock), SCOPE_coupons, SCOPE_marketplaces, SCOPE_feeds (images-feeds, redirect-feeds, google-feeds), SCOPE_web (stock-sfcc, json-seo-plp-generate). Rutas públicas: /api/check-domain, /jobs/token, /api/optics/*.

6. Integraciones externas

SistemaProtocoloDirecciónDetalle
Shopee, Decathlon (EU/AU), Miravia, TheIconic, Zalando, AliExpressHTTP (clientes @HttpExchange o Feign, según librería)SalienteSincronización de stock/pedidos por marketplace
Salesforce Commerce Cloud (SFCC)HTTP (sfcc-client)Entrante/SalienteGeneración de catálogos, actualización de stock web
Dynamics 365 (Commerce + F&O)HTTP OAuth client_credentials (dynamics-client)Entrante/SalientePrecios, stock, clientes
Sprint Logistics (API v2)HTTPSalienteIntegración logística
Google Sheets/DriveAPI de GoogleEntranteGeneración de catálogos (SFCC, variaciones), procesamiento de imágenes de feeds
Cooper Vision (SFTP)SFTPSalientePedidos de lentillas
SFTP genérico (sftp.hawkersco.com)SFTPEntrante/SalienteFeeds, imágenes, Auro
SMTP (Gmail)SMTPSalienteEnvío de correo (hawkers.contact@saldum.com)
Auth0OAuth2/JWTEntranteAutenticación de la propia API en entorno pro/test
SlackHTTP (SlackClient)SalienteNotificaciones de error

7. Configuración

En producción (application-pro.properties, plantilla versionada) las credenciales llegan por variables de entorno inyectadas como Secret de Kubernetes; application.properties está en .gitignore según indica el propio CLAUDE.md, pero el fichero presente en este repositorio de trabajo sí existe físicamente y contiene credenciales reales de prácticamente todas las integraciones (ver alerta de seguridad, la más severa de todo este lote de proyectos).

Clave (prefijo)Descripción
spring.datasource.*BD logistics (primaria)
marketplaces.datasource.*BD marketplaces
sunajager.datasource.*BD sunajager
dynamics.datasource.*BD dynamics-pro
feeds.datasource.*BD feeds
application.environmentdev / test / pro — controla el nivel de aplicación de seguridad en SecurityConfig
spring.security.oauth2.resourceserver.jwt.issuer-uri, auth0.audienceConfiguración Auth0
infranete.interfaceOrigen permitido por CORS (http://localhost:4040 en dev)
shopee.api.*, decathlon*.credentials.*, miravia.client.*, theiconic.api.*, zalando.*, aliexpress.*, sfcc.*, dynamics.login.*, dynamics.picustomersetup.*, sprintlogistics-v2.api.*Credenciales de cada integración de marketplace/ERP
dev.ftp.*, pro.ftp.*, cooper.ftp.*, auro.ftp.*, images.ftp.*Credenciales SFTP por integración
slack.client.url / .auth.token / .channel.idNotificaciones Slack
spring.mail.*Credenciales SMTP
sfccgenerator.*, zalando.*.driveIDs de hojas de Google Sheets usadas como catálogo/config

⚠️ Alerta de seguridad (severidad crítica)

El fichero src/main/resources/application.properties de este repositorio de trabajo contiene credenciales reales de prácticamente todas las integraciones externas de Hawkers: contraseñas de las 5 bases de datos PostgreSQL (todas con el mismo usuario/contraseña), la API key/secret de partner de Shopee, las claves de Mirakl de Decathlon EU y AU, el appkey/appsecret de Miravia, el client-id/client-secret de TheIconic, la clave/contraseña base de Zalando, el app-secret/generated-secret de AliExpress, el client-id/client-secret de SFCC (dos aplicaciones distintas), un client-secret OAuth de Dynamics 365 (el mismo tenant PRO ya señalado como expuesto en gio-pos-sync-service), credenciales SFTP de Cooper Vision, Auro y del servidor general de imágenes/feeds, el token de bot de Slack, y la contraseña SMTP de la cuenta hawkers.contact@saldum.com. Ninguno de estos valores se ha reproducido en este documento. Dado el alcance (prácticamente toda la superficie de integración del ecosistema Hawkers PI queda comprometida si este fichero se filtra), se recomienda con prioridad máxima:

  1. Rotar de forma inmediata y coordinada todas las credenciales listadas: las 5 bases de datos, Shopee, Decathlon EU/AU, Miravia, TheIconic, Zalando, AliExpress, SFCC, Dynamics 365, Cooper Vision, Auro, SFTP de imágenes, Slack y la cuenta SMTP.
  2. Confirmar si el fichero application.properties está realmente excluido por .gitignore en el repositorio remoto (el CLAUDE.md lo da por hecho) y, si no lo está o lo estuvo en el pasado, auditar el historial de Git para determinar el alcance real de la exposición.
  3. Mover progresivamente esta configuración a un gestor de secretos centralizado en lugar de un fichero de propiedades local, dado el volumen y la criticidad de las credenciales involucradas.

8. Persistencia

Cinco bases de datos PostgreSQL independientes, cada una con su propio DataSource/EntityManagerFactory/TransactionManager (logistics como primaria): logistics, marketplaces, sunajager, dynamics-pro, feeds. Todas con *.jpa.hibernate.ddl-auto=none. No hay Flyway/Liquibase en este repositorio.

9. Procesos programados y mensajería

Al arrancar (InfraneteApiRunner, solo si application.environment=pro, una única vez por ciclo de vida del proceso)

originalFeedsSync.downloadNewFeeds()orderLinesSync.syncOrderLines()imagesFeedsSync.downloadAllImages().

Jobs con @Scheduled activo

JobCronFunción
ImagesFeedsSync0 45 23 * * ? y 0 0/30 * ? * *Descarga de imágenes de feeds (limpieza a las 23:45, sincronización cada 30 min)
OrdersErrorCleanJob0 0 3,15 * * ?Limpieza de pedidos en estado de error, dos veces al día

Jobs sin @Scheduled (invocados como beans desde otros puntos, no programados por cron)

MiraviaUpdateStockJob, SfccNwUpdateStockJob, SfccUpdateStockJob, ShopeeUpdateStockJob, OrderLinesSync (invocado por InfraneteApiRunner, no tiene cron propio).

Jobs con @Scheduled comentado (desactivados)

CusterIpJob (// @Scheduled(cron = "0 */5 * ? * *")), OriginalFeedsSync (//@Scheduled(cron = "0 */5 * * * ?"), invocado igualmente desde InfraneteApiRunner al arrancar).

10. Ejecución en local

Requisitos previos: JDK 25, Maven, acceso a las 5 bases de datos PostgreSQL y credenciales de todas las integraciones externas listadas en la sección 7.

# Compilar sin tests (patrón estándar aquí)
./mvnw -B -DskipTests clean install

# Compilar con tests
./mvnw clean install

# Ejecutar un test concreto
./mvnw test -Dtest=MyTestClassName

# Análisis SonarQube (usado en CI)
mvn sonar:sonar -Dmaven.test.skip=true -Dsonar.projectKey=<key> -Dsonar.host.url=<url> -Dsonar.login=<token>

En dev/entornos distintos de pro, SecurityConfig permite todas las rutas (permitAll) aunque el filtro JWT sigue configurado. Verificación de que el servicio está operativo: no hay Actuator configurado; se recomienda usar /api/check-domain (público) como comprobación básica de disponibilidad.

11. Despliegue

  • Imagen: construida con jib-maven-plugin (base eclipse-temurin:25-jre, containerizingMode=packaged), incluyendo además el directorio templates/ (plantillas de factura/email) como directorio extra en la imagen. Publicada en europe-west3-docker.pkg.dev/pi-saldum/pi-repo/infranete-api:<tag>.
  • Orquestación: Kubernetes Deployment (k8s/deployment.yaml, no CronJob) en el clúster GKE pi-cluster-hw (zona europe-west3-a, proyecto pi-saldum), namespace pi, replicas: 1.
  • CI/CD (Jenkins): pipeline real de 2 etapas — CheckoutBuild & Push (sustituye application-pro.properties por application.properties) → Deploy to GKE (aplica el manifiesto templado y espera rollout status). El CLAUDE.md describe un pipeline mucho más extenso (Build → KICS Scan → SonarQube → Test → Docker Push → K8s Deploy → Clean) y menciona una imagen base eclipse-temurin:17-jdk-alpine con heap de 5 GB (-Xmx5g) y un manifiesto en jenkins/deployment/app-deployment.yml; ninguno de estos detalles coincide con el Jenkinsfile/pom.xml/estructura de directorios actuales (ver hallazgo en la sección 13).
  • Las variables sensibles se inyectan en el pod mediante un Secret de Kubernetes llamado igual que la app (infranete-api), con un número muy elevado de claves (5 bases de datos + Auth0 + todas las integraciones de marketplace).

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/infranete-api/

12. Manejo de errores y logging

No se ha localizado un @RestControllerAdvice global centralizado en el código revisado; el manejo de errores parece resolverse por controlador/servicio. CleanApiRunner (desactivado) captura excepciones genéricas dentro de su bucle y solo registra un WARNING. Los niveles de log de Jackson/HTTP y Spring Security están elevados a DEBUG en application.properties (adecuado solo para desarrollo; debería revisarse antes de cualquier uso en producción, dado que puede filtrar información sensible en los logs). Notificación de errores a Slack disponible vía slack-client, aunque su uso específico no se ha podido verificar exhaustivamente dado el tamaño del proyecto.

13. Notas y consideraciones

  • CleanApiRunner contiene un bucle infinito sin pausa (while(true) sin Thread.sleep): aunque está desactivado (@Component comentado), el código tal cual quedaría escrito ejecutaría shipmentService.clean() en un bucle infinito y sin ningún retardo entre iteraciones si se reactivara — un busy-loop que consumiría CPU de forma continua y generaría carga constante e innecesaria sobre la base de datos logistics. Si en algún momento se reactiva esta clase, debe añadirse como mínimo una espera (Thread.sleep o, mejor, convertirlo en un @Scheduled) antes de descomentar el @Component.
  • Doble configuración de CORS potencialmente conflictiva: InfraneteApiApplication registra un WebMvcConfigurer que permite allowedOrigins("*") en /** para los métodos GET/POST/PUT/DELETE, mientras que SecurityConfig registra por separado un CorsFilter con precedencia máxima que restringe el origen a ${infranete.interface} (con allowCredentials(true)). Tener dos configuraciones CORS distintas y potencialmente contradictorias en la misma aplicación dificulta razonar sobre el comportamiento real ante peticiones cross-origin; se recomienda consolidar en una única fuente de verdad.
  • Advertencia de migración de Feign a @HttpExchange presente tanto en CLAUDE.md como en un comentario del propio código (InfraneteApiApplication): ambos documentos afirman que las librerías internas de cliente (shopee-client, slack-client, etc.) siguen usando Spring Cloud OpenFeign y no se pueden inyectar hasta migrarlas a @HttpExchange. Esto contrasta con el patrón ya confirmado en otros proyectos de este mismo ecosistema (p. ej. decathlon-create-db, eci-create-db, donation-update), donde las librerías equivalentes (slack-client, decathlon-client, etc.) en la misma versión 1.0.25-SNAPSHOT se inyectan correctamente vía @HttpExchange + AutoConfiguration.imports, sin necesidad de @EnableFeignClients. Es posible que esta advertencia esté desactualizada y que la migración ya se haya completado en las librerías compartidas; se recomienda verificarlo directamente (comprobando si los beans de shopee-client/etc. se inyectan sin errores al arrancar) antes de asumir que sigue siendo un bloqueo real.
  • Discrepancias menores de conteo/estructura en CLAUDE.md: el documento indica "33 controladores"; el recuento real en el árbol de fuentes es 31. También describe un paquete controller/stores/ para api/sfcc-stores que no existe como tal en la estructura actual (existe service/logistics/SfccStoreService pero no se ha localizado un controlador dedicado bajo ese nombre de paquete).
  • InfraneteApiRunner ejecuta lógica de sincronización pesada solo una vez por arranque y solo en pro: al ser una aplicación de larga duración (Deployment, no CronJob), esta ejecución inicial (OriginalFeedsSync, OrderLinesSync, ImagesFeedsSync) solo ocurre en el momento del despliegue/reinicio del pod; el resto del tiempo, la sincronización de estos tres procesos depende exclusivamente de sus jobs @Scheduled correspondientes (cuando los tienen — OriginalFeedsSync no tiene cron activo, solo se dispara al arrancar).
  • Ver alerta de seguridad de severidad crítica en la sección 7: este es, con diferencia, el proyecto con mayor volumen de credenciales reales expuestas en application.properties de todo este lote de documentación.