HK Times Logistics Client
1. Descripción general
hk-timeslogistics-client es una librería cliente reutilizable (JAR) que encapsula la comunicación con la API de Hong Kong Times Logistics (HKTL), proveedor de fulfillment logístico integrado en el ecosistema de microservicios de Hawkers. El proyecto no expone ningún endpoint REST propio; se publica en el registro de artefactos Maven interno y es consumido por otros microservicios que necesiten crear/cancelar pedidos, consultar inventario, SKUs o el estado de tracking en el almacén HKTL.
La librería gestiona de forma transparente la autenticación mediante token Bearer (con caché de 1 hora), de modo que los servicios consumidores no necesitan implementar ninguna lógica de autenticación. Expone operaciones para:
- Crear o actualizar un pedido (
order/create). - Cancelar un pedido (
orders/cancel). - Consultar inventario paginado (
inventory). - Consultar el listado paginado de SKUs (
sku). - Consultar el estado/tracking de un pedido (
order/status).
2. Información técnica
| Propiedad | Valor |
|---|---|
artifactId | hk-timeslogistics-client |
groupId | com.hawkersco |
version | 1.0.25-SNAPSHOT |
| Java | 25 |
| Spring Boot | 4.0.6 |
| Tipo de artefacto | JAR (librería, no ejecutable) |
| Módulos | Proyecto único (no multi-módulo) |
3. Arquitectura y diseño
Estructura del proyecto:
com.hawkersco.hktimeslogistics
├── client/
│ ├── HkTimesLogisticsClient.java # Interfaz @HttpExchange con las 5 operaciones de negocio
│ └── HkTimesLogisticsTokenClient.java # Interfaz @HttpExchange para obtención de token (/auth/login)
├── config/
│ ├── HkTimesLogisticsConfig.java # @AutoConfiguration principal (registra ambos clientes + interceptor Bearer)
│ ├── CacheStore.java # Cache genérica en memoria (Guava)
│ └── HkTimesLogisticsConstants.java # Constante TXT_TOKEN = "token"
└── pojos/
├── HkTimesLogisticsOrderCU / HkTimesLogisticsOrderCUResponse
├── HkTimesLogisticsOrderStatus
├── HkTimesLogisticsInventory
├── HkTimesLogisticSkus
└── HkTimesLogisticsTokenRequest / HkTimesLogisticsTokenResponse
Flujo principal de autenticación y llamada
sequenceDiagram
participant Consumidor as Microservicio consumidor
participant Client as HkTimesLogisticsClient
participant Cache as CacheStore
participant TokenClient as HkTimesLogisticsTokenClient
participant API as API HKTL
Consumidor->>Client: createOrder / getInventory / ...
Client->>Cache: get("token")
alt Token en caché (< 1h)
Cache-->>Client: token válido
else Token ausente o expirado
Client->>TokenClient: getToken(username, password)
TokenClient->>API: POST /auth/login
API-->>TokenClient: { "token": "...", "expires_in": ... }
TokenClient-->>Client: token
Client->>Cache: add("token", token)
end
Client->>API: request + header Authorization: Bearer <token>
API-->>Client: respuesta JSON
Client-->>Consumidor: ResponseEntity<T>
La autoconfiguración (HkTimesLogisticsConfig) se activa condicionalmente con @ConditionalOnProperty(prefix = "hktl", name = {"url", "id", "pass"}), por lo que solo se inicializa si las tres propiedades están presentes. Registra dos beans:
hkTimesLogisticsTokenClient—RestClientsin interceptor, usado únicamente para/auth/login.hkTimesLogisticsClient—RestClientcon unrequestInterceptorque resuelve el token (desde caché o pidiendo uno nuevo) e inyecta la cabeceraAuthorization: Bearer <token>en cada llamada.
El registro de la autoconfiguración se realiza mediante el fichero estándar de Spring Boot:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
4. Dependencias principales
| Dependencia | Versión | Propósito |
|---|---|---|
spring-boot-starter | (gestionada SB4) | Base de Spring Boot (contexto, autoconfiguración) |
spring-web | (gestionada SB4) | RestClient + @HttpExchange / HttpServiceProxyFactory |
org.json:json | 20251224 | Declarada en el pom.xml; no se usa en el código fuente actual |
com.google.guava:guava | 33.6.0-jre | Implementación de caché en CacheStore (CacheBuilder) |
com.google.code.gson:gson | (gestionada SB4) | Anotaciones @SerializedName en los POJOs (soporte dual con Jackson) |
com.fasterxml.jackson.core:jackson-databind | (gestionada SB4) | Serialización/deserialización Jackson en los POJOs |
org.projectlombok:lombok | 1.18.46 | Generación de boilerplate en los POJOs (getters, setters, constructores) |
spring-boot-starter-test | (gestionada SB4) | Testing (scope test) |
5. API / Endpoints
No aplica a este proyecto. hk-timeslogistics-client es una librería cliente JAR que no expone endpoints REST propios. Las operaciones que encapsula sobre la API de HKTL se detallan en la sección 6.
6. Integraciones externas
API de HKTL (fulfillment logístico)
| Método cliente | HTTP | Ruta remota | Dirección | Descripción |
|---|---|---|---|---|
createOrder | POST | /api/foms/v2/order/create | Saliente | Crea o actualiza un pedido en el sistema de fulfillment HKTL |
cancelOrder | POST | /api/foms/v1/orders/cancel | Saliente | Cancela un pedido existente por su orderName |
getInventory | GET | /api/foms/v2/inventory | Saliente | Consulta paginada del inventario del almacén (page, size) |
getSkus | GET | /api/foms/v2/sku | Saliente | Consulta paginada del catálogo de SKUs (page, size) |
getOrderStatus | GET | /api/foms/v2/order/status | Saliente | Consulta el estado de fulfillment y tracking de un pedido (orderNumber) |
El endpoint de autenticación es POST /auth/login (vía HkTimesLogisticsTokenClient), al que se llama con username/password en el body JSON.
Ejemplo de payload createOrder (HkTimesLogisticsOrderCU):
{
"warehouse_code": "HKG01",
"logistics_provider": { "code": "HKTL" },
"order_number": "ORD-000123",
"declared_value": 5000,
"currency": "USD",
"sender": {
"name": "Hawkers HK",
"company": "Hawkers",
"address": "...",
"city": "Hong Kong",
"country_code": "HK",
"phone": "...",
"email": "..."
},
"receiver": {
"name": "Cliente Final",
"address": "...",
"city": "...",
"province": "...",
"post_code": "...",
"country_code": "ES",
"phone": "..."
},
"items": [
{ "sku_code": "SKU-001", "unit_price": 2500, "qty": 2 }
]
}
Ejemplo de respuesta getOrderStatus (HkTimesLogisticsOrderStatus, resumida):
{
"code": 200,
"message": "OK",
"data": {
"order_number": "ORD-000123",
"packages": [
{
"master_tracking_number": "...",
"tracking_number": "...",
"courier_code": "...",
"courier_name": "...",
"package_status": {
"event_time": "2026-07-01T10:00:00",
"event_code": "DELIVERED",
"remark": ""
},
"items": [
{ "sku_code": "SKU-001", "qty": 2 }
]
}
]
}
}
Protocolo: HTTPS REST (JSON, contentType = application/json). Autenticación: Bearer token (obtenido dinámicamente vía /auth/login, cacheado 1 hora).
7. Configuración
No se incluye ningún application.properties/application.yml en la librería (no existe fichero de propiedades en src/main/resources, salvo el registro de autoconfiguración). Las propiedades deben ser inyectadas por la aplicación consumidora.
Propiedades requeridas (prefijo hktl)
| Propiedad | Descripción | Ejemplo de valor |
|---|---|---|
hktl.url | URL base de la API HKTL (activa la autoconfiguración) | ${HKTL_URL} |
hktl.id | Usuario para autenticación en HKTL | ${HKTL_ID} |
hktl.pass | Contraseña para autenticación en HKTL | ${HKTL_PASS} |
Importante: Si falta cualquiera de las tres propiedades (
hktl.url,hktl.id,hktl.pass), el beanHkTimesLogisticsConfigno se activa (condición@ConditionalOnPropertycon las tres claves).
Variables de entorno recomendadas
| Variable | Propiedad mapeada |
|---|---|
HKTL_URL | hktl.url |
HKTL_ID | hktl.id |
HKTL_PASS | hktl.pass |
8. Persistencia
No aplica a este proyecto. La librería no accede a ninguna base de datos. El único estado que persiste en memoria es la caché del token Bearer (CacheStore, TTL 1 hora, backend Guava).
9. Procesos programados y mensajería
No aplica a este proyecto. No existen jobs @Scheduled, listeners de colas/topics ni runners batch.
10. Ejecución en local
hk-timeslogistics-client es una librería JAR, no una aplicación ejecutable. No tiene servidor embebido ni endpoint de health.
Requisitos previos
- Java 25
- Maven 3.x
- Acceso al registro de artefactos Maven interno (
europe-west3-maven.pkg.dev/pi-saldum/pi-repo-maven) para resolver/publicar dependencias.
Compilar e instalar en repositorio local
# Compilar sin tests
mvn -B -DskipTests clean install
# Compilar con tests
mvn clean package
Uso como dependencia en un microservicio consumidor
<dependency>
<groupId>com.hawkersco</groupId>
<artifactId>hk-timeslogistics-client</artifactId>
<version>1.0.25-SNAPSHOT</version>
</dependency>
La autoconfiguración se activa automáticamente al declarar hktl.url, hktl.id y hktl.pass en la aplicación consumidora.
11. Despliegue
El pipeline de Jenkins (Jenkinsfile) consta de dos etapas:
- Checkout — descarga el código del repositorio.
- Publish to Artifact Registry — ejecuta
mvn deploy -DskipTestspara publicar el JAR en Google Artifact Registry.
| Parámetro | Valor |
|---|---|
| JDK | JDK25 (tool Jenkins) |
| Maven | Maven3 (tool Jenkins) |
| Repositorio | europe-west3-maven.pkg.dev/pi-saldum/pi-repo-maven (Artifact Registry GCP) |
No existe Dockerfile ni despliegue como servicio independiente; el artefacto es un JAR publicado en el registro Maven.
Job de Jenkins:
https://jenkins-pi.hawkersco.net/job/hk-timeslogistics-client/
12. Manejo de errores y logging
La librería no implementa ninguna estrategia propia de manejo de excepciones ni logging estructurado. Las excepciones de red o HTTP propagadas por RestClient (como RestClientException) son responsabilidad del servicio consumidor.
En resolveToken, si la respuesta de /auth/login no contiene body o el campo token viene nulo, el método devuelve una cadena vacía ("") en lugar de lanzar una excepción — esto provocaría que las llamadas posteriores se autentiquen con Authorization: Bearer (token vacío) y fallen con un error HTTP del lado de HKTL, en vez de fallar de forma explícita en el cliente.
No hay configuración de logback ni de niveles de log específicos en la librería.
13. Notas y consideraciones
-
Dependencia
org.jsonsin uso: Elpom.xmldeclaraorg.json:json(versión 20251224) pero no se encuentra ninguna referencia a esta librería en el código fuente (pojos/,client/,config/). Posible remanente de una versión anterior del cliente o de otro cliente similar (p. ej.auro-client) usado como plantilla. Pendiente de verificar si puede eliminarse. -
Fallo silencioso en
resolveToken: Si la autenticación falla o el body de respuesta no incluyetoken,HkTimesLogisticsConfig.resolveTokendevuelve""en lugar de propagar una excepción. Esto puede dificultar el diagnóstico de errores de autenticación, ya que el fallo real se manifestará como un 401/403 en la llamada de negocio posterior, no en el punto donde se obtiene el token. -
expires_inno utilizado:HkTimesLogisticsTokenResponseincluye el campoexpires_indevuelto por la API, pero la caché de token usa un TTL fijo de 1 hora (HkTimesLogisticsConfig) sin tener en cuenta este valor. Si HKTL emite tokens con una expiración distinta a 1 hora, podría producirse un desajuste entre el TTL de la caché local y la validez real del token. -
Doble serialización (Jackson + Gson): Todos los POJOs del paquete
pojos/contienen anotaciones de Jackson (@JsonProperty) y Gson (@SerializedName) simultáneamente, permitiendo que los microservicios consumidores usen cualquiera de las dos librerías para (de)serializar. Mismo patrón que otros clientes del ecosistema (p. ej.auro-client). -
Campos
Objecten POJOs de respuesta: Varios campos comoexpiry_date,manufacture_date,batch_no,udf_1/2/3enHkTimesLogisticsOrderStatus.Data.Itemy enHkTimesLogisticsInventory.Datumestán tipados comoObjecten lugar deString/tipo concreto, probablemente porque la API HKTL devuelve estos campos con tipo variable (string, null, número). Reduce la seguridad de tipos para el consumidor. -
Sin tests implementados: El directorio
src/test/no existe. La dependenciaspring-boot-starter-testestá declarada pero no hay ninguna prueba. Pendiente implementar cobertura. -
HkTimesLogisticsClientApplication.java: Existe una clase principal de Spring Boot en el paquete raíz (HkTimeslogisticsClientApplication), lo que es inusual para una librería. No tiene funcionalidad operativa y probablemente sea un artefacto residual de la generación inicial del proyecto con Spring Initializr, mismo patrón observado en otros clientes del ecosistema. -
Nombres de clase con inconsistencia de mayúsculas: El artifactId y el paquete usan
hktimeslogistics(minúsculas), mientras que las clases usanHkTimesLogistics...(con "Times" y "Logistics" en PascalCase); la clase principal usaHkTimeslogisticsClientApplication(con "logistics" en minúscula), una inconsistencia menor de nomenclatura entre la clase principal y el resto de clases del proyecto.