Este proyecto implementa el microservicio producto, responsable de gestionar productos dentro de una arquitectura de microservicios basada en Spring Boot y Spring Cloud.
Actualmente incluye:
- API REST funcional para productos
- Persistencia con MySQL
- Configuracion por perfiles (
dev,prod) - Migraciones versionadas con Flyway en
prod - Contenerizacion con Docker
- Documentacion OpenAPI/Swagger en
dev - Integracion operativa con Config Server
- Integracion operativa con Registry Server (Eureka)
- Integracion operativa con API Gateway
- Enrutamiento dinamico con
lb://producto - Comunicacion con
catalogomediante OpenFeign - Resiliencia con Circuit Breaker sobre la consulta a
catalogo - Seguridad local como
resource servercon validacion JWT
Client -> Gateway -> Microservicios -> Eureka -> Config Server
Este repositorio implementa unicamente el microservicio producto.
Estructura recomendada del entorno integrado:
ProyectosMS2026/
infra/
config-server/
registry-server/
gateway/
services/
catalogo/
producto/
- Java 17
- Spring Boot 3.5.12
- Maven 3.9+
- MySQL 8.4
- Docker
- Docker Compose
- Flyway
- SpringDoc OpenAPI
Comandos utiles:
java -version
mvn -v
docker -v
docker compose version- Spring Web
- Spring Data JPA
- Spring Validation
- Lombok
- MySQL Driver
- Flyway
- Spring Boot Actuator
- Spring Boot DevTools
- SpringDoc OpenAPI WebMVC UI
- Eureka Client
- OpenFeign
- Spring Cloud Circuit Breaker Resilience4j
La entidad principal es Producto y actualmente contiene:
idnombredescripcionidCategoria
Tabla actual:
productosMigracion base:
src/main/resources/db/migration/V1__create_productos_table.sql
| Servicio | Puerto |
|---|---|
| Aplicacion dev | 9091 |
| Aplicacion prod | 9092 |
| MySQL dev | 3391 |
| MySQL prod | 3392 |
| Modo | Ejecucion | Base de datos | Puerto app | Swagger | Flyway |
|---|---|---|---|---|---|
| DEV | Maven | MySQL local o Docker | 9091 | habilitado | deshabilitado |
| PROD | Docker Compose | Docker | 9092 | deshabilitado | habilitado |
producto es el modulo que concentra con mayor fuerza la transicion entre la base distribuida y la robustez del sistema:
S1-S4como microservicio registrable y enrutableS6como consumidor decatalogovia Feign y como punto de aplicacion de Circuit BreakerS7como fuente principal para observar trafico, fallos, fallback y trazabilidad end-to-endS8como microservicio protegido con JWT y roles, listo para control de acceso distribuido
Por eso producto suele ser el mejor punto de demostracion para:
- interaccion entre servicios
- resiliencia
- observabilidad de errores y fallback
Base path:
/api/v1/productos
Operaciones disponibles:
POST /api/v1/productosGET /api/v1/productosGET /api/v1/productos/{id}GET /api/v1/productos/detalle/{id}PUT /api/v1/productos/{id}DELETE /api/v1/productos/{id}
Ejemplo de payload:
{
"nombre": "Laptop Lenovo",
"descripcion": "Equipo para laboratorio",
"idCategoria": 1
}Regla de acceso actual:
- operaciones de lectura requieren usuario autenticado
- operaciones de escritura (
POST,PUT,DELETE) requierenROLE_ADMIN
Endpoint auxiliar para pruebas de gateway y balanceo:
GET /api/v1/producto/instancia
Ejemplo de respuesta:
{
"servicio": "producto",
"instancia": "9092",
"host": "nombre-del-host",
"traceId": "uuid-o-correlacion-actual"
}Endpoint enriquecido con categoria:
GET /api/v1/productos/detalle/{id}
Ejemplo de respuesta cuando catalogo responde:
{
"id": 1,
"nombre": "Laptop Lenovo",
"descripcion": "Equipo para laboratorio",
"idCategoria": 1,
"categoria": {
"id": 1,
"nombre": "Tecnologia",
"descripcion": "Productos tecnologicos"
}
}- Los cambios de esquema deben quedar en SQL versionado.
- Flyway ejecuta scripts en
src/main/resources/db/migrationcuando arrancaprod. - En
prod, Hibernate no crea tablas; valida el esquema existente. - En
dev, Hibernate usaddl-auto: updatey Flyway esta deshabilitado.
Flujo recomendado:
- Ajustar el esquema en SQL.
- Probar en
dev. - Crear nueva migracion (
V2,V3, etc.). - Aplicar en
prod. - Arrancar y validar.
git clone https://github.com/261dist/producto.git
cd productodocker compose -f docker-compose-dev.yml up -dEsto levanta MySQL dev en el puerto 3391 con la base db_producto.
mvn spring-boot:runPerfil activo por defecto:
dev
http://localhost:9091/api/v1/productos
http://localhost:9091/swagger-ui/index.html
http://localhost:9091/actuator/health
http://localhost:9091/api/v1/producto/instancia
http://localhost:7091/api/v1/producto/instancia
- Obtener JWT desde
auth-service:
$body = @{
username = "admin"
password = "admin123"
} | ConvertTo-Json
$response = Invoke-RestMethod `
-Method Post `
-Uri "http://localhost:8041/auth/login" `
-ContentType "application/json" `
-Body $body
$token = $response.accessToken- Probar lectura sin token:
Invoke-WebRequest `
-Uri "http://localhost:9091/api/v1/productos"Resultado esperado:
401 Unauthorized
- Probar lectura con token:
Invoke-RestMethod `
-Method Get `
-Uri "http://localhost:9091/api/v1/productos" `
-Headers @{ Authorization = "Bearer $token" }- Probar escritura con
ROLE_ADMIN:
$productoBody = @{
nombre = "Producto Seguridad"
descripcion = "Prueba JWT"
idCategoria = 1
} | ConvertTo-Json
Invoke-RestMethod `
-Method Post `
-Uri "http://localhost:9091/api/v1/productos" `
-Headers @{ Authorization = "Bearer $token" } `
-ContentType "application/json" `
-Body $productoBodyPRODUCTO_MYSQL_ROOT_PASSWORD=root
PRODUCTO_MYSQL_DATABASE=db_producto
SPRING_PROFILES_ACTIVE=prod
CONFIG_SERVER_URL=http://config-server:7071
PRODUCTO_DB_HOST=mysql-producto
PRODUCTO_DB_PORT=3306
PRODUCTO_DB_NAME=db_producto
PRODUCTO_DB_USERNAME=root
PRODUCTO_DB_PASSWORD=rootdocker compose -f docker-compose.yml up -dEsto levanta:
- MySQL prod en
3392 - la aplicacion
productoen9092
http://localhost:9092/api/v1/productos
http://localhost:9092/actuator/health
http://localhost:9092/api/v1/producto/instancia
http://localhost:7092/api/v1/producto/instancia
Swagger:
deshabilitado en prod
Ejemplo rapido sin detener el entorno previo:
docker create --name producto22 --network ms-net --env-file .env -p 9099:9092 producto-prod-producto
docker network connect producto-int producto22
docker start producto22Verificacion:
docker psPrueba por gateway:
http://localhost:7092/api/v1/producto/instancia
Limpieza:
docker stop producto22
docker rm producto22
docker rmi producto-prod-productoO limpiar el entorno:
docker rm -f producto22 producto33
docker compose -f docker-compose.yml downSPRING_CONFIG_IMPORT=optional:configserver:http://localhost:7071EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://localhost:7081/eurekauri: lb://productoRutas de verificacion:
http://localhost:7091/api/v1/producto/instancia
http://localhost:7092/api/v1/producto/instancia
La comunicacion entre microservicios esta operativa desde producto hacia catalogo:
productohabilita clientes Feign con@EnableFeignClientsCatalogoClientconsumeGET /api/v1/categorias/{id}findDetalleByIdarma una respuesta enriquecida con los datos de categoria- el cliente Feign resuelve el servicio por nombre usando Eureka:
@FeignClient(name = "catalogo")
En esta fase de seguridad:
productovalida JWT localmente comoresource servercatalogopermanece sin seguridad propia- el acceso a
catalogose sigue restringiendo desdegateway - esto permite comparar proteccion en el borde vs proteccion en el microservicio
Rutas de prueba:
http://localhost:9091/api/v1/productos/detalle/{id}
http://localhost:9092/api/v1/productos/detalle/{id}
http://localhost:7091/api/v1/productos/detalle/{id}
http://localhost:7092/api/v1/productos/detalle/{id}
La operacion GET /api/v1/productos/detalle/{id} esta protegida con Resilience4j.
ProductoServiceImpl.findDetalleById(...)usa@CircuitBreaker(name = "catalogo", fallbackMethod = "fallbackCategoria")- el circuito protege la llamada Feign hacia
catalogo - si
catalogofalla o no esta disponible, se activafallbackCategoria(...) - el fallback devuelve el producto y deja
categoriaennull
Configuracion actual en infra/config-repo/producto-dev.yml:
resilience4j:
circuitbreaker:
instances:
catalogo:
slidingWindowSize: 5
minimumNumberOfCalls: 3
failureRateThreshold: 50
waitDurationInOpenState: 5s
permittedNumberOfCallsInHalfOpenState: 2
automaticTransitionFromOpenToHalfOpenEnabled: trueComportamiento esperado:
- si
catalogoresponde bien,detalle/{id}retorna categoria - si
catalogoesta caido,detalle/{id}sigue respondiendo concategoria: null - despues de varios fallos, el circuito se abre temporalmente para evitar llamadas repetidas al servicio remoto
producto expone capacidades basicas de observabilidad para operacion e integracion:
GET /actuator/healthGET /actuator/metricsGET /actuator/prometheusGET /actuator/circuitbreakersGET /actuator/circuitbreakereventsGET /api/v1/producto/instancia- logs con
traceIden consola y archivo local
Ubicaciones de log en desarrollo:
services/producto/logs/producto.loginfra/gateway/logs/gateway.logservices/catalogo/logs/catalogo.log
La guia didactica paso a paso de esta fase no se repite en este README. Se mantiene en:
- SESION-06.P2-OBSERVABILIDAD.md
- SESION-07-OBSERVABILIDAD-CON-HERRAMIENTAS.md
En modo dev y prod, producto queda listo para integrarse con observabilidad externa:
- Prometheus consume metricas desde
/actuator/prometheus - Promtail recoge
services/producto/logs/*.log - Loki centraliza los logs
- Grafana consulta metricas y logs desde una sola interfaz
Verificacion operativa rapida:
- Levantar
infra,catalogoyproducto. - Consultar
GET /api/v1/productos/detalle/{id}. - Detener
catalogo. - Repetir la consulta varias veces.
- Verificar respuesta exitosa del producto con
categoria: nully logs de fallback.
- Config Server
- Registry Server (Eureka)
- API Gateway
- Enrutamiento
lb://producto - Feign
- Circuit Breaker + Observabilidad basica manual
- Observabilidad con herramientas
- Seguridad local en
productocomo resource server - Gestion del trafico (filtros, politicas y control de peticiones)
- Integracion con frontend
Continuar con atributos de calidad sobre la base actual:
- consolidar
S7con dashboards, consultas y trazabilidad guiada - consolidar
S8con validacion JWT local y comparacion frente acatalogo - aplicar gestion del trafico en Gateway
- habilitar integracion con frontend
Este proyecto no incluye aun:
- Gestion del trafico en Gateway
- Integracion con frontend
Importante:
- este repositorio (
producto) puede avanzar y versionarse en momentos distintos ainfraycatalogo - el tag sugerido de este README aplica solo al avance funcional de
producto
git branch
git pull origin maingit checkout -b tarea/avancegit add .
git commit -m "feat: avance"
git push -u origin tarea/avancegit checkout main
git pull origin main
git branch -d tarea/avance
git push origin --delete tarea/avancegit tag -a vs08-auth -m "Producto protegido como resource server con JWT y roles"
git push origin vs08-authgit tag -d vs08-auth
git push origin --delete vs08-authhttps://upeuoficial.github.io/carrera-sistemas-docs-operativos/