Plataforma experiencial de motorsport en resort · API REST y motor de negocio
- Visión general
- Stack tecnológico
- Arquitectura
- Features
- Quick Start
- Variables de entorno
- Documentación API
- Estructura del proyecto
- Modelo de datos
- Seguridad y autorización
- Despliegue
- Testing
- Versionado
- Convenciones de Git
- Autor
Drive Arena Backend es la API REST y el motor de reglas de negocio del resort experiencial Drive Arena. Gestiona el ciclo completo de una sesión: desde la venta de pases en taquilla y la asignación de turnos, hasta el registro de tiempos en circuito, la emisión automática de recompensas y el control operativo de mantenimientos.
Construida sobre **Spring Boot 4 con arquitectura package-by-feature**, expone endpoints autenticados mediante JWT, persiste sobre MySQL 8 y delega el almacenamiento de imágenes a Cloudinary.
| Capa | Tecnología | Versión |
|---|---|---|
| Lenguaje | Java | 25 |
| Framework | Spring Boot | 4.0.x |
| Seguridad | Spring Security + JWT (jjwt) | 0.12.6 |
| Persistencia | Spring Data JPA + Hibernate | 7.x |
| Base de datos | MySQL | 8.0 |
| Documentación | springdoc-openapi (Swagger UI) | 2.x |
| Build | Maven Wrapper | 3.9+ |
| Cloud Storage | Cloudinary SDK | — |
| Spring Boot Starter Mail | — | |
| Productividad | Lombok | — |
| Observabilidad | Spring Boot Actuator | — |
A partir de la versión v1.4.0 el proyecto migró desde una estructura por capas (controllers/, services/, repositories/) hacia una organización por feature donde cada dominio del negocio agrupa todas sus piezas:
com.driveArena.backend/
├── atraccion/ # CRUD + lógica de atracciones del parque
├── cliente/ # Gestión de clientes y búsqueda paginada
├── circuito/ # Circuitos y registro de tiempos
├── compra/ # Ventas, taquilla y entradas
├── dashboard/ # Métricas agregadas y KPIs
├── empleado/ # Empleados y turnos
├── hotel/ # Lodges/hoteles del resort
├── mantenimiento/ # Operativa técnica multi-técnico
├── pase/ # PaseGratuito (gamificación)
├── shared/ # Excepciones, GlobalExceptionHandler, utilidades
├── tarifa/ # Tarifas y políticas de precio
├── turno/ # Turnos de empleados
└── usuarioSistema/ # Usuarios con rol (ADMIN/TAQUILLA/TÉCNICO)
Cada feature internamente sigue el patrón Controller → Service → Repository con DTOs específicos (Request / Response), un Mapper manual basado en @Component, y una entidad JPA enriquecida con Lombok.
HTTP Request
│
▼
┌─────────────┐
│ Controller │ ← @RestController · valida @Valid · gobierna HTTP semantics
└─────┬───────┘
│
▼
┌─────────────┐
│ Service │ ← @Service · lógica de negocio · @Transactional · orquesta agregados
└─────┬───────┘
│
▼
┌─────────────┐
│ Repository │ ← @Repository extends JpaRepository · queries derivadas y @Query
└─────┬───────┘
│
▼
MySQL 8
Excepciones de negocio (ConflictException, ForbiddenOperationException, MailDeliveryException, etc.) se capturan en un GlobalExceptionHandler centralizado que devuelve ProblemDetail (RFC 7807) consistente al cliente.
- CRUDs completos sobre Atracción, Tarifa, Cliente, Empleado, Compra+Entrada, Turno, Mantenimiento y UsuarioSistema.
- Paginación server-side con filtros y búsqueda en clientes, ventas y usuarios (
Pageable+ Spring Data). - Mantenimiento multi-técnico vía tabla intermedia
mantenimiento_tecnicos, con asignación dinámica y endpoints PATCH para cambio de estado. - Dashboard con métricas agregadas: ingresos mensuales, top lodges, ventas por rango de edad, mantenimientos pendientes.
PaseGratuitoautoemitido al detectar podio o récord en un circuito.TiempoCircuitocon modelo híbrido (FK Cliente opcional +nombrePilotosiempre obligatorio) para registrar tiempos tanto de clientes registrados como de visitantes ocasionales.CROSS_PROMOhardcodeado en config, mapeando circuito de origen a recompensa cruzada.caducidadcalculada dinámicamente desde la últimaCompraactiva, con fallback a 24 h.- Autoemisión envuelta en try/catch: el fallo en emitir un pase nunca interrumpe el registro de tiempo.
EmailServicecon plantillas (reserva-confirmada,ticket-compra) enviadas tras eventos clave.MailDeliveryExceptionpropaga errores SMTP sin romper la operación principal.
- Autenticación JWT con
BCrypt(10 rounds) para passwords. - Cloudinary para almacenamiento de imágenes (perfiles, atracciones, lodges).
- Swagger UI auto-generado con OpenAPI 3.1.
- CORS configurado en
SecurityFilterChain(no enWebMvcConfigurer) tal como exige Spring Boot 4. - Soft-delete protection: un usuario ADMIN no puede borrarse a sí mismo.
- Java 25 (JDK)
- MySQL 8.0 corriendo en local o accesible vía red
- Maven Wrapper incluido en el repo (no requiere Maven instalado)
# 1. Clonar
git clone https://github.com/BryanStrk/drive-arena-backend.git
cd drive-arena-backend
# 2. Crear base de datos
mysql -u root -p -e "CREATE DATABASE drive_arena CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
# 3. Configurar variables (ver siguiente sección)
cp .env.example .env
# edita .env con tus credenciales
# 4. Compilar
./mvnw clean compile
# 5. Arrancar
./mvnw spring-boot:runLa API quedará disponible en http://localhost:8080.
Swagger UI: http://localhost:8080/swagger-ui.html
Las credenciales nunca deben estar hardcodeadas ni en git. El proyecto usa el patrón de IntelliJ Run Configurations con variables separadas por ;:
# Base de datos
DB_URL=jdbc:mysql://localhost:3306/drive_arena
DB_USERNAME=tu_usuario
DB_PASSWORD=tu_password
# JWT
JWT_SECRET=clave_secreta_minimo_256_bits_codificada_en_base64
JWT_EXPIRATION_MS=86400000
# Cloudinary
CLOUDINARY_CLOUD_NAME=tu_cloud
CLOUDINARY_API_KEY=tu_key
CLOUDINARY_API_SECRET=tu_secret
# Email SMTP
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=tu_email@gmail.com
MAIL_PASSWORD=tu_app_password
# CORS
CORS_ALLOWED_ORIGINS=http://localhost:5173,https://drive-arena.vercel.appapplication.properties está incluido en .gitignore. El template público es application.properties.example.
Tras arrancar el backend, la documentación interactiva está disponible en:
- Swagger UI:
http://localhost:8080/swagger-ui.html - OpenAPI JSON:
http://localhost:8080/v3/api-docs
| Recurso | Base path | Roles |
|---|---|---|
| Autenticación | /api/auth |
público |
| Usuarios sistema | /api/usuarios |
ADMIN |
| Clientes | /api/clientes |
ADMIN, TAQUILLA |
| Compras (ventas) | /api/compras |
ADMIN, TAQUILLA |
| Atracciones | /api/atracciones |
ADMIN |
| Lodges | /api/hoteles |
ADMIN |
| Circuitos | /api/circuitos |
ADMIN, TÉCNICO |
| Tiempos de circuito | /api/tiempos-circuito |
ADMIN, TÉCNICO |
| Pases gratuitos | /api/pases |
ADMIN |
| Mantenimientos | /api/mantenimientos |
ADMIN, TÉCNICO |
| Dashboard | /api/dashboard |
ADMIN |
Nota: la autorización por rol se aplica vía
@PreAuthorize("hasRole('XXX')")a nivel de método.
drive-arena-backend/
├── src/
│ ├── main/
│ │ ├── java/com/driveArena/backend/
│ │ │ ├── atraccion/
│ │ │ ├── auth/ ← JWT, login, AuthController
│ │ │ ├── cliente/
│ │ │ ├── circuito/
│ │ │ ├── compra/
│ │ │ ├── config/ ← SecurityConfig, CorsConfig, OpenApiConfig
│ │ │ ├── dashboard/
│ │ │ ├── empleado/
│ │ │ ├── hotel/
│ │ │ ├── mantenimiento/
│ │ │ ├── pase/
│ │ │ ├── shared/ ← exceptions, GlobalExceptionHandler, utils
│ │ │ ├── tarifa/
│ │ │ ├── turno/
│ │ │ ├── usuarioSistema/
│ │ │ └── DriveArenaBackendApplication.java
│ │ └── resources/
│ │ ├── templates/ ← plantillas email (Thymeleaf)
│ │ │ ├── reserva-confirmada.html
│ │ │ └── ticket-compra.html
│ │ ├── application.properties (gitignored)
│ │ └── application.properties.example
│ └── test/
│ └── java/com/driveArena/backend/ ← estructura preparada, tests pendientes
├── AUDIT.md ← auditoría arquitectónica del refactor v1.4.0
├── pom.xml
├── mvnw / mvnw.cmd
└── README.md
usuario_sistema ──┐
│ (auditoría)
▼
cliente ─── compra ─── entrada ─── atraccion
│ │
│ └─── tarifa
│
└──── hotel (opcional, lodges)
│
└── zona, esVip
circuito ─── tiempo_circuito ─── cliente (opcional)
│
└─── pase_gratuito (autoemitido)
mantenimiento ─── mantenimiento_tecnicos ─── usuario_sistema (rol TÉCNICO)
│
└── atraccion / circuito (afectado)
empleado ─── turno
El proyecto usa ddl-auto=validate en producción. Cambios de schema se aplican mediante migraciones SQL manuales versionadas documentadas en commits independientes (chore(db): ALTER TABLE ...).
- Endpoint
/api/auth/loginrecibeusername+password, valida contraBCryptPasswordEncoder, y devuelve un JWT firmado con HS256. - El JWT se incluye en cada petición autenticada vía header
Authorization: Bearer <token>. JwtAuthenticationFilter(extendsOncePerRequestFilter) intercepta cada request, valida el token y popula elSecurityContext.
- Roles soportados:
ADMIN,TAQUILLA,TÉCNICO. - Cada endpoint protegido usa
@PreAuthorize("hasRole('XXX')")ohasAnyRole(...). - Operaciones sensibles (eliminar usuario, cambiar rol) incluyen soft-delete protection y validación contra el
principalactual.
Configurado dentro del SecurityFilterChain (no como WebMvcConfigurer, ya que Spring Boot 4 lo requiere así):
http.cors(cors -> cors.configurationSource(corsConfigurationSource()));- VPS: IONOS Ubuntu 24.04 — 2 vCPU / 2 GB RAM.
- Frente: Nginx como reverse proxy + TLS (Let's Encrypt).
- Proceso: unidad
systemdcon auto-restart. - Build:
./mvnw clean package -DskipTests→ JAR ejecutable.
location /api/ {
proxy_pass http://localhost:8080/; # trailing slash importante: strip del prefijo
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}[Service]
EnvironmentFile=/etc/drive-arena/env
ExecStart=/usr/bin/java -jar /opt/drive-arena/backend.jar
Restart=always
RestartSec=5El proyecto incluye las dependencias de test ya configuradas en pom.xml:
spring-boot-starter-test(JUnit 5, Mockito, AssertJ)spring-security-testtestcontainers-mysql(para tests de integración)rest-assured
La estructura de carpetas está preparada en src/test/java/, pero la cobertura de tests automatizados es parte de la siguiente iteración tras la entrega del TFG. La validación actual se ha hecho mediante Postman y QA manual end-to-end.
| Tag | Hito |
|---|---|
v1.0.0 |
Primera entrega funcional con CRUDs base |
v1.2.0 |
Sistema de autenticación JWT + Spring Security |
v1.3.0 |
NIVEL B de gamificación (PaseGratuito + TiempoCircuito + CROSS_PROMO) |
v1.4.0 |
Refactor arquitectónico: package-by-feature |
v2.0.0 |
Port de roles (TÉCNICO), multi-técnico en mantenimientos, dashboard, paginación |
El proyecto sigue Conventional Commits y GitFlow simplificado:
| Tipo | Uso |
|---|---|
feat |
Nueva funcionalidad |
fix |
Corrección de bug |
refactor |
Cambio sin alterar comportamiento externo |
chore |
Mantenimiento, dependencias, config |
docs |
Solo documentación |
test |
Solo tests |
git checkout -b feature/nombre-acotado
# trabajo + commits atómicos
git checkout main
git merge feature/nombre-acotado --no-ff # historia explícita
git tag -a vX.Y.Z -m "..."
git push origin main --tagsBryan Alejandro Paico Albines — Desarrollo de Aplicaciones Web (DAW) · 2026
- GitHub: @BryanStrk
- Proyecto frontend: drive-arena-frontend
Proyecto académico desarrollado como Trabajo academico de Desarrollo de Aplicaciones Web. Uso no comercial.
Drive Arena · Conduce · Compite · Domina