Prueba técnica — Módulo 2 (Hands-on Code Challenge) Autor: Jhon Alejandro Murillo Diaz
API REST para la gestión de pólizas de arrendamiento de inmuebles (individuales y colectivas), sus riesgos, renovación con ajuste de IPC y sincronización con el CORE transaccional legado (simulado).
| Componente | Versión / Detalle |
|---|---|
| Lenguaje | Java 21 |
| Framework | Spring Boot 3.3.5 (Web, Data JPA, Validation) |
| Persistencia | H2 en memoria (no requiere instalación) |
| Documentación | springdoc-openapi (Swagger UI) |
| Build | Maven (incluye Maven Wrapper mvnw) |
| Pruebas | JUnit 5, Mockito, Spring MockMvc |
- JDK 21 instalado y disponible (
JAVA_HOMEapuntando a un JDK 21). - Conexión a internet la primera vez (para que Maven descargue dependencias).
- No necesita Maven instalado: el proyecto incluye el Maven Wrapper (
mvnw/mvnw.cmd).
Verificar Java:
java -version
# openjdk version "21.x.x"Desde la carpeta raíz del proyecto (poliza-api/):
Windows (PowerShell / CMD):
mvnw.cmd spring-boot:runLinux / macOS:
./mvnw spring-boot:runWindows:
mvnw.cmd clean package
java -jar target\poliza-api-1.0.0.jarLinux / macOS:
./mvnw clean package
java -jar target/poliza-api-1.0.0.jarLa aplicación arranca en http://localhost:8080.
Al iniciar se cargan datos de ejemplo en memoria:
| id | número | tipo | riesgos |
|---|---|---|---|
| 1 | POL-IND-001 | INDIVIDUAL | 1 |
| 2 | POL-COL-001 | COLECTIVA | 2 |
Todos los endpoints de negocio exigen el header:
x-api-key: 123456
Si el header falta o es inválido, la API responde 401 Unauthorized.
Rutas públicas (sin API key): Swagger UI,
v3/api-docs, consola H2 y la raíz.
Todos los errores se devuelven como application/problem+json (estándar RFC 7807 / ProblemDetail), con códigos HTTP semánticos: 400 (validación), 401 (API key), 404 (no encontrado), 409 (regla de negocio), 415 (media type). Ejemplo:
{
"type": "about:blank",
"title": "Regla de negocio violada",
"status": 409,
"detail": "No se puede renovar una poliza cancelada (id 2)",
"instance": "/polizas/2/renovar",
"timestamp": "2026-09-17T09:15:00-05:00"
}- Swagger UI: http://localhost:8080/swagger-ui.html
- OpenAPI JSON: http://localhost:8080/v3/api-docs
- Consola H2: http://localhost:8080/h2-console
- JDBC URL:
jdbc:h2:mem:polizasdb - Usuario:
sa— Contraseña: (vacía)
- JDBC URL:
En Swagger, usa el botón Authorize o agrega el header
x-api-key: 123456para probar los endpoints protegidos.
| # | Método | Ruta | Descripción |
|---|---|---|---|
| 1 | GET |
/polizas?tipo={tipo}&estado={estado} |
Lista pólizas. tipo y estado son opcionales. |
| 2 | GET |
/polizas/{id}/riesgos |
Lista los riesgos de una póliza. |
| 3 | POST |
/polizas/{id}/renovar |
Renueva la póliza (canon y prima +IPC). Estado → RENOVADA. |
| 4 | POST |
/polizas/{id}/cancelar |
Cancela la póliza y, en cascada, sus riesgos. |
| 5 | POST |
/polizas/{id}/riesgos |
Agrega un riesgo. Solo si tipo = COLECTIVA. |
| 6 | POST |
/riesgos/{id}/cancelar |
Cancela un riesgo específico. |
| — | POST |
/core-mock/evento |
Mock del CORE: registra el evento en logs. |
Valores válidos:
tipo:INDIVIDUAL,COLECTIVAestado:VIGENTE,RENOVADA,CANCELADA
- Una póliza individual solo puede tener 1 riesgo (se crea con él; el endpoint de agregar riesgo la rechaza).
- No se puede renovar una póliza cancelada.
- La cancelación de una póliza cancela todos sus riesgos (cascada).
- Agregar riesgo exige validación del tipo de póliza (solo Colectiva).
- La prima =
canon mensual × meses de vigencia. - Al renovar:
nuevo canon = canon × (1 + IPC), se recalcula la prima y la vigencia se desplaza el mismo período. Si no se envíaipc, se usa el configurado (app.negocio.ipc-default = 0.062). - Toda acción que modifica estado (renovar, cancelar póliza/riesgo, agregar riesgo) consume el servicio agnóstico de edición (capa media WebLogic → CORE), dejando trazabilidad en logs.
En Windows PowerShell puede usar
curl.exeen lugar decurl.
Listar todas las pólizas:
curl -H "x-api-key: 123456" http://localhost:8080/polizasListar solo colectivas vigentes:
curl -H "x-api-key: 123456" "http://localhost:8080/polizas?tipo=COLECTIVA&estado=VIGENTE"Riesgos de una póliza:
curl -H "x-api-key: 123456" http://localhost:8080/polizas/2/riesgosRenovar con IPC explícito (10%):
curl -X POST -H "x-api-key: 123456" -H "Content-Type: application/json" \
-d "{\"ipc\":0.10}" http://localhost:8080/polizas/2/renovarRenovar con IPC por defecto (body vacío):
curl -X POST -H "x-api-key: 123456" http://localhost:8080/polizas/2/renovarAgregar riesgo a una póliza colectiva:
curl -X POST -H "x-api-key: 123456" -H "Content-Type: application/json" \
-d "{\"descripcion\":\"Local 3\",\"direccionInmueble\":\"Cra 7 #45-14\",\"valorAsegurado\":320000000}" \
http://localhost:8080/polizas/2/riesgosCancelar una póliza:
curl -X POST -H "x-api-key: 123456" http://localhost:8080/polizas/2/cancelarCancelar un riesgo:
curl -X POST -H "x-api-key: 123456" http://localhost:8080/riesgos/3/cancelarMock del CORE:
curl -X POST -H "x-api-key: 123456" -H "Content-Type: application/json" \
-d "{\"evento\":\"ACTUALIZACION\",\"polizaId\":555}" \
http://localhost:8080/core-mock/evento# Windows
mvnw.cmd test
# Linux / macOS
./mvnw testIncluye:
- Pruebas unitarias (
PolizaServiceTest): reglas de negocio (renovación con IPC, no renovar canceladas, cancelación en cascada, validación de tipo al agregar riesgo). - Pruebas de integración (
PolizaApiIntegrationTest): seguridad por API key, listado, filtros, renovación y el mock del CORE vía MockMvc.
poliza-api/
├── pom.xml
├── mvnw, mvnw.cmd, .mvn/ # Maven Wrapper
├── src/main/java/com/segurosbolivar/polizas/
│ ├── PolizaApiApplication.java
│ ├── config/ # Seguridad (ApiKeyFilter), propiedades, seed de datos
│ ├── controller/ # Controllers REST + manejo global de errores
│ ├── core/ # CoreMockService + ServicioEdicionAgnostico (capa media/CORE)
│ ├── domain/ # Entidades (Poliza, Riesgo) y enums
│ ├── dto/ # Records de request/response
│ ├── exception/ # Excepciones de negocio
│ ├── mapper/ # Conversión entidad → DTO
│ ├── repository/ # Spring Data JPA
│ └── service/ # Casos de uso y reglas de negocio
├── src/main/resources/
│ └── application.yml
└── src/test/java/... # Pruebas unitarias e integración
Arquitectura por capas: controller → service → repository, con un modelo de dominio rico (la lógica de estado vive en las entidades Poliza/Riesgo) y DTOs desacoplando la API del modelo persistente.
src/main/resources/application.yml:
| Propiedad | Valor por defecto | Descripción |
|---|---|---|
server.port |
8080 |
Puerto HTTP. |
app.security.header-name |
x-api-key |
Nombre del header de API key. |
app.security.api-key |
123456 |
Valor esperado de la API key. |
app.negocio.ipc-default |
0.062 |
IPC aplicado en renovación cuando no se envía uno. |