Skip to main content

shopee-update-stock

1. Descripción general

Según el pom.xml, el proyecto se describe como "Shopee update stock". Es un microservicio batch (runner) que actualiza el stock de producto en las 5 tiendas regionales de Shopee (Malasia, Tailandia, Singapur, Filipinas, Vietnam) a partir de una hoja de Google Sheets que centraliza el stock y el mapeo de SKU→(itemId, modelId) por país.

2. Información técnica

CampoValor
artifactIdshopee-update-stock
groupIdcom.hawkersco
version1.0.25
Java25
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 un único CommandLineRunner (ShopeeUpdateStockRunner).

  • .configShopeeApiProperties (@ConfigurationProperties, credenciales y paths de la API de Shopee).
  • .utilShopeeUpdateStockUtil (obtención de token desde el servicio de credenciales, firma HMAC-SHA256, llamada a la API de Shopee).
flowchart TD
A[ShopeeUpdateStockRunner] -->|obtiene tokens 5 regiones| B[pi-generate-credentials]
A -->|lee stock!A2:B| C[Google Sheets]
A -->|lee sku_by_country!A2:O| C
A -->|para cada SKU y región| D[Shopee Partner API<br/>update_stock]
D -.->|fallo, hasta 5 reintentos| E[Recarga token]
A -->|System.exit al terminar| F[Fin del proceso]

Flujo: obtiene el token de acceso de las 5 tiendas regionales llamando al servicio interno pi-generate-credentials; lee de Google Sheets la hoja stock (SKU + cantidad) y la hoja sku_by_country (mapeo por columnas fijas de SKU→itemId/modelId para cada una de las 5 regiones); para cada SKU y cada región en la que exista mapeo, llama a la API de Shopee para actualizar el stock, reintentando hasta 5 veces con recarga de token entre intentos si la llamada falla.

4. Dependencias principales

DependenciaPropósito
spring-boot-starterNúcleo de Spring Boot (sin web, es un runner CLI)
spring-webRestClient/@HttpExchange
com.hawkersco:shopee-clientCliente @HttpExchange para la API de Shopee Partner
com.hawkersco:pi-generate-credentials-clientCliente para el servicio interno de credenciales (pi-generate-credentials)
com.hawkersco:pi-function-commonsSheetsServiceUtils (integración con Google Sheets)
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

SistemaProtocoloDirecciónDetalle
Google Sheets (hoja 1GfjSwIJ0y1xLzkblVMyFPmUdqBR51xXkO1wqsO21rHA)API de Google (SheetsServiceUtils)EntranteStock por SKU (stock!A2:B) y mapeo SKU→itemId/modelId por país (sku_by_country!A2:O)
pi-generate-credentials (servicio interno)HTTP (PiGenerateCredentialsClient)EntranteObtención/renovación de tokens de acceso para las 5 tiendas Shopee
Shopee Partner API (partner.shopeemobile.com)HTTP REST (firma HMAC-SHA256, ShopeeClient)SalienteActualización de stock (update_stock) por tienda regional

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ón
shopee.api.host / .partnerId / .partnerKeyCredenciales de partner de Shopee
shopee.api.shopId.{my,th,sg,ph,vn}IDs de tienda por región
shopee.api.path.*Rutas de la API de Shopee (update_stock, etc.)
credentials-client.api.hostURL del servicio interno pi-generate-credentials

⚠️ Alerta de seguridad

El fichero src/main/resources/application.properties (perfil local) contiene actualmente la clave de partner real de Shopee (shopee.api.partnerKey) — la misma ya señalada como expuesta en pi-generate-credentials. No se ha reproducido en este documento. Se recomienda:

  1. Rotar la clave de partner de Shopee, coordinando con pi-generate-credentials (que la comparte).
  2. Sustituir el valor hardcodeado de application.properties por credenciales de un entorno de desarrollo aislado.
  3. Revisar el historial de control de versiones.

8. Persistencia

No aplica a este proyecto. No usa base de datos: la fuente de verdad del stock es la hoja de Google Sheets, y el estado de credenciales se gestiona en el servicio externo pi-generate-credentials.

9. Procesos programados y mensajería

No hay @Scheduled ni listeners de colas: la periodicidad la impone el CronJob de Kubernetes, que ejecuta el contenedor lunes, miércoles y viernes a las 15:45 (schedule: "45 15 * * 1,3,5", zona horaria Europe/Madrid). Flujo único descrito en la sección 3.

10. Ejecución en local

Requisitos previos: JDK 25, Maven, credenciales de aplicación por defecto de Google (Sheets) y acceso al servicio pi-generate-credentials (local o remoto).

# Compilar sin tests
./mvnw -B -DskipTests clean install

# Ejecutar tests
./mvnw test

# Ejecutar la aplicación localmente
./mvnw spring-boot:run

# Build Docker
docker build -t shopee-update-stock .

Al ser un CommandLineRunner, no expone Actuator/health: la verificación se hace revisando el log de consola o el stock reflejado en el panel de Shopee Seller Center.

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/shopee-update-stock:<tag>.
  • Orquestación: Kubernetes CronJob en el clúster GKE pi-cluster-hw, namespace pi, contenedor no privilegiado (runAsNonRoot: true, allowPrivilegeEscalation: false), ejecutándose 3 veces por semana.
  • CI/CD (Jenkins): pipeline Build → KICS scan → SonarQube → Test → Docker push → kubectl apply, con el manifiesto del CronJob generado dinámicamente en jenkins/scripts/deployment.sh, según el propio CLAUDE.md.

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/shopee-update-stock/

12. Manejo de errores y logging

No hay una estrategia de excepciones centralizada (no hay @ControllerAdvice, es un runner). Cada línea de stock del Sheet se procesa en su propio try/catch, evitando que un error en un SKU detenga el resto del lote. Los fallos al obtener/recargar token se capturan devolviendo una cadena vacía en lugar de propagar la excepción. El envío a Shopee reintenta hasta 5 veces por SKU/región, recargando el token en cada intento fallido, independientemente de si el fallo es de autenticación o de otro tipo (p. ej. itemId/modelId inválido) — ver hallazgo en la sección 13. Logging mediante java.util.logging.Logger estándar (consola).

13. Notas y consideraciones

  • Reintento incondicional con recarga de token: updateRegionalStock recarga el token de acceso en cada uno de los 5 reintentos ante cualquier fallo de sendUpdate, sin distinguir si el error es realmente de autenticación (token caducado) o un error permanente de datos (p. ej. itemId/modelId no encontrado en Shopee). Para errores no relacionados con el token, esto genera hasta 5 llamadas innecesarias al servicio de credenciales y a la API de Shopee por cada SKU/región afectado, sin ninguna posibilidad de éxito.
  • CLAUDE.md verificado y consistente con el código: la arquitectura, el flujo de datos (Sheets → credenciales → Shopee), la clase principal y el patrón de reintento coinciden con lo observado directamente en ShopeeUpdateStockRunner.
  • Ver alerta de seguridad en la sección 7 sobre la clave de partner de Shopee expuesta en application.properties.