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
| Campo | Valor |
|---|---|
artifactId | shopee-update-stock |
groupId | com.hawkersco |
version | 1.0.25 |
| Java | 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 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
| Dependencia | Propósito |
|---|---|
spring-boot-starter | Núcleo de Spring Boot (sin web, es un runner CLI) |
spring-web | RestClient/@HttpExchange |
com.hawkersco:shopee-client | Cliente @HttpExchange para la API de Shopee Partner |
com.hawkersco:pi-generate-credentials-client | Cliente para el servicio interno de credenciales (pi-generate-credentials) |
com.hawkersco:pi-function-commons | SheetsServiceUtils (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
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
Google Sheets (hoja 1GfjSwIJ0y1xLzkblVMyFPmUdqBR51xXkO1wqsO21rHA) | API de Google (SheetsServiceUtils) | Entrante | Stock 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) | Entrante | Obtención/renovación de tokens de acceso para las 5 tiendas Shopee |
Shopee Partner API (partner.shopeemobile.com) | HTTP REST (firma HMAC-SHA256, ShopeeClient) | Saliente | Actualizació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).
| Clave | Descripción |
|---|---|
shopee.api.host / .partnerId / .partnerKey | Credenciales 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.host | URL 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:
- Rotar la clave de partner de Shopee, coordinando con
pi-generate-credentials(que la comparte). - Sustituir el valor hardcodeado de
application.propertiespor credenciales de un entorno de desarrollo aislado. - 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(baseeclipse-temurin:25-jre,containerizingMode=packaged), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/shopee-update-stock:<tag>. - Orquestación: Kubernetes
CronJoben el clúster GKEpi-cluster-hw, namespacepi, 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 delCronJobgenerado dinámicamente enjenkins/scripts/deployment.sh, según el propioCLAUDE.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:
updateRegionalStockrecarga el token de acceso en cada uno de los 5 reintentos ante cualquier fallo desendUpdate, sin distinguir si el error es realmente de autenticación (token caducado) o un error permanente de datos (p. ej.itemId/modelIdno 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.mdverificado 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 enShopeeUpdateStockRunner.- Ver alerta de seguridad en la sección 7 sobre la clave de partner de Shopee expuesta en
application.properties.