pickup-point-create-db
1. Descripción general
Según el pom.xml, el proyecto se describe como "Pickup Points create db". Es un microservicio batch (runner) que sincroniza el catálogo de puntos de recogida de dos transportistas — CTT (vía fichero CSV público) y GLS (vía API XML, para 15 países europeos) — con la tabla pickup_point de la base de datos de logística, añadiendo los puntos nuevos y eliminando los que ya no existen en la fuente.
2. Información técnica
| Campo | Valor |
|---|---|
artifactId | pickup-point-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 dos CommandLineRunner, ambos activos.
com.hawkersco.pickuppointcreatedb— clase principal (PickupPointCreateDbApplication) y los dos runners..config—PickupPointCreateDBConfig(beanPickupPointService,PersistenceManagedTypes, cliente GLS)..pojo—CTTPoint(POJO mapeado desde columnas del CSV de CTT)..utils—PickupPointCreateDbUtils(marshalling/unmarshalling JAXB de las respuestas XML de GLS).
flowchart TD
A["1. PickupPointCTTCreateDbRunner"] -->|descarga CSV| B[transfer.cttexpress.com]
A -->|diff códigos DB vs CSV| C[(logistics · pickup_point)]
D["2. PickupPointGLSCreateDbRunner"] -->|por cada país + zip existente| E[GLS API XML]
D -->|diff códigos DB vs API| C
D -->|System.exit al terminar| F[Fin del proceso]
Ambos runners siguen el mismo patrón de sincronización: construyen el conjunto de códigos ya presentes en BD, el conjunto de códigos de la fuente externa, calculan la diferencia (Sets.difference de Guava) para saber qué añadir y qué borrar, y aplican ambos cambios.
4. Dependencias principales
| Dependencia | Propósito |
|---|---|
spring-boot-starter | Núcleo de Spring Boot (sin web, es un runner CLI) |
com.opencsv:opencsv:5.12.0 | Parseo del CSV de puntos CTT |
jakarta.xml.bind:jakarta.xml.bind-api:4.0.1 | JAXB para (des)serializar el XML de GLS |
com.hawkersco:gls-pickup-client:1.0.25-SNAPSHOT | Cliente @HttpExchange (GlsPickupClient) para la API de puntos de GLS |
com.hawkersco:logistics-commons:1.0.25-SNAPSHOT | PickupPoint (entidad), PickupPointService |
com.hawkersco:pi-function-commons:1.0.25-SNAPSHOT | DateUtils, DirectoryUtils |
com.hawkersco:slack-client:1.0.25-SNAPSHOT | Declarada en el pom.xml; sin uso detectado en el código actual (ver sección 13) |
lombok | Generación de código boilerplate (usada en CTTPoint) |
spring-boot-starter-test (test) | JUnit 5 + Spring Test |
5. API / Endpoints
No aplica a este proyecto. Es un batch/runner sin capa REST.
6. Integraciones externas
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
CTT Express (transfer.cttexpress.com/IT/export/integra/PUNTOSCTT.csv) | HTTP (descarga directa de CSV) | Entrante | Fichero público con todos los puntos de recogida de CTT |
GLS (wsclientes.asmred.com/infoasm.asmx) | HTTP (@HttpExchange vía GlsPickupClient, XML) | Entrante | Búsqueda de puntos de recogida cercanos a un código postal, para 15 países EU |
PostgreSQL (logistics) | JDBC | Entrante/Saliente | Lectura/escritura de la tabla pickup_point |
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 logistics | ${dbLogisitcsUrl}, etc. |
gls.client.url | URL base del servicio web de GLS | https://wsclientes.asmred.com/infoasm.asmx |
slack.client.url / .auth.token / .channel.id | Configuración del cliente Slack (declarada, sin uso real, ver sección 13) | ${slackClientUrl}, etc. |
⚠️ Alerta de seguridad
El fichero src/main/resources/application.properties (perfil local) contiene actualmente credenciales reales en texto plano: contraseña de la base de datos PostgreSQL y token de bot de Slack (xoxb-...). Ninguno de estos valores se ha reproducido en este documento. Se recomienda:
- Rotar la contraseña de BD y el token de Slack expuestos.
- 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 (logistics), acceso vía JPA a través de la librería logistics-commons. spring.jpa.hibernate.ddl-auto=none. Entidad relevante: PickupPoint (misma entidad consultada por pickup-point-api). 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 dos veces al día, a las 08:00 y a las 20:00 (schedule: "0 8,20 * * *"). Se ejecutan en orden los 2 runners:
PickupPointCTTCreateDbRunner(order=1): descarga el CSV público de CTT, lo parsea con OpenCSV, compara los códigos de punto con los ya existentes en BD para el carrierCTT, añade los nuevos y elimina los que ya no aparecen en el CSV.PickupPointGLSCreateDbRunner(order=2): para cada uno de los 15 países soportados (AT, BE, HR, CZ, DK, FI, FR, DE, HU, IT, LU, NL, PL, SK, SI), obtiene primero los códigos postales ya distintos existentes en BD para ese país (findDistinctZipCodesByCountry) y, si no hay ninguno, omite el país por completo; para cada código postal existente, consulta la API de GLS (radio-1, sin límite) y agrega los puntos devueltos, deduplicando por código. Al terminar todos los países, cierra la JVM.
10. Ejecución en local
Requisitos previos: JDK 25, Maven, acceso a la BD logistics y conectividad hacia CTT/GLS.
# Compilar sin tests
./mvnw clean install -DskipTests
# Compilar con tests
./mvnw clean install
# Ejecutar todos los tests
./mvnw test
# Ejecutar un test concreto
./mvnw test -Dtest=PickupPointCreateDbApplicationTests
./mvnw test -Dtest=PickupPointCreateDbApplicationTests#contextLoads
Al ser un CommandLineRunner, no expone Actuator/health: la forma de verificar la ejecución es revisar el log de consola o consultar el número de registros en pickup_point por carrier 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/pickup-point-create-db:<tag>. - Orquestación: Kubernetes
CronJob(k8s/cronjob.yaml) en el clúster GKEpi-cluster-hw, namespacepi, ejecutándose dos veces al día. - CI/CD (Jenkins): pipeline con
Build & Push(sustituyeapplication-pro.propertiesporapplication.properties) →Deploy to GKE. ElCLAUDE.mddescribe un pipeline más extenso (Build → KICS scan → SonarQube → Test → Docker push → Deploy), no verificado exhaustivamente contra elJenkinsfilereal en este documento. - Las variables sensibles se inyectan en el pod mediante un
Secretde Kubernetes llamado igual que la app (pickup-point-create-db).
Job de Jenkins: https://jenkins-pi.hawkersco.net/job/pickup-point-create-db/
12. Manejo de errores y logging
No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). PickupPointCTTCreateDbRunner.downloadCsvFile captura IOException y devuelve false si la descarga falla, evitando la sincronización en ese ciclo. PickupPointGLSCreateDbRunner.run() envuelve todo el bucle de países en un único try/catch que registra el error con Level.INFO (no SEVERE/WARNING) y continúa hasta cerrar la JVM. Ningún runner notifica errores por Slack pese a tener la dependencia declarada. Logging mediante java.util.logging.Logger estándar (consola).
13. Notas y consideraciones
slack-clientdeclarado pero sin uso: la dependencia está en elpom.xmly elCLAUDE.mdla describe como responsable de "notifications", pero no se ha encontrado ninguna llamada aSlackClienten ninguno de los dos runners; todos los errores quedan solo en el log del pod.- GLS solo se sincroniza para códigos postales que ya existen en BD:
PickupPointGLSCreateDbRunnerobtiene primero los códigos postales ya presentes en la tablapickup_pointpara cada país (findDistinctZipCodesByCountry) y usa esa lista para consultar la API de GLS; si un país no tiene ningún punto GLS previamente registrado, se omite por completo (if (zipCodes.isEmpty()) return;). Esto significa que añadir GLS como carrier en un país completamente nuevo requeriría una carga inicial manual de al menos un código postal antes de que este runner pueda empezar a descubrir puntos automáticamente — un efecto "huevo y gallina" a tener en cuenta si se amplía la cobertura de países. - Nivel de log inconsistente en errores:
PickupPointGLSCreateDbRunnerregistra su error de nivel más alto conLevel.INFOen lugar deWARNING/SEVERE, lo que podría hacer que fallos reales de sincronización pasen desapercibidos en sistemas de monitorización que filtran por nivel de log. - Ver alerta de seguridad en la sección 7 sobre credenciales reales expuestas en
application.properties.