Skip to main content

products-dynamics-pi-gold

1. Descripción general

Según el pom.xml, el proyecto se describe como "Get all products to Dynamics and save PI Gold". Es la variante de products-dynamics-pi que sincroniza contra el entorno Dynamics "Gold" (una instancia/base de datos distinta, dynamics-gold, en un host de PostgreSQL diferente al de products-dynamics-pi). El flujo de negocio es idéntico salvo por una diferencia relevante: esta variante no sincroniza variantes de producto, solo productos/stock, precios de Privalia y códigos de barras.

2. Información técnica

CampoValor
artifactIdproducts-dynamics-pi-gold
groupIdcom.hawkersco
version1.0.25
Java25 (maven.compiler.release=25)
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 un único CommandLineRunner (ProductsDynamicsPiGoldRunner).

  • com.hawkersco.productsdynamicspigold — clase principal (ProductsDynamicsPiGoldApplication) y el runner.
  • .configProductsDynamicsPiGoldConfig (beans de servicios, PersistenceManagedTypesScanner).
flowchart TD
A[ProductsDynamicsPiGoldRunner] -->|getProductsPaginate x6 dataAreaId| B[Dynamics 365 API]
A -->|insertProductDynamicsList| C[(dynamics-gold · ProductDynamics)]
A -->|getPricesPrivaliaFromDate últimos 3 meses| B
A -->|truncate + batch insert| D[(dynamics-gold · DynamicsPricesPrivalia)]
A -->|getHWKInventItemBarcodes| B
A -->|truncate + batch insert| E[(dynamics-gold · DynamicsHWKInventItemBarcodes)]
A -->|System.exit al terminar| F[Fin del proceso]

A diferencia de products-dynamics-pi, este runner no inyecta VariantDynamicsService ni llama a dynamicsDataClient.getVariantsPaginate — no existe lógica de sincronización mensual de variantes en esta variante.

4. Dependencias principales

Idénticas a products-dynamics-pi: com.hawkersco:dynamics-commons, com.hawkersco:dynamics-client, com.hawkersco:privalia-client (esta última sin uso detectado en el código, igual que en el proyecto hermano).

5. API / Endpoints

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

6. Integraciones externas

SistemaProtocoloDirecciónDetalle
Dynamics 365 (dynamics.base.url)HTTP OAuth client_credentials (DynamicsDataClient)EntranteProductos/stock (paginado), precios de Privalia, códigos de barras — sin sincronización de variantes
PostgreSQL (dynamics-gold, host pi-saldum-db-dynamics.hawkersco.net)JDBCSalientePersistencia; nótese que es un host y base de datos distintos a los de products-dynamics-pi (que usa noctua-instance.hawkersco.net:5432/dynamics-pro)

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ónEjemplo (producción)
spring.datasource.url / .username / .passwordCredenciales de la BD dynamics-gold (usuario admin, distinto del pi-noctua-dbuser usado en el resto del ecosistema)${dbDynamicsUrl}, etc.
dynamics.login.*OAuth client_credentials para Dynamics 365 Commerce — mismo client-id que products-dynamics-pi, pero con un client-secret distinto (ver nota en sección 13)${dynamicsLoginClientId}, etc.
dynamics.picustomersetup.*OAuth client_credentials para Dynamics F&O (PI Customer Setup), también con secreto distinto al de products-dynamics-pi${dynamicsPiClientId}, etc.
slack.client.url / .auth.token / .channel.idConfiguración de Slack declarada, sin ningún uso real en el código (mismo patrón que products-dynamics-pi)${slackClientUrl}, etc.

⚠️ Alerta de seguridad (severidad alta)

El fichero src/main/resources/application.properties (perfil local) contiene actualmente credenciales OAuth reales de Dynamics 365 (Commerce y F&O, entorno Gold), la contraseña de la base de datos dynamics-gold (usuario admin), y un token de bot de Slack (xoxb-...). Ninguno de estos valores se ha reproducido en este documento. Se recomienda:

  1. Rotar el client-secret de ambas aplicaciones Azure AD del entorno Gold y la contraseña de la BD dynamics-gold.
  2. Rotar el token de Slack (compartido con otros proyectos del ecosistema).
  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 dynamics-gold (host pi-saldum-db-dynamics.hawkersco.net, distinto del resto del ecosistema PI, que usa mayoritariamente noctua-instance.hawkersco.net), acceso vía JPA a través de dynamics-commons. spring.jpa.hibernate.ddl-auto=none. Mismas entidades que products-dynamics-pi excepto VariantDynamics (no usada aquí). 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 (k8s/cronjob.yaml), que ejecuta el contenedor cada 15 minutos, mientras la hora esté entre la 01:00 y las 05:00 (schedule: "*/15 1-5 * * *") — a diferencia de products-dynamics-pi, que se ejecuta durante todo el día. En cada ejecución: recorre los 6 dataAreaId acumulando productos (con el mismo patrón de idProductDynamics reiniciado por área, ver hallazgo en la sección 13), los inserta, sincroniza precios de Privalia de los últimos 3 meses y códigos de barras (ambos con truncar + insertar), y cierra la JVM.

10. Ejecución en local

Requisitos previos: JDK 25, Maven, acceso a la BD dynamics-gold y credenciales OAuth válidas de Dynamics 365 (entorno Gold).

# Compilar sin tests
mvn -B -DskipTests clean install

# Ejecutar la aplicación localmente
mvn spring-boot:run

# Build & push con Jib
mvn clean package jib:build -DskipTests -Dimage.tag=<VERSION>

No hay suite de tests real más allá de la carga de contexto (ProductsDynamicsPiGoldApplicationTests). Al ser un CommandLineRunner, no expone Actuator/health.

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/products-dynamics-pi-gold:<tag>.
  • Orquestación: Kubernetes CronJob (k8s/cronjob.yaml) en el clúster GKE pi-cluster-hw, namespace pi, ejecutándose cada 15 minutos entre la 01:00 y las 05:00.
  • CI/CD (Jenkins): pipeline Checkout → Build & Push (Jib) → Deploy to GKE → Clean, según el propio CLAUDE.md.

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/products-dynamics-pi-gold/

12. Manejo de errores y logging

Idéntico a products-dynamics-pi: getProductDynamicsByDataAreaId captura cualquier excepción por página con Level.SEVERE y continúa con la siguiente página; el resto del flujo no tiene manejo de errores explícito. No hay notificación a Slack pese a la configuración presente. Logging mediante java.util.logging.Logger estándar (consola).

13. Notas y consideraciones

  • Mismo patrón de posible colisión de idProductDynamics que en products-dynamics-pi: getProductDynamicsByDataAreaId reinicia idProductDynamics a 1 en cada una de las 6 llamadas (una por dataAreaId), por lo que la lista acumulada final contiene identificadores duplicados entre distintas empresas antes de insertarse. Ver el detalle de este hallazgo en la documentación de products-dynamics-pi, ya que aplica igual aquí.
  • Sin sincronización de variantes: a diferencia de products-dynamics-pi, este runner no tiene ninguna lógica de actualización mensual de variantes (VariantDynamicsService no se usa). Si las variantes de Dynamics también deben reflejarse en dynamics-gold, no ocurre a través de este proyecto.
  • Mismo client-id de Dynamics con client-secret distinto al de products-dynamics-pi: ambos proyectos configuran dynamics.login.client-id=5bf489cc-e925-428e-ad7c-66bd92e0dbc9 (la misma aplicación Azure AD), pero con valores de client-secret diferentes. Esto es compatible con el soporte de Azure AD para múltiples secretos activos simultáneamente en una misma aplicación, por lo que no es necesariamente un error, pero conviene confirmarlo con el equipo de infraestructura para saber si ambos secretos siguen siendo válidos o si uno de los dos ficheros quedó desactualizado tras una rotación.
  • Host de base de datos distinto al resto del ecosistema: dynamics-gold vive en pi-saldum-db-dynamics.hawkersco.net, mientras que la mayoría de proyectos de este ecosistema usan noctua-instance.hawkersco.net. Es un detalle de infraestructura a tener en cuenta si se audita el acceso a bases de datos.
  • Ver alerta de seguridad en la sección 7 sobre credenciales reales expuestas en application.properties.