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
| Campo | Valor |
|---|---|
artifactId | products-dynamics-pi-gold |
groupId | com.hawkersco |
version | 1.0.25 |
| Java | 25 (maven.compiler.release=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 único CommandLineRunner (ProductsDynamicsPiGoldRunner).
com.hawkersco.productsdynamicspigold— clase principal (ProductsDynamicsPiGoldApplication) y el runner..config—ProductsDynamicsPiGoldConfig(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
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
Dynamics 365 (dynamics.base.url) | HTTP OAuth client_credentials (DynamicsDataClient) | Entrante | Productos/stock (paginado), precios de Privalia, códigos de barras — sin sincronización de variantes |
PostgreSQL (dynamics-gold, host pi-saldum-db-dynamics.hawkersco.net) | JDBC | Saliente | Persistencia; 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).
| Clave | Descripción | Ejemplo (producción) |
|---|---|---|
spring.datasource.url / .username / .password | Credenciales 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.id | Configuració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:
- Rotar el
client-secretde ambas aplicaciones Azure AD del entorno Gold y la contraseña de la BDdynamics-gold. - Rotar el token de Slack (compartido con otros proyectos del ecosistema).
- 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 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(baseeclipse-temurin:25-jre,containerizingMode=packaged), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/products-dynamics-pi-gold:<tag>. - Orquestación: Kubernetes
CronJob(k8s/cronjob.yaml) en el clúster GKEpi-cluster-hw, namespacepi, 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 propioCLAUDE.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
idProductDynamicsque enproducts-dynamics-pi:getProductDynamicsByDataAreaIdreiniciaidProductDynamicsa1en cada una de las 6 llamadas (una pordataAreaId), 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 deproducts-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 (VariantDynamicsServiceno se usa). Si las variantes de Dynamics también deben reflejarse endynamics-gold, no ocurre a través de este proyecto. - Mismo
client-idde Dynamics conclient-secretdistinto al deproducts-dynamics-pi: ambos proyectos configurandynamics.login.client-id=5bf489cc-e925-428e-ad7c-66bd92e0dbc9(la misma aplicación Azure AD), pero con valores declient-secretdiferentes. 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-goldvive enpi-saldum-db-dynamics.hawkersco.net, mientras que la mayoría de proyectos de este ecosistema usannoctua-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.