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
| Campo | Valor |
|---|---|
artifactId | sfsc-catalog-updater |
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 3 CommandLineRunner, todos activos.
| Orden | Runner | Propósito |
|---|---|---|
| 1 | SfscCatalogUpdaterRunner | Productos estándar → upsert en Salesforce Service Cloud |
| 2 | SfscCatalogVGUpdaterRunner | Productos de grupo de variación → upsert en Salesforce Service Cloud |
| 3 | SfscSurveyUpdaterRunner | Encuestas CSV/JSON desde SFTP → cuentas de Salesforce + eventos de Marketing Cloud |
.config—SfscCatalogUpdaterConfig(beans de servicios dewebproductcatalog-commons+PersistenceManagedTypes),PiFtpProperties..util—CatalogUpdaterUtil(extracción y mapeo de datos de producto a ~22 combinaciones locale/sitio),SendCatalogUpdaterUtil(serialización JSON + llamada HTTPPATCHa SFCC)..model—SurveyErpPiResponse.
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
| Dependencia | Propósito |
|---|---|
spring-boot-starter-data-jpa + postgresql | Acceso a la BD web_product_catalog |
com.hawkersco:webproductcatalog-commons | Entidades JPA (Products, ProductAttributes, ProductSiteData, etc.) y servicios |
com.hawkersco:sfcc-services-client | Cliente @HttpExchange para Salesforce Service Cloud (sendProduct) |
com.hawkersco:sfcc-marketing-client | Cliente para Salesforce Marketing Cloud |
com.hawkersco:slack-client | Notificaciones de error |
com.hawkersco:pi-function-commons | Utilidades compartidas (incluye SFTP) |
jakarta.xml.bind-api, jackson-databind | Parseo XML/JSON |
lombok | 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 |
|---|---|---|---|
| Salesforce Service Cloud | OAuth2 password grant + HTTP PATCH | Saliente | Upsert de productos por código |
| Salesforce Marketing Cloud | OAuth2 client_credentials | Saliente | Disparo de eventos de encuesta |
Servidor SFTP (sftp.hawkersco.com, usuario logistic-eu) | SFTP | Entrante/Saliente | Lectura de encuestas pendientes (/src/survey/pending/) y archivo tras procesar (/src/survey/processed/) |
| Slack | HTTP (SlackClient) | Saliente | Notificación de errores |
PostgreSQL (web_product_catalog) | JDBC | Entrante | Lectura 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).
| Clave | Descripció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.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ñ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:
- Rotar de forma coordinada las credenciales de Salesforce (Service Cloud y Marketing Cloud), compartidas con otros proyectos del ecosistema.
- Rotar la contraseña de BD, las credenciales SFTP 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
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(baseeclipse-temurin:25-jre,containerizingMode=packaged), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/sfsc-catalog-updater:<tag>. ElCLAUDE.mdmenciona una imagen baseeclipse-temurin:25-jdk-alpinecon heap de 4GB, que no coincide exactamente con la configuración vía Jib delpom.xmlactual. - Orquestación: Kubernetes
CronJoben el clúster GKEpi-cluster-hw, namespacepi, ejecutándose cada hora. Recursos elevados segúnCLAUDE.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 propioCLAUDE.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.mddetallado y verificado: los 3 runners, sus órdenes de ejecución, el patrón de paginación con limpieza deEntityManager, y las integraciones descritas coinciden con el código real (verificado directamente enSfscCatalogUpdaterRunner). Es uno de los documentosCLAUDE.mdmás precisos encontrados en este lote.- Instancia de utilidad estática en lugar de bean inyectado:
SfscCatalogUpdaterRunnerdeclarastatic final CatalogUpdaterUtil catalogUpdaterUtil = new CatalogUpdaterUtil()en lugar de inyectarlo como bean de Spring (a diferencia deproductService/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).