Skip to main content

sfsc-catalog-updater

1. Descripción general

Según el pom.xml, el proyecto se describe como "Sfsc Catalog Updater". Es un microservicio batch (runner) que sincroniza el catálogo de producto almacenado en PostgreSQL (web_product_catalog) con Salesforce Service Cloud (productos estándar y grupos de variación), y además procesa encuestas recibidas por SFTP para crear/actualizar cuentas en Salesforce y disparar eventos en Salesforce Marketing Cloud.

2. Información técnica

CampoValor
artifactIdsfsc-catalog-updater
groupIdcom.hawkersco
version1.0.25
Java25
Spring Boot4.0.6
Tipo de artefactojar (ejecutable, Spring Boot batch/CLI)
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 3 CommandLineRunner, todos activos.

OrdenRunnerPropósito
1SfscCatalogUpdaterRunnerProductos estándar → upsert en Salesforce Service Cloud
2SfscCatalogVGUpdaterRunnerProductos de grupo de variación → upsert en Salesforce Service Cloud
3SfscSurveyUpdaterRunnerEncuestas CSV/JSON desde SFTP → cuentas de Salesforce + eventos de Marketing Cloud
  • .configSfscCatalogUpdaterConfig (beans de servicios de webproductcatalog-commons + PersistenceManagedTypes), PiFtpProperties.
  • .utilCatalogUpdaterUtil (extracción y mapeo de datos de producto a ~22 combinaciones locale/sitio), SendCatalogUpdaterUtil (serialización JSON + llamada HTTP PATCH a SFCC).
  • .modelSurveyErpPiResponse.
flowchart TD
A["1. SfscCatalogUpdaterRunner<br/>productos estándar"] -->|paginado 100| B[(web_product_catalog · Products)]
C["2. SfscCatalogVGUpdaterRunner<br/>grupos de variación"] --> B
A -->|PATCH upsert| D[Salesforce Service Cloud]
C -->|PATCH upsert| D
E["3. SfscSurveyUpdaterRunner"] -->|lee| F[SFTP /src/survey/pending/]
E -->|crea si 404, si no actualiza| G[Salesforce Account]
E -->|dispara evento| H[Salesforce Marketing Cloud]
E -->|archiva| I[SFTP /src/survey/processed/]
A -.->|error por producto| J[Slack]

4. Dependencias principales

DependenciaPropósito
spring-boot-starter-data-jpa + postgresqlAcceso a la BD web_product_catalog
com.hawkersco:webproductcatalog-commonsEntidades JPA (Products, ProductAttributes, ProductSiteData, etc.) y servicios
com.hawkersco:sfcc-services-clientCliente @HttpExchange para Salesforce Service Cloud (sendProduct)
com.hawkersco:sfcc-marketing-clientCliente para Salesforce Marketing Cloud
com.hawkersco:slack-clientNotificaciones de error
com.hawkersco:pi-function-commonsUtilidades compartidas (incluye SFTP)
jakarta.xml.bind-api, jackson-databindParseo XML/JSON
lombokGeneración de código boilerplate

5. API / Endpoints

No aplica a este proyecto. Es un batch/runner sin capa REST.

6. Integraciones externas

SistemaProtocoloDirecciónDetalle
Salesforce Service CloudOAuth2 password grant + HTTP PATCHSalienteUpsert de productos por código
Salesforce Marketing CloudOAuth2 client_credentialsSalienteDisparo de eventos de encuesta
Servidor SFTP (sftp.hawkersco.com, usuario logistic-eu)SFTPEntrante/SalienteLectura de encuestas pendientes (/src/survey/pending/) y archivo tras procesar (/src/survey/processed/)
SlackHTTP (SlackClient)SalienteNotificación de errores
PostgreSQL (web_product_catalog)JDBCEntranteLectura paginada del catálogo de producto

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).

ClaveDescripción
spring.datasource.*Credenciales de la BD web_product_catalog
sfccservices.credentials.*Credenciales OAuth password grant de Salesforce Service Cloud
sfccmarketing.credentials.*Credenciales OAuth client_credentials de Salesforce Marketing Cloud
pi.ftp.*Credenciales SFTP para encuestas
slack.client.url / .auth.token / .channel.idConfiguración de Slack

⚠️ Alerta de seguridad

El fichero src/main/resources/application.properties (perfil local) contiene actualmente credenciales reales en texto plano: contraseña de la BD web_product_catalog, credenciales OAuth completas de Salesforce Service Cloud (las mismas ya señaladas como expuestas en return-pi-dynamics y sfcc-abandoned-cart) y de Marketing Cloud, credenciales SFTP, y token de bot de Slack. Ninguno de estos valores se ha reproducido en este documento. Se recomienda:

  1. Rotar de forma coordinada las credenciales de Salesforce (Service Cloud y Marketing Cloud), compartidas con otros proyectos del ecosistema.
  2. Rotar la contraseña de BD, las credenciales SFTP y el token de Slack.
  3. Sustituir los valores hardcodeados de application.properties por credenciales de un entorno de desarrollo aislado.
  4. Revisar el historial de control de versiones, ya que estas credenciales pueden seguir expuestas en commits anteriores.

8. Persistencia

Base de datos PostgreSQL web_product_catalog, acceso vía JPA a través de webproductcatalog-commons. spring.jpa.hibernate.ddl-auto=none. Entidades relevantes: Products, ProductAttributes, ProductSiteData, ProductSiteDataImages, ProductSiteLocaleAttributes, ProduDataLocalePrices. 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, que ejecuta el contenedor cada hora (schedule: "0 * * * *", concurrencyPolicy: Forbid), con una duración estimada de 8–10 minutos por ejecución según el propio CLAUDE.md. Los runners 1 y 2 paginan el catálogo completo (100 productos por página, entityManager.clear() entre páginas para evitar acumulación de memoria en el contexto de persistencia) y envían cada producto individualmente a Salesforce, capturando RestClientResponseException por producto para no interrumpir el resto del lote. El runner 3 procesa los ficheros de encuesta pendientes en SFTP, crea la cuenta en Salesforce si no existe (404) o la actualiza, dispara el evento correspondiente en Marketing Cloud, y archiva el fichero procesado.

10. Ejecución en local

Requisitos previos: JDK 25, Maven, acceso a la BD web_product_catalog, credenciales SFTP y credenciales OAuth de Salesforce (Service Cloud y Marketing Cloud).

# Compilar sin tests
./mvnw clean install -DskipTests

# Ejecutar tests
./mvnw test

# Ejecutar con perfil de producción
java -jar target/sfsc-catalog-updater-*.jar --spring.profiles.active=pro

Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o el estado de los productos/cuentas en Salesforce tras la ejecución.

11. Despliegue

  • Imagen: construida con jib-maven-plugin (base eclipse-temurin:25-jre, containerizingMode=packaged), publicada en europe-west3-docker.pkg.dev/pi-saldum/pi-repo/sfsc-catalog-updater:<tag>. El CLAUDE.md menciona una imagen base eclipse-temurin:25-jdk-alpine con heap de 4GB, que no coincide exactamente con la configuración vía Jib del pom.xml actual.
  • Orquestación: Kubernetes CronJob en el clúster GKE pi-cluster-hw, namespace pi, ejecutándose cada hora. Recursos elevados según CLAUDE.md: límite de 8Gi memoria / 2 CPU, solicitud de 4Gi / 1 CPU — coherente con el volumen de datos de todo el catálogo procesado por ejecución.
  • CI/CD (Jenkins): pipeline Build → KICS Security Scan → SonarQube → Test → Docker Push → K8s Deploy → Clean, según el propio CLAUDE.md.

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/sfsc-catalog-updater/

12. Manejo de errores y logging

No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). RestClientResponseException se captura individualmente por producto en los runners 1 y 2, evitando que un fallo puntual detenga el procesamiento del resto del catálogo. Los errores del runner de encuestas se notifican a Slack. Logging mediante java.util.logging.Logger estándar (consola).

13. Notas y consideraciones

  • CLAUDE.md detallado y verificado: los 3 runners, sus órdenes de ejecución, el patrón de paginación con limpieza de EntityManager, y las integraciones descritas coinciden con el código real (verificado directamente en SfscCatalogUpdaterRunner). Es uno de los documentos CLAUDE.md más precisos encontrados en este lote.
  • Instancia de utilidad estática en lugar de bean inyectado: SfscCatalogUpdaterRunner declara static final CatalogUpdaterUtil catalogUpdaterUtil = new CatalogUpdaterUtil() en lugar de inyectarlo como bean de Spring (a diferencia de productService/sendCatalogUpdaterUtil, que sí se inyectan por constructor). No es un error funcional dado que la clase parece ser stateless (solo se usa como fachada de métodos utilitarios), pero es una inconsistencia de estilo dentro de la misma clase.
  • Ver alerta de seguridad en la sección 7 sobre credenciales reales de Salesforce y BD expuestas en application.properties, compartidas con otros proyectos del ecosistema (return-pi-dynamics, sfcc-abandoned-cart).