Skip to main content

robo-api

1. Descripción general

Según el pom.xml, el proyecto se describe como "Robo API". Es la API REST que sustenta la gestión de devoluciones de producto (creación, edición, listado, filtrado) para los distintos perfiles de usuario del ecosistema Hawkers: administradores, equipo de atención al cliente (ATC), tiendas físicas y clientes finales. Toda la persistencia se delega en librerías internas (logistics-commons, dynamics-commons); este proyecto no define entidades ni repositorios propios.

2. Información técnica

CampoValor
artifactIdrobo-api
groupIdcom.hawkersco
version1.0.25
Java25
Spring Boot4.0.6
Tipo de artefactojar (ejecutable, API web de larga duración)
MódulosNo aplica (proyecto de módulo único)

3. Arquitectura y diseño

API REST con 12 controladores, seguridad OAuth2/JWT basada en scopes, doble datasource y un modo de pruebas mediante tablas sombra.

  • .controllerReturnController, ReturnStoreController, ReturnReasonController, ReturnStatusController, ReturnLineStatusController, ReturnMethodController, ReturnPaymentMethodController, ReturnOriginController, ReturnLogController, ReturnAuth0UserController, OrderController, SourceController, RoboApiController.
  • .configSecurityConfig (JWT + reglas de autorización por scope), CorsConfig (segunda configuración CORS independiente, ver hallazgo en la sección 13), LogisticsDbConfig, DynamicsDbConfig, TestModeFilter, RequestContext, SwaggerConfig, AppConfig, AudienceValidator.
  • .jobRoboApiJob (sincronización de usuarios Auth0 desde Google Sheets — ver hallazgo crítico en la sección 13).
  • .utilRoboUtil (extracción de JWT, creación de log de devolución), RoboApiConst, ReturnStatusEnum.
  • .modelOrderDynamics, UserAuth0 (únicos modelos propios; el resto de entidades viven en las librerías comunes).
flowchart TD
A[Cliente/Frontend] -->|JWT Auth0, scope-based| B[SecurityConfig]
B --> C[Controladores REST]
C -->|X-Test-Mode: true| D[TestModeFilter → RequestContext ThreadLocal]
D -->|redirige a tablas *Test| E[(logistics · Return/ReturnLine/ReturnLog)]
C -->|modo normal| E
C --> F[(dynamics-pro · OrderShippedService)]
G["RoboApiJob (sin @Scheduled activo)"] -.->|Google Sheets → Auth0| H[Auth0 Management API]

Modo de pruebas (TestModeFilter)

Un filtro Servlet lee la cabecera X-Test-Mode; si vale true, activa un flag en RequestContext (ThreadLocal) que los servicios de logistics-commons usan para redirigir las operaciones a tablas sombra (ReturnTest, ReturnLineTest, ReturnLogTest) en lugar de las tablas de producción.

Seguridad

OAuth2 Resource Server con JWT emitido por Auth0 (robo-hawkers.eu.auth0.com), validado contra el JWKS público. Autorización por scope a nivel de ruta en SecurityConfig: SCOPE_admin, SCOPE_atc, SCOPE_store, SCOPE_customer, con reglas granulares por endpoint (p. ej. alta/edición/baja de motivos y métodos de devolución solo para SCOPE_admin).

4. Dependencias principales

DependenciaPropósito
spring-boot-starter-webExposición de los endpoints REST
spring-boot-starter-security + spring-boot-starter-oauth2-resource-serverAutenticación/autorización JWT vía Auth0
org.springdoc:springdoc-openapi-starter-webmvc-uiDocumentación Swagger/OpenAPI
com.hawkersco:logistics-commonsEntidades/servicios de devoluciones, pedidos, usuarios Auth0 de la app
com.hawkersco:dynamics-commonsOrderShippedService (datos de envío en Dynamics)
com.hawkersco:sfcc-commonsUtilidades de consulta de catálogo SFCC
com.hawkersco:slack-clientNotificaciones de error
com.hawkersco:auth0-clientCliente para la Management API de Auth0 (usado por RoboApiJob)
com.hawkersco:pi-function-commonsSheetsServiceUtils (lectura de Google Sheets)
spring-boot-devtoolsRecarga en caliente en desarrollo
lombokGeneración de código boilerplate

5. API / Endpoints

Endpoints agrupados por recurso (rutas verificadas en SecurityConfig), todos protegidos por JWT salvo los indicados como públicos:

RecursoRutasScopes permitidos
Público/swagger-ui/**, /v3/api-docs/**, /check/domainNinguno
Pedido/order/info, /order/create-returnadmin, atc, store, customer
Devolución/return/info, /return/info-all/**admin, atc, store (info también customer)
Devolución/return/filter, /return/new, /return/edit/**, /return/delete/**admin, atc, store
Método de devolución/return-method/info, /searchadmin, atc, store (+customer en search)
Método de devolución/return-method/new, /edit/**, /delete/**admin
Método de pago/return-payment-method/infoadmin, atc, store
Motivo de devolución/return-reason/info, /searchadmin, atc, store (+customer en info)
Motivo de devolución/return-reason/new, /edit/**, /delete/**admin
Estado de devolución/línea/return-status/info, /return-line-status/infoadmin, atc, store, customer
Origen de devolución/return-origin/infoadmin, atc, store
Fuente/source/infoadmin, atc, store
Tienda de devolución/return-store/infoadmin, atc, store
Tienda de devolución/return-store/edit/**admin
Log de devolución/return-log/info/**admin, atc, store
Usuario Auth0/return-auth0-user/info, /info/**, /edit/**admin

Cualquier otra ruta no listada se deniega explícitamente (anyRequest().denyAll()).

6. Integraciones externas

SistemaProtocoloDirecciónDetalle
Auth0 (robo-hawkers.eu.auth0.com)OAuth2/JWT + Management API (Auth0Client)Entrante/SalienteValidación de tokens de acceso a la API; gestión de usuarios (alta, asignación de rol) desde RoboApiJob
Google SheetsAPI de Google (SheetsServiceUtils)EntranteFuente de la lista de usuarios ATC/tienda a sincronizar con Auth0 (job desactivado)
Salesforce Commerce CloudHTTP (SfccUtils)EntranteConsulta de catálogo de producto
SlackHTTP (SlackClient)SalienteNotificaciones de error
PostgreSQL (logistics, dynamics-pro)JDBCEntrante/SalientePersistencia de devoluciones y datos de envío

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
spring.datasource.*Credenciales de la BD logistics
dynamics.datasource.*Credenciales de la BD dynamics-pro
spring.security.oauth2.resourceserver.jwt.issuer-uri / .audienceConfiguración del validador JWT de Auth0
auth0.client.url / .id / .secret / .audienceCredenciales de la Management API de Auth0 (usadas por RoboApiJob)
slack.client.url / .auth.token / .channel.idConfiguración de Slack

⚠️ Alerta de seguridad (severidad crítica)

Se han encontrado dos problemas de seguridad graves en este proyecto:

  1. Generación de contraseñas predecibles y registro en texto plano en RoboApiJob.uploadUsersAuth0(): al crear un nuevo usuario en Auth0, la contraseña asignada es Base64.getEncoder().encodeToString(email.getBytes()) — es decir, el propio email del usuario codificado en Base64, una transformación trivialmente reversible y por tanto equivalente a no tener contraseña real. Además, la línea logger.info(returnAuth0User.getEmail() + " - " + password) registra esa contraseña en texto plano en los logs de la aplicación. Aunque los tres métodos de RoboApiJob tienen su @Scheduled comentado (el job no se ejecuta automáticamente en la configuración actual), el código permanece en el repositorio y podría ejecutarse manualmente o reactivarse sin que nadie repare en esta debilidad. Cualquier cuenta creada por este mecanismo tendría una contraseña calculable por cualquiera que conozca (o adivine) el email del usuario.
  2. application.properties local con credenciales reales: contraseñas de ambas bases de datos PostgreSQL, client-secret real de la aplicación Auth0 Management API, y token de bot de Slack. Ninguno de estos valores se ha reproducido en este documento.

Se recomienda con prioridad máxima:

  1. Corregir uploadUsersAuth0() para generar una contraseña aleatoria criptográficamente segura (o, mejor, usar el flujo de invitación/reseteo de contraseña de Auth0 en lugar de asignar una contraseña inicial conocida), y eliminar el logger.info que imprime la contraseña.
  2. Si este job ha llegado a ejecutarse alguna vez en producción, forzar el reseteo de contraseña de todos los usuarios Auth0 creados por este mecanismo.
  3. Rotar el client-secret de Auth0, las contraseñas de BD y el token de Slack expuestos en application.properties.

8. Persistencia

Dos bases de datos PostgreSQL: logistics (entidades de devoluciones, motivos, métodos, tiendas, usuarios Auth0 de la app: Return, ReturnLine, ReturnLog, ReturnAuth0User, ReturnStore, etc., con sus variantes *Test para el modo de pruebas) y dynamics-pro (OrderShippedService). spring.jpa.hibernate.ddl-auto=none en ambas. No hay Flyway/Liquibase en este repositorio.

9. Procesos programados y mensajería

RoboApiJob contiene 3 métodos pensados como tareas programadas (createDbUsersAuth0, updateDbUsersAuth0, uploadUsersAuth0), pero los tres tienen su @Scheduled comentado — no se ejecutan automáticamente pese a que la clase principal habilita @EnableScheduling. Su propósito, si se reactivaran: sincronizar una hoja de Google Sheets con la tabla ReturnAuth0User, asociar usuarios a tiendas, y finalmente crear/actualizar esos usuarios en Auth0 con asignación de rol (ver alerta de seguridad sobre la generación de contraseñas).

10. Ejecución en local

Requisitos previos: JDK 25, Maven, acceso a ambas BD, y credenciales de Auth0 Management API si se necesita ejercitar RoboApiJob.

# Compilar
./mvnw clean install

# Compilar sin tests
./mvnw clean install -DskipTests

# Ejecutar (perfil dev)
./mvnw spring-boot:run

# Ejecutar todos los tests
./mvnw test

# Ejecutar con perfil de producción
java -jar target/robo-api-1.0.25.jar --spring.profiles.active=pro

Documentación interactiva disponible en /swagger-ui/ (ruta pública).

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/robo-api:<tag>.
  • Orquestación: Kubernetes Deployment (no CronJob) en el clúster GKE pi-cluster-hw, namespace pi.
  • CI/CD (Jenkins): pipeline que sustituye application-pro.properties por application.properties antes de construir.

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/robo-api/

12. Manejo de errores y logging

No se ha localizado un @RestControllerAdvice centralizado en el código revisado. RoboApiJob captura excepciones genéricas por operación (Sheets, Auth0) y registra con Level.SEVERE/WARNING, salvo updateDbUsersAuth0, que relanza IOException como RuntimeException sin capturarla. Logging mediante java.util.logging.Logger estándar (consola).

13. Notas y consideraciones

  • Generación de contraseñas predecibles y su registro en logs: ver alerta de seguridad crítica en la sección 7. Es el hallazgo más grave de todo este proyecto.
  • Doble configuración de CORS: SecurityConfig registra un CorsFilter propio con precedencia máxima, y por separado CorsConfig implementa WebMvcConfigurer.addCorsMappings con una configuración de orígenes casi idéntica pero no exactamente igual (CorsConfig no incluye OPTIONS de forma redundante con el filtro, y ambas definen la lista de orígenes por separado, con riesgo de que diverjan). Mismo patrón de duplicación de CORS ya observado en gio-api-notifications.
  • CLAUDE.md describe correctamente la arquitectura general (dual datasource, modo de pruebas, seguridad por scopes, integraciones), pero no menciona en absoluto el contenido interno de RoboApiJob ni el hallazgo de seguridad de la sección 7.
  • Ver alerta de seguridad en la sección 7 sobre credenciales reales expuestas en application.properties.