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
| Campo | Valor |
|---|---|
artifactId | privalia-create-db |
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 5 CommandLineRunner, de los cuales solo 2 están activos.
com.hawkersco.privaliacreatedb— clase principal (PrivaliaCreateDbApplication) y los 5 runners..config—DynamicsDbConfig(datasource primariodynamics-pro),LogisticsDbConfig(datasource secundariologistics),PrivaliaCreateDbConfig(declaración manual de servicios)..utils—PrivaliaCreateDbUtils(transformación de pedidos, clientes, líneas, envíos).
| Runner | Orden | Estado | Propósito |
|---|---|---|---|
PrivaliaOneOrderCreateDbRunner | 0 | Desactivado (//@Component) | Depuración: procesa un único pedido hardcodeado |
PrivaliaOnlyPrivaliaOrderCreateDbRunner | 0 | Desactivado (//@Component) | Depuración: reprocesa pedidos ya existentes en la BD de logística |
PrivaliaCreateDbRunner | 1 | Activo | Flujo principal: todas las operaciones/lotes/pedidos de la API v3 de Privalia |
PrivaliaCreateDbNoDataRunner | 2 | Activo | Limpieza: pedidos a los que les falta el registro OrderMarketplace |
PrivaliaMarketplaceCreateDbRunner | 3 | Desactivado (//@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
| Dependencia | Propósito |
|---|---|
spring-boot-starter | Núcleo de Spring Boot (sin web, es un runner CLI) |
org.apache.poi:poi-ooxml:5.3.0 | Declarada; sin uso detectado en los runners activos |
commons-io:2.18.0 | Utilidades de E/S |
com.hawkersco:privalia-client:1.0.25-SNAPSHOT | Cliente @HttpExchange para la API v3 de Privalia (usado por el flujo activo) |
com.hawkersco:privalia-marketplace-client:1.0.25-SNAPSHOT | Cliente para la API v2 de Privalia Marketplace (usado solo por el runner desactivado) |
com.hawkersco:logistics-commons:1.0.25-SNAPSHOT | Entidades JPA y servicios de logística compartidos |
com.hawkersco:dynamics-commons:1.0.25-SNAPSHOT | Entidades de la BD Dynamics |
com.hawkersco:pi-function-commons:1.0.25-SNAPSHOT | Utilidades comunes |
com.hawkersco:slack-client:1.0.25-SNAPSHOT | Notificaciones de error a Slack |
lombok | Generació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
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
Privalia API v3 (dropshipment.veepee.com/api/v3) | HTTP (@HttpExchange vía PrivaliaClient) | Entrante/Saliente | Operaciones, 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/Saliente | Lectura de pedidos PENDING y actualización de estado a PROCESSING |
| Slack | HTTP (SlackClient) | Saliente | Alerta cuando un pedido llega con una fuente (idSource) no registrada |
PostgreSQL (dynamics-pro, logistics) | JDBC | Entrante/Saliente | Persistencia 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).
| Clave | Descripción | Ejemplo (producción) |
|---|---|---|
privalia.credentials.url / .token.username / .token.password | Credenciales de la API v3 de Privalia (producción; hay un bloque sandbox comentado con otras credenciales reales) | ${privaliaCredentialsUrl}, etc. |
spring.datasource.jdbc-url / .username / .password | Credenciales de la BD dynamics-pro (datasource primario) | ${dbDynamicsUrl}, etc. |
logistics.datasource.jdbc-url / .username / .password | Credenciales de la BD logistics (datasource secundario) | ${dbLogisitcsUrl}, etc. |
slack.client.url / .auth.token / .channel.id | Configuración del cliente Slack | ${slackClientUrl}, etc. |
gcs.bucket.name | Bucket de GCS (declarado; sin uso detectado en los runners activos) | pi-logistics-segment |
privaliacreatedb.prefix | Prefijo de nombre de pedido interno | PRIVEU |
privalia-marketplace-createdb.prefix | Prefijo para la integración v2 (declarado; runner desactivado) | PRIVEUMKT |
privaliacreatedb.auro.ftp.* | Credenciales SFTP para entrega de etiquetas a Auro | server/user/pass reales en local |
privaliacreatedb.v2.token | Token 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:
- 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.
- Eliminar el bloque sandbox comentado o sustituirlo por un marcador si se quiere conservar como referencia.
- 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
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 prefijoPRIVEU); genera la etiqueta ZPL y, si falla, intenta regenerarla a partir delparcel; guarda cliente, pedido, líneas, estado de envío y el registroOrderMarketplace(incluyendo la etiqueta codificada). Si la fuente del pedido no está registrada al guardar elShipment, notifica por Slack.PrivaliaCreateDbNoDataRunner(order=2): limpieza de pedidos a los que les falta el registroOrderMarketplace(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(baseeclipse-temurin:25-jre,containerizingMode=packaged), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/privalia-create-db:<tag>. - Orquestación: Kubernetes
CronJob(k8s/cronjob.yaml) en el clúster GKEpi-cluster-hw, namespacepi, ejecutándose 3 veces al día. - CI/CD (Jenkins): pipeline que sustituye
application-pro.propertiesporapplication.propertiesantes de construir. - Las variables sensibles se inyectan en el pod mediante un
Secretde 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 pedidosPENDING, actualización aPROCESSING), pero está desactivado (//@Component) y no se menciona en absoluto en elCLAUDE.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.processNewOrderincluye la condiciónString.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:
PrivaliaMarketplaceCreateDbRunnerinyecta${privaliacreatedb.v2.token}sin valor por defecto, pero esta propiedad no existe enapplication.propertiesni enapplication-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-ooxmlygcs.bucket.nameestán presentes en elpom.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.