Skip to main content

order-dynamics-create-db

1. Descripción general

Según el pom.xml, el proyecto se describe como "Order Dynamics create DB". Es un microservicio batch (runner) que sincroniza pedidos generados en Dynamics 365 —recibidos como ficheros JSON en Google Cloud Storage— con la base de datos de logística.

2. Información técnica

CampoValor
artifactIdorder-dynamics-create-db
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 2 CommandLineRunner.

OrdenRunnerPropósito
0OrderDynamicsCreateDbLocalRunnerEntorno local/pruebas, con JSON hardcodeado, sin GCS
1OrderDynamicsCreateDbRunnerEntorno de producción: procesa ficheros de pedido pendientes en GCS
  • .configDynamicsDbConfig (datasource dynamics-pro), LogisticsDbConfig (datasource logistics), OrderDynamicsCreateDbConfig.
  • .modelOrderAzureBus (modelo mapeado con Gson; el nombre es un resto histórico, ver hallazgo en la sección 13).
  • .utilsOrderDynamicsCreateDbUtils (lógica de procesamiento, processMessage).
flowchart TD
A[OrderDynamicsCreateDbRunner] -->|lista prefix pending| B[(GCS pi-logistics-segment)]
A -->|descarga y parsea| C[OrderAzureBus]
C -->|processMessage| D{"¿existe ya el pedido?"}
D -->|no| E[crea Order/Customer/Shipment]
D -->|"sí, IsSendLogistic=false"| F[actualiza pedido existente]
D -->|"sí, IsSendLogistic=true"| G[lanza error, no modificable]
A -->|copyTo + delete| H[GCS processed/AAAA/MM/DD/]

Flujo: el runner de producción pagina los blobs de GCS bajo el prefijo order-dynamics-create-gs/orders_pending_dynamics/, descarga cada fichero, lo pasa a OrderDynamicsCreateDbUtils.processMessage, y si el procesamiento tiene éxito archiva el blob en el prefijo de procesados (particionado por fecha) y lo borra del prefijo de pendientes. Manejo de duplicados: si el pedido ya existe y IsSendLogistic=false, se actualiza; si ya existe y IsSendLogistic=true (ya enviado a logística), se lanza un error porque no puede modificarse.

4. Dependencias principales

DependenciaPropósito
spring-boot-starterNúcleo de Spring Boot (sin web, es un runner CLI)
spring-webRestClient/@HttpExchange usado por el cliente Slack
com.azure:azure-core / azure-messaging-servicebusDeclaradas, sin ningún uso en el código actual (ver hallazgo en la sección 13)
jakarta.xml.bind:jakarta.xml.bind-apiSoporte JAXB
com.hawkersco:dynamics-commonsAddressCountryRegion y entidades de dominio Dynamics
com.hawkersco:logistics-commonsEntidades Order, Customer, OrderLine, Shipment y servicios
com.hawkersco:slack-clientNotificaciones de error
com.hawkersco:pi-function-commonsUtilidades de GCS, fecha y directorio

5. API / Endpoints

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

6. Integraciones externas

SistemaProtocoloDirecciónDetalle
Google Cloud Storage (bucket pi-logistics-segment)API de GCSEntrante/SalienteLectura de pedidos pendientes de Dynamics y archivado tras procesar
SlackHTTP (SlackClient)SalienteNotificación de errores
PostgreSQL (dynamics-pro, logistics)JDBC (doble datasource)Entrante/SalienteLectura de datos Dynamics y escritura de pedidos en logística

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 dynamics-pro
logistics.datasource.*Credenciales de la BD logistics
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: la misma contraseña de PostgreSQL reutilizada para ambas bases de datos (dynamics-pro, logistics — ya señalada como expuesta en múltiples proyectos de este ecosistema), y el token de bot de Slack. Ninguna se ha reproducido en este documento. Se recomienda rotar ambas credenciales y sustituir los valores hardcodeados por credenciales de un entorno de desarrollo aislado.

8. Persistencia

Dos bases de datos PostgreSQL independientes: dynamics-pro (lectura, vía dynamics-commons) y logistics (escritura de Order, Customer, OrderLine, Shipment, vía logistics-commons), cada una con su propio EntityManagerFactory/TransactionManager (dynamicsTransactionManager/logisticsTransactionManager). No hay Flyway/Liquibase en este repositorio.

9. Procesos programados y mensajería

No hay @Scheduled ni listeners de colas activos: la periodicidad la impone el CronJob de Kubernetes, que ejecuta el contenedor cada 30 minutos (schedule: "*/30 * * * *"). Se ejecutan en orden los 2 runners de la tabla de la sección 3.

10. Ejecución en local

Requisitos previos: JDK 25, Maven, acceso a ambas BD.

# Compilar
mvn clean install

# Compilar sin tests (estilo producción)
mvn -B -DskipTests clean install

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

Para pruebas locales sin GCS, OrderDynamicsCreateDbLocalRunner (orden 0) se ejecuta primero con un JSON hardcodeado; el runner de producción solo procesa ficheros de GCS, por lo que en local no hace nada si GCS no es accesible. No existe script de test todavía (jenkins/scripts/test.sh está vacío).

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/order-dynamics-create-db:<tag>.
  • Orquestación: Kubernetes CronJob en el clúster GKE pi-cluster-hw, namespace pi, ejecutándose cada 30 minutos.
  • CI/CD (Jenkins): pipeline real de 3 etapas — CheckoutBuild & PushDeploy to GKE.

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/order-dynamics-create-db/

12. Manejo de errores y logging

No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). El procesamiento de duplicados ya enviados a logística lanza un error explícito para evitar modificar un pedido ya en curso. Logging mediante java.util.logging.Logger estándar (consola).

13. Notas y consideraciones

  • Dependencias de Azure Service Bus sin ningún uso en el código: el pom.xml declara com.azure:azure-core y com.azure:azure-messaging-servicebus, pero no se ha encontrado ninguna referencia a las clases del SDK de Azure en el código Java de este proyecto — el flujo real es exclusivamente vía ficheros JSON en GCS, tal y como describe el propio CLAUDE.md. El nombre del modelo OrderAzureBus es probablemente un resto de una arquitectura anterior en la que los pedidos llegaban directamente desde Azure Service Bus, antes de migrar al patrón actual de fichero intermedio en GCS. Convendría eliminar las dependencias de Azure si ya no tienen uso previsto, para reducir superficie y tamaño de la imagen.
  • config/SlackClientConfig y client/SlackClient citados en CLAUDE.md no existen como ficheros propios: el árbol de código real solo contiene DynamicsDbConfig, LogisticsDbConfig y OrderDynamicsCreateDbConfig en .config, y no existe ningún paquete client/ — el cliente de Slack se autoconfigura desde la propia librería slack-client (patrón @HttpExchange estándar de este ecosistema), no desde clases locales del proyecto.
  • El resto de la arquitectura descrita en CLAUDE.md (los 2 runners y su orden, el doble datasource, el manejo de duplicados) coincide con el código real, verificado directamente en OrderDynamicsCreateDbRunner.
  • Ver alerta de seguridad en la sección 7 sobre credenciales reales expuestas en application.properties.