Skip to main content

privalia-create-db

1. Descripción general

Según el pom.xml, el proyecto se describe como "Privalia create DB". Es un microservicio batch (runner) que importa los pedidos de dropshipment del marketplace Privalia (operado por Veepee) desde su API v3, genera/regenera las etiquetas de envío en formato ZPL, y persiste los pedidos como entidades internas (Order, OrderLine, Customer, OrderMarketplace, OrderShipmentStatus) repartidas entre dos bases de datos PostgreSQL (dynamics-pro y logistics).

El repositorio contiene también una integración v2 de Privalia (privalia-marketplace-client, con autenticación Bearer) implementada en un runner completo pero desactivado, no mencionado en absoluto en el CLAUDE.md (ver hallazgo en la sección 13).

2. Información técnica

CampoValor
artifactIdprivalia-create-db
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 5 CommandLineRunner, de los cuales solo 2 están activos.

  • com.hawkersco.privaliacreatedb — clase principal (PrivaliaCreateDbApplication) y los 5 runners.
  • .configDynamicsDbConfig (datasource primario dynamics-pro), LogisticsDbConfig (datasource secundario logistics), PrivaliaCreateDbConfig (declaración manual de servicios).
  • .utilsPrivaliaCreateDbUtils (transformación de pedidos, clientes, líneas, envíos).
RunnerOrdenEstadoPropósito
PrivaliaOneOrderCreateDbRunner0Desactivado (//@Component)Depuración: procesa un único pedido hardcodeado
PrivaliaOnlyPrivaliaOrderCreateDbRunner0Desactivado (//@Component)Depuración: reprocesa pedidos ya existentes en la BD de logística
PrivaliaCreateDbRunner1ActivoFlujo principal: todas las operaciones/lotes/pedidos de la API v3 de Privalia
PrivaliaCreateDbNoDataRunner2ActivoLimpieza: pedidos a los que les falta el registro OrderMarketplace
PrivaliaMarketplaceCreateDbRunner3Desactivado (//@Component)Integración v2 (API REST con Bearer token) — no documentada en CLAUDE.md, ver sección 13
flowchart TD
A[PrivaliaCreateDbRunner] -->|getOperations| B[Privalia API v3]
B -->|getBatchesByOperation| B
B -->|getDeliveryOrdersByBatch| B
B -->|generateLabelZpl / getParcel| B
A -->|guarda Customer, Order, OrderLine,<br/>OrderShipmentStatus, OrderMarketplace| C[(logistics)]
A -->|guarda Shipment| D[(dynamics-pro vía logistics-commons)]
A -.->|fuente sin registrar| E[Slack]

F["PrivaliaMarketplaceCreateDbRunner (DESACTIVADO)"] -.->|Bearer token| G[Privalia Marketplace API v2]

Doble datasource

Dos datasources PostgreSQL independientes con EntityManager/TransactionManager propios: DynamicsDbConfig (@Primary, BD dynamics-pro, gestor dynamicsTransactionManager) y LogisticsDbConfig (BD logistics, gestor logisticsTransactionManager). El código que necesita transaccionalidad explícita debe indicar el gestor: @Transactional("logisticsTransactionManager").

4. Dependencias principales

DependenciaPropósito
spring-boot-starterNúcleo de Spring Boot (sin web, es un runner CLI)
org.apache.poi:poi-ooxml:5.3.0Declarada; sin uso detectado en los runners activos
commons-io:2.18.0Utilidades de E/S
com.hawkersco:privalia-client:1.0.25-SNAPSHOTCliente @HttpExchange para la API v3 de Privalia (usado por el flujo activo)
com.hawkersco:privalia-marketplace-client:1.0.25-SNAPSHOTCliente para la API v2 de Privalia Marketplace (usado solo por el runner desactivado)
com.hawkersco:logistics-commons:1.0.25-SNAPSHOTEntidades JPA y servicios de logística compartidos
com.hawkersco:dynamics-commons:1.0.25-SNAPSHOTEntidades de la BD Dynamics
com.hawkersco:pi-function-commons:1.0.25-SNAPSHOTUtilidades comunes
com.hawkersco:slack-client:1.0.25-SNAPSHOTNotificaciones de error a Slack
lombokGeneración de código boilerplate
spring-boot-starter-test (test)JUnit 5 + Spring Test

5. API / Endpoints

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

6. Integraciones externas

SistemaProtocoloDirecciónDetalle
Privalia API v3 (dropshipment.veepee.com/api/v3)HTTP (@HttpExchange vía PrivaliaClient)Entrante/SalienteOperaciones, lotes, pedidos de entrega, generación/regeneración de etiqueta ZPL, consulta de parcel
Privalia Marketplace API v2 (usado solo por el runner desactivado)HTTP (Bearer token, PrivaliaMarketplaceClient)Entrante/SalienteLectura de pedidos PENDING y actualización de estado a PROCESSING
SlackHTTP (SlackClient)SalienteAlerta cuando un pedido llega con una fuente (idSource) no registrada
PostgreSQL (dynamics-pro, logistics)JDBCEntrante/SalientePersistencia de pedidos y envíos en ambas bases

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)
privalia.credentials.url / .token.username / .token.passwordCredenciales de la API v3 de Privalia (producción; hay un bloque sandbox comentado con otras credenciales reales)${privaliaCredentialsUrl}, etc.
spring.datasource.jdbc-url / .username / .passwordCredenciales de la BD dynamics-pro (datasource primario)${dbDynamicsUrl}, etc.
logistics.datasource.jdbc-url / .username / .passwordCredenciales de la BD logistics (datasource secundario)${dbLogisitcsUrl}, etc.
slack.client.url / .auth.token / .channel.idConfiguración del cliente Slack${slackClientUrl}, etc.
gcs.bucket.nameBucket de GCS (declarado; sin uso detectado en los runners activos)pi-logistics-segment
privaliacreatedb.prefixPrefijo de nombre de pedido internoPRIVEU
privalia-marketplace-createdb.prefixPrefijo para la integración v2 (declarado; runner desactivado)PRIVEUMKT
privaliacreatedb.auro.ftp.*Credenciales SFTP para entrega de etiquetas a Auroserver/user/pass reales en local
privaliacreatedb.v2.tokenToken Bearer para la API v2 — no está definida en ningún perfil (ver sección 13)

⚠️ Alerta de seguridad

El fichero src/main/resources/application.properties (perfil local) contiene actualmente credenciales reales en texto plano: contraseñas de la API de Privalia (tanto de producción como de un bloque "SANDBOX" comentado), contraseñas de ambas bases de datos PostgreSQL, credenciales SFTP de Auro y token de bot de Slack (xoxb-...). Ninguno de estos valores se ha reproducido en este documento. Se recomienda:

  1. Rotar las credenciales de Privalia (producción y sandbox), las contraseñas de ambas BD, las credenciales SFTP de Auro y el token de Slack.
  2. Eliminar el bloque sandbox comentado o sustituirlo por un marcador si se quiere conservar como referencia.
  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

Dos bases de datos PostgreSQL independientes: dynamics-pro (datasource primario) y logistics (datasource secundario), ambas accedidas vía JPA a través de logistics-commons/dynamics-commons. spring.jpa.hibernate.ddl-auto=none en ambas. Entidades relevantes: Order, OrderLine, Customer, OrderMarketplace, OrderShipmentStatus, SkuEyeglassesSoldInPrivalia (lista de SKUs de gafas vendidas en Privalia, usada para clasificar líneas de pedido). 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 tres veces al día (schedule: "30 7,9,13 * * *"). Se ejecutan en orden los 2 runners activos:

  • PrivaliaCreateDbRunner (order=1): recorre operaciones → lotes → pedidos de entrega de la API v3; omite los pedidos cancelados y los ya existentes (por nombre de pedido con el prefijo PRIVEU); genera la etiqueta ZPL y, si falla, intenta regenerarla a partir del parcel; guarda cliente, pedido, líneas, estado de envío y el registro OrderMarketplace (incluyendo la etiqueta codificada). Si la fuente del pedido no está registrada al guardar el Shipment, notifica por Slack.
  • PrivaliaCreateDbNoDataRunner (order=2): limpieza de pedidos a los que les falta el registro OrderMarketplace (no se ha revisado su implementación en detalle en este documento, dado el alcance).

10. Ejecución en local

Requisitos previos: JDK 25, Maven, acceso a ambas BD (dynamics-pro, logistics) y credenciales válidas de la API de Privalia en un application.properties local.

# Compilar sin tests
mvn -B -DskipTests clean install

# Compilar con tests
mvn clean install

# Ejecutar el JAR directamente
java -jar target/privalia-create-db.jar

Para depurar un pedido concreto: descomentar @Component en PrivaliaOneOrderCreateDbRunner (o PrivaliaOnlyPrivaliaOrderCreateDbRunner) y comentar el de PrivaliaCreateDbRunner, según indica el propio CLAUDE.md. Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o la tabla orders (prefijo PRIVEU) tras la ejecución.

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/privalia-create-db:<tag>.
  • Orquestación: Kubernetes CronJob (k8s/cronjob.yaml) en el clúster GKE pi-cluster-hw, namespace pi, ejecutándose 3 veces al día.
  • CI/CD (Jenkins): pipeline que sustituye application-pro.properties por application.properties antes de construir.
  • Las variables sensibles se inyectan en el pod mediante un Secret de Kubernetes llamado igual que la app (privalia-create-db).

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

12. Manejo de errores y logging

No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). PrivaliaCreateDbRunner captura RestClientResponseException en cada nivel de la cadena (operaciones, lotes, pedidos, generación de etiqueta, parcel), registrando con logger.warn y continuando con el resto de elementos sin abortar todo el proceso. Notificación a Slack únicamente cuando la fuente del pedido no está registrada al guardar el Shipment. Logging mediante SLF4J (consola).

13. Notas y consideraciones

  • Integración v2 de Privalia completamente implementada pero no documentada: PrivaliaMarketplaceCreateDbRunner (orden 3) implementa un flujo completo alternativo contra una API v2 de Privalia Marketplace (autenticación Bearer, lectura de pedidos PENDING, actualización a PROCESSING), pero está desactivado (//@Component) y no se menciona en absoluto en el CLAUDE.md, que solo describe 4 runners. Es probable que sea una migración en curso hacia una nueva versión de la API de Privalia.
  • Pedido excluido explícitamente por ID hardcodeado: PrivaliaMarketplaceCreateDbRunner.processNewOrder incluye la condición String.valueOf(orderId).equals("2011625") para omitir un pedido específico, además de la comprobación normal de duplicados. Es una exclusión puntual fijada en código (probablemente para evitar reprocesar un pedido problemático durante pruebas) que debería documentarse con un comentario explicando el motivo, o eliminarse si ya no es necesaria.
  • Propiedad de configuración requerida pero ausente: PrivaliaMarketplaceCreateDbRunner inyecta ${privaliacreatedb.v2.token} sin valor por defecto, pero esta propiedad no existe en application.properties ni en application-pro.properties. Si el runner se reactivase sin añadir esta propiedad, la aplicación fallaría al arrancar por no poder resolver el placeholder.
  • Dependencias declaradas sin uso aparente en el flujo activo: poi-ooxml y gcs.bucket.name están presentes en el pom.xml/configuración pero no se ha detectado su uso en los runners activos (PrivaliaCreateDbRunner, PrivaliaCreateDbNoDataRunner); podrían usarse en los runners de depuración desactivados, no revisados exhaustivamente en este documento.
  • Ver alerta de seguridad en la sección 7 sobre credenciales reales expuestas en application.properties, incluyendo un bloque de credenciales sandbox comentado.