update-sfcloud
1. Descripción general
Según el pom.xml, el proyecto se describe como "Update Sfcc and Sfsc". Es un microservicio batch (runner) que sincroniza estados de envío y datos de pedido/producto desde el sistema de logística interno hacia Salesforce Commerce Cloud (SFCC) y Salesforce Service Cloud (SFSC), orquestando hasta 8 procesadores distintos en paralelo mediante CompletableFuture.
2. Información técnica
| Campo | Valor |
|---|---|
artifactId | update-sfcloud |
groupId | com.hawkersco |
version | 1.0.25 |
| Java | 25 |
| Spring Boot | 4.0.6 |
| Tipo de artefacto | jar (ejecutable, Spring Boot batch/CLI) |
| 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 CommandLineRunner coordinador (UpdateSfcloudCoordinator) que orquesta en paralelo hasta 8 runners asíncronos, cada uno @Component con un método @Async runAsync(): CompletableFuture<Void>.
| Runner | Propósito |
|---|---|
LogisticsStatusProcessSfccRunner | Envía a la API Shop de SFCC actualizaciones de estado de envío pendientes; gestiona pedidos multi-envío y pedidos de recogida en tienda con mapeos de estado por sitio de origen |
LogisticsStatusProcessCheckShipmentSfccRunner | Comprueba datos de seguimiento del envío y actualiza SFCC |
LogisticsStatusProcessCheckShipmentSfccMxRunner | Igual que el anterior, específico para México |
LogisticsStatusProcessCheckShipmentSfccAnotherRunner | Variante para proveedores logísticos específicos (Cubbo, Servientrega, Auro, Logsolutions, Sprint Logistics, 99minutos, Sarmed, Logiscore, NPF — según los modelos StatusOrder* del paquete .models) |
UpdateDatabaseSfscProductsRunner | Sincroniza datos de producto hacia SFSC |
UpdateSfscOrderBatchRunner | Sincroniza pedido + envío completo hacia SFSC vía API batch, con pausas entre pasos del lote |
UpdateSfscStatusReptBatchRunner | Actualización por lotes en SFSC del estado REPT (En Reparto) |
UpdateSfscStatusResPrepConfBatchRunner | Actualización por lotes en SFSC de los estados RES/PREP/CONF |
UpdateSfcloudCoordinator lee la propiedad futures.async.runners ("All" o el nombre de una clase de runner concreta) para decidir qué runners ejecutar; los lanza todos como CompletableFuture async, espera a que todos terminen (CompletableFuture.allOf) y llama a System.exit. Los fallos de cualquier runner individual se registran (Level.SEVERE) sin interrumpir al resto.
.config—DynamicsDbConfig(@Primary, datasourcedynamics-pro),LogisticsDbConfig(datasourcelogistics),AsyncConfig,SfccApiProperties,UpdateSfcloudConfig(beans de servicios delogistics-commons)..models— modelos de estado por transportista (StatusOrderCubbo,StatusOrderServientrega,StatusOrdersAuro,StatusOrderLogsolutions,StatusOrderSprintLogistics,StatusOrderList99min,StatusOrderSarmed,StatusOrderShippingLogiscore,StatusOrderNpf),CountriesLocale..utils—LogisticsStatusProcessCheckShipmentUtils,UpdateSfscStatusBatchUtils, excepciones propias (MyException,SfscAsyncTaskException).
flowchart TD
A[UpdateSfcloudCoordinator] -->|lee futures.async.runners| B{"All / runner concreto"}
B --> C[8 runners @Async CompletableFuture]
C -->|estados pendientes| D[(logistics · Order/Shipment/ShipmentStatusHistory)]
C -->|push estado| E[SFCC Shop API]
C -->|batch productos/pedidos/estados| F[SFSC Services API]
C -.->|error por runner| G[log SEVERE]
4. Dependencias principales
| Dependencia | Propósito |
|---|---|
spring-boot-starter | Núcleo de Spring Boot (sin web, es un runner CLI) |
com.opencsv:opencsv | Parseo de datos auxiliares en CSV |
com.hawkersco:logistics-commons | Entidades JPA y servicios (Order, Shipment, ShipmentStatusHistory, SfscProduct, etc.) |
com.hawkersco:sfcc-client | Cliente @HttpExchange para la API Shop de SFCC (SfccShopShipmentClient) |
com.hawkersco:sfcc-services-client | Cliente @HttpExchange para la API batch de Salesforce Services (SfccServicesBatchClient) |
com.hawkersco:slack-client | Cliente @HttpExchange para notificaciones de Slack |
com.hawkersco:pi-function-commons | DateUtils y utilidades compartidas |
| Lombok (dependencia directa) | Generación de código boilerplate |
5. API / Endpoints
No aplica a este proyecto. Es un batch/runner sin capa REST.
6. Integraciones externas
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
| SFCC Shop API | HTTP REST (sfcc-client) | Saliente | Actualización del estado de envío por pedido |
| Salesforce Service Cloud (SFSC) Services API | OAuth password grant + HTTP batch (sfcc-services-client) | Saliente | Sincronización batch de productos, pedidos y estados |
| Slack | HTTP (slack-client) | Saliente | Notificación de errores por runner |
PostgreSQL (dynamics-pro, logistics) | JDBC (doble datasource) | Entrante/Saliente | Lectura de pedidos/envíos 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 |
|---|---|
futures.async.runners | Controla qué runners se ejecutan ("All" o el nombre de una clase concreta; en local está fijado a un único runner para pruebas dirigidas) |
spring.datasource.* | Credenciales de la BD dynamics-pro (datasource primario) |
logistics.datasource.* | Credenciales de la BD logistics |
sfcc.client.url / .staging.client.url / .shop.client.url / .auth.client.url | URLs de los distintos entornos/módulos de SFCC |
sfcc.api.siteid / .sitemxid / .sitecoid / .version / .clientid | Identificadores de sitio y credenciales de API de SFCC |
sfcc.auth.basic | Credencial HTTP Basic (Base64) para la API de SFCC |
sfccservices.credentials.token.* | Credenciales OAuth password grant de Salesforce Service Cloud |
sfccservices.credentials.url | URL base de la API de Salesforce Service Cloud |
slack.client.url / .auth.token / .channel.id | Configuración de Slack |
⚠️ Alerta de seguridad
El fichero src/main/resources/application.properties (perfil local) contiene actualmente credenciales reales en texto plano: contraseñas de ambas bases de datos PostgreSQL (las mismas ya señaladas como expuestas en múltiples proyectos de este ecosistema), la credencial HTTP Basic de la API de SFCC, las credenciales OAuth completas de Salesforce Service Cloud (las mismas ya señaladas como expuestas en return-pi-dynamics, sfcc-abandoned-cart y sfsc-catalog-updater), y el token de bot de Slack. Ninguno de estos valores se ha reproducido en este documento. Se recomienda:
- Rotar de forma coordinada las credenciales de Salesforce (Service Cloud y SFCC), compartidas con otros proyectos del ecosistema.
- Rotar las contraseñas de ambas BD 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
Dos bases de datos PostgreSQL con datasources JPA independientes (ddl-auto=none en ambas):
dynamics-pro(DynamicsDbConfig,@Primary).logistics(LogisticsDbConfig): entidadesOrder,Shipment,ShipmentStatusHistory,OrderLine,SfscProduct, más unSfscProductBatchRepositoryconstruido directamente sobreJdbcTemplate(no un repositorio Spring Data estándar).
No hay Flyway/Liquibase en este repositorio.
9. Procesos programados y mensajería
No hay @Scheduled interno: la periodicidad la impone el CronJob de Kubernetes (k8s/cronjob.yaml), que ejecuta el contenedor cada 5 minutos (schedule: "0/5 * * * *", concurrencyPolicy: Forbid, activeDeadlineSeconds: 7200). En producción se ejecutan todos los runners (futures.async.runners=All) en paralelo, según la tabla de la sección 3.
10. Ejecución en local
Requisitos previos: JDK 25, Maven, acceso a ambas BD y credenciales válidas de SFCC/Salesforce Service Cloud.
# Compilar sin tests
./mvnw -B -DskipTests clean install
# Ejecutar tests
./mvnw test
# Ejecutar un test concreto
./mvnw test -Dtest=UpdateSfcloudApplicationTests
# Build Docker
docker build -t update-sfcloud .
En local, futures.async.runners está fijado a un único runner (UpdateSfscStatusReptBatchRunner) para facilitar pruebas dirigidas, en lugar de "All". Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o el estado reflejado en SFCC/SFSC.
11. Despliegue
- Imagen: construida con
jib-maven-plugin(baseeclipse-temurin:25-jre,containerizingMode=packaged), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/update-sfcloud:<tag>. - 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 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/update-sfcloud/
12. Manejo de errores y logging
No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). El coordinador envuelve cada CompletableFuture con un manejador (whenComplete) que registra Level.SEVERE con el nombre del runner si falla, sin interrumpir al resto de runners en curso. Las excepciones checked lanzadas al invocar runAsync() (InterruptedException, ParseException, IOException) se capturan y se relanzan envueltas en la excepción propia SfscAsyncTaskException. Logging mediante java.util.logging.Logger estándar (consola).
13. Notas y consideraciones
CLAUDE.mddescribe los clientes desfcc-client,sfcc-services-clientyslack-clientcomo "Feign client", terminología obsoleta: el código real (LogisticsStatusProcessSfccRunnery el resto de runners) importa clientes@HttpExchange(SfccShopShipmentClient,SlackClient) desde esas mismas librerías, sin ninguna dependencia de Spring Cloud OpenFeign en elpom.xml— coherente con el patrón de migración a@HttpExchange/RestClientya observado en el resto de proyectos de este ecosistema (Spring Boot 4 eliminó el soporte nativo de Feign).SfscProductBatchRepositoryconstruido manualmente sobreJdbcTemplate: a diferencia del resto de repositorios delogistics-commons(Spring Data JPA), este se instancia como un@Beanexplícito que envuelve unJdbcTemplate, sugiriendo que la operación batch subyacente no encaja bien en el modelo estándar de Spring Data (probablemente por el volumen de filas o el tipo de sentencia SQL usada).CLAUDE.mdverificado y consistente en el resto de aspectos: los 8 runners, el patrón de orquestación asíncrona víaCompletableFuture, el filtrado porfutures.async.runners, el doble datasource, y los mapeos deidSource/estado de envío a SFCC coinciden con el código real, verificado directamente enUpdateSfcloudCoordinator.- Ver alerta de seguridad en la sección 7 sobre credenciales reales expuestas en
application.properties, compartidas con otros proyectos del ecosistema.