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).

  • .config — ShopeeApiProperties (@ConfigurationProperties, credenciales y paths de la API de Shopee).
  • .util — ShopeeUpdateStockUtil (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.