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
| Campo | Valor |
|---|---|
artifactId | order-dynamics-create-db |
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 2 CommandLineRunner.
| Orden | Runner | Propósito |
|---|---|---|
| 0 | OrderDynamicsCreateDbLocalRunner | Entorno local/pruebas, con JSON hardcodeado, sin GCS |
| 1 | OrderDynamicsCreateDbRunner | Entorno de producción: procesa ficheros de pedido pendientes en GCS |
.config—DynamicsDbConfig(datasourcedynamics-pro),LogisticsDbConfig(datasourcelogistics),OrderDynamicsCreateDbConfig..model—OrderAzureBus(modelo mapeado con Gson; el nombre es un resto histórico, ver hallazgo en la sección 13)..utils—OrderDynamicsCreateDbUtils(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
| Dependencia | Propósito |
|---|---|
spring-boot-starter | Núcleo de Spring Boot (sin web, es un runner CLI) |
spring-web | RestClient/@HttpExchange usado por el cliente Slack |
com.azure:azure-core / azure-messaging-servicebus | Declaradas, sin ningún uso en el código actual (ver hallazgo en la sección 13) |
jakarta.xml.bind:jakarta.xml.bind-api | Soporte JAXB |
com.hawkersco:dynamics-commons | AddressCountryRegion y entidades de dominio Dynamics |
com.hawkersco:logistics-commons | Entidades Order, Customer, OrderLine, Shipment y servicios |
com.hawkersco:slack-client | Notificaciones de error |
com.hawkersco:pi-function-commons | Utilidades de GCS, fecha y directorio |
5. API / Endpoints
No aplica a este proyecto. Es un batch/runner sin capa REST.
6. Integraciones externas
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
Google Cloud Storage (bucket pi-logistics-segment) | API de GCS | Entrante/Saliente | Lectura de pedidos pendientes de Dynamics y archivado tras procesar |
| Slack | HTTP (SlackClient) | Saliente | Notificación de errores |
PostgreSQL (dynamics-pro, logistics) | JDBC (doble datasource) | Entrante/Saliente | Lectura 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).
| Clave | Descripción |
|---|---|
spring.datasource.* | Credenciales de la BD dynamics-pro |
logistics.datasource.* | Credenciales de la BD logistics |
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: 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(baseeclipse-temurin:25-jre,containerizingMode=packaged), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/order-dynamics-create-db:<tag>. - Orquestación: Kubernetes
CronJoben el clúster GKEpi-cluster-hw, namespacepi, ejecutándose cada 30 minutos. - CI/CD (Jenkins): pipeline real de 3 etapas —
Checkout→Build & Push→Deploy 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.xmldeclaracom.azure:azure-coreycom.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 propioCLAUDE.md. El nombre del modeloOrderAzureBuses 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/SlackClientConfigyclient/SlackClientcitados enCLAUDE.mdno existen como ficheros propios: el árbol de código real solo contieneDynamicsDbConfig,LogisticsDbConfigyOrderDynamicsCreateDbConfigen.config, y no existe ningún paqueteclient/— el cliente de Slack se autoconfigura desde la propia libreríaslack-client(patrón@HttpExchangeestá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 enOrderDynamicsCreateDbRunner. - Ver alerta de seguridad en la sección 7 sobre credenciales reales expuestas en
application.properties.