¡Hola y bienvenido! Este desarrollo se trata de un ejercicio propuesto en la comunidad de Skool DeHaroHub por Nacho De Haro (el creador de la comunidad) en este repositorio. En el propio enunciado pone que se debe realizar una PR en ese mismo repositorio para que toda la gente de la comunidad pueda revisarlo, aprender de él y aportar su granito de arena. Pero como la comunidad esta inactiva y actualmente cerrada y su creador esta a otras cosas he optado por publicar mi desarrollo en este repositorio.
- Descripción
- Objetivo
- Características Funcionales
- Requerimientos Técnicos
- Arquitectura del Proyecto
- Tecnologías Utilizadas
- Instalación y Configuración
- Documentación de la API
- Pruebas
- Desafíos Adicionales y Mejoras Futuras
- Contribuciones
- Licencia
Esta API RESTful permite la gestión completa de un hotel, incluyendo la administración de clientes, habitaciones, reservas, pagos y administradores. Se ha desarrollado utilizando Java con Spring Boot, aplicando los principios de una arquitectura limpia para separar la lógica de negocio del acceso a datos y la presentación.
El objetivo de este proyecto es crear una API para la gestión de un hotel que permita:
- Manejar reservas, habitaciones, pagos, clientes y administradores.
- Implementar la lógica de negocio, estructuras de datos y endpoints necesarios.
- Aprender las habilidades en la creación de APIs RESTful, mejorar el manejo de bases de datos y aplicación de buenas prácticas en arquitectura de software.
- CRUD: Crear, leer, actualizar y eliminar clientes.
- Campos obligatorios: ID, Nombre, Apellidos, Correo electrónico, Número de teléfono.
- CRUD: Crear, leer, actualizar y eliminar habitaciones.
- Campos obligatorios: ID, Número de habitación, Tipo de habitación (simple, doble, suite), Precio por noche, Estado (disponible, ocupada, en mantenimiento).
- CRUD: Crear, leer, actualizar y cancelar reservas.
- Campos obligatorios: ID, ID del cliente, ID de la habitación, Fecha de inicio, Fecha de fin, Estado (pendiente, confirmada, cancelada).
- Registro de pagos: Asociados a una reserva.
- Campos obligatorios: ID, ID de la reserva, Monto, Fecha de pago, Método de pago (tarjeta, efectivo, transferencia).
- CRUD: Crear, leer, actualizar y eliminar administradores.
- Campos obligatorios: ID, Nombre, Correo electrónico, Contraseña (hasheada), Rol (admin, superadmin).
- Implementación de autenticación JWT para administradores y clientes.
- Solo los administradores pueden crear, actualizar o eliminar habitaciones y reservas.
- Los clientes pueden crear y ver sus reservas, pero no modificarlas una vez confirmadas.
- Lenguaje y Framework: Java con Spring Boot.
- Base de Datos: MariaDB ejecutado en un contenedor Docker, con un script sql para crear y poblar las tablas de la base de datos.
- ORM: No he usado ningún ORM en su lugar he usado JDBC de manera directa ya que es más flexible.
- Contenedores: Docker para MariaDB y Adminer.
- Documentación: Swagger/OpenAPI para la documentación de la API.
- Pruebas: Pruebas unitarias y de integración con JUnit5, Mockito y Testcontainers.
erDiagram
User {
INT id PK
VARCHAR email
VARCHAR password
ENUM role "CLIENT, ADMIN, SUPERADMIN"
}
Client {
INT id PK
INT user_id FK
VARCHAR first_name
VARCHAR last_name
VARCHAR phone
}
Administrator {
INT id PK
INT user_id FK
VARCHAR name
}
Room {
INT id PK
INT room_number
ENUM room_type "SINGLE, DOUBLE, SUITE"
DECIMAL price_per_night
ENUM status "AVAILABLE, OCCUPIED, MAINTENANCE"
}
Reservation {
INT id PK
INT client_id FK
INT room_id FK
DECIMAL total_price
DATE start_date
DATE end_date
ENUM status "PENDING, CONFIRMED, CANCELED"
}
Payment {
INT id PK
INT reservation_id FK
DECIMAL amount
DATE payment_date
ENUM payment_method "CARD, CASH, TRANSFER"
}
Client ||--o{ Reservation : has
Room ||--o{ Reservation : "is booked in"
Reservation ||--o{ Payment : has
User ||--|| Client : "is a"
User ||--|| Administrator : "is a"
El proyecto está organizado siguiendo una arquitectura limpia:
-
Adaptadores:
- Controladores REST para recibir peticiones y enviar respuestas.
- DTOs para el mapeo de datos entre la API y la lógica de negocio.
- Adaptador de seguridad (JWT, filtros, etc.).
-
Aplicación:
- Casos de Uso que orquestan la lógica de negocio.
-
Dominio:
- Entidades de dominio (Modelos) y lógica de negocio.
- Interfaces de repositorios (Puertos).
-
Infraestructura:
- Implementaciones de repositorios (con JDBC).
- Configuración de acceso a la base de datos (MariaDB en Docker).
graph TD;
subgraph CLIENTE
Client["💻 Cliente (Front-end)"]
end
subgraph ADAPTADORES
Controller["🌐 @RestController Controladores Web"]
DTOs["🔌 DTOs
(Request/Response)"]
Security["🔐 Filtros y JWT
(Adaptador de Seguridad)"]
end
subgraph APLICACIÓN
UseCase["⚙️ Casos de Uso
(Lógica de Negocio)"]
end
subgraph DOMINIO
Entities["🗃️ Entidades de Dominio (Modelos)"]
Ports["📁 Interfaces de Repositorios (Puertos)"]
end
subgraph INFRAESTRUCTURA
RepoImpl["📂 @Repository Implementación de Repositorios con JDBC"]
DB["🗄️🐋 Base de Datos (MariaDB)"]
end
Client -- "HTTP Request" --> Controller
Controller -- "DTO Mapping" --> UseCase
UseCase -- "Invoca reglas de negocio" --> Entities
UseCase -- "Solicita persistencia" --> Ports
Ports -- "Implementado por" --> RepoImpl
RepoImpl -- "Acceso a datos" --> DB
Controller -- "HTTP Response" --> Client
%% Opcional: Integración de seguridad
Controller -- "Autenticación/Autorización" --> Security
graph TD;
subgraph CLIENTE
Cliente["💻 Cliente (Front-end)"]
end
subgraph FILTROS
JwtFilter["🔍 JwtAuthenticationFilter{}🔸 Verifica si el JWT es null"]
end
subgraph AUTENTICACION
AuthController["🔐 AuthenticationController{}"]
AuthService["⚙️ AuthenticationService{}"]
JwtService["🛠️ JwtService{}
🔸Genera JWT Token"]
end
subgraph REPOSITORIO
UserRepo["📂UserRepository{} 🔸Guarda/Obtiene UserDetail"]
User["🧑💼 User{}
🔸Implementa UserDetails"]
end
subgraph CONFIGURACION
Config["⚙️ ApplicationConfig 🔸Authentication Manager 🔸Providers 🔸PasswordEncoders"]
end
subgraph BASE DE DATOS
DB[("🗄️🐋 Base de Datos (MariaDB)")]
end
%% Flujo del proceso de autenticación
Cliente -- "HTTP Request" --> JwtFilter
JwtFilter --> AuthController
AuthController --> AuthService
AuthService --> UserRepo
UserRepo --> User
User --> DB
AuthService --> JwtService
JwtService --> AuthController
AuthController -- "HTTP Response (JWT Token)" --> Cliente
%% Conexiones de configuración
Config -.-> AuthService
graph TD;
subgraph CLIENTE
Cliente["💻 Cliente (Front-end)"]
end
subgraph FILTROS
JwtFilter["🔍 JwtAuthenticationFilter{}🔸 Verifica el JWT"]
end
subgraph SERVICIOS
JwtService["🛠️ JwtService{}
🔸Extrae el usuario del JWT
🔸Verifica el token"]
UserDetailsService["⚙️ UserDetailsService{} 🔸 loadUserByUsername()"]
end
subgraph REPOSITORIO
User["🧑💼 User{}
🔸Implementa UserDetails"]
DB[("🗄️🐋 Base de Datos")]
end
subgraph SecurityContext
Authentication["🔐Authentication
Principle | Credentials | Authorities"]
end
subgraph CONTROLADOR
Controller["⚡ Controller{}"]
end
%% Flujo del proceso de validación JWT
Cliente -- "HTTP Request (Token)" --> JwtFilter
JwtFilter --> JwtService
JwtService --> UserDetailsService
UserDetailsService --> User
User --> DB
JwtFilter --> Authentication
Authentication --> Controller
Controller -- "✅ HTTP Response (JSON)" --> Cliente
%% Manejo de errores (403)
JwtFilter -- "❌ HTTP 403: Token inválido" --> Cliente
JwtFilter -- "❌ HTTP 403: Falta token o usuario no existe" --> Cliente
- Java 21+
- Spring Boot
- Spring Security con JWT
- JDBC
- Docker
- MariaDB
- Adminer
- Swagger/OpenAPI
- Gradle
- JUnit5
- Mockito
- Testcontainers
- JDK 21 o superior instalado.
- Docker y Docker Compose instalados.
- Git instalado.
El proyecto incluye un archivo docker-compose.yml
para levantar la base de datos y Adminer. Un ejemplo de docker-compose.yml
podría ser:
version: '3.8'
services:
mariadb:
image: mariadb:10.5
container_name: hotel-mariadb
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: hotel_db
MYSQL_USER: hoteluser
MYSQL_PASSWORD: hotelpassword
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
adminer:
image: adminer
container_name: hotel-adminer
ports:
- "8080:8080"
volumes:
db_data:
Para iniciar los contenedores, ejecuta en la raíz del proyecto:
docker compose up -d
-
Clona el repositorio:
git clone https://github.com/asobrados03/HotelManagementAPI.git cd HotelManagementAPI
-
Compila y ejecuta la aplicación:
./gradlew build ./gradlew bootRun
-
La API estará disponible en
http://localhost:8080
.
La documentación interactiva se genera automáticamente con Swagger. Una vez iniciada la aplicación, puedes acceder a ella en:
http://localhost:8080/swagger-ui.html
ohttp://localhost:8080/swagger-ui/index.html
Se han implementado pruebas unitarias y de integración para asegurar el correcto funcionamiento de la API. Para ejecutarlas:
./gradlew test
Important
Para las pruebas de integración debe estar corriendo Docker en la máquina.
- Optimización de Consultas: Mejorar el rendimiento en operaciones complejas sobre reservas y habitaciones.
- Gestión de Estados: Refinar la lógica de transición de estados en reservas.
- Manejo de Concurrencia: Evitar sobre-reservas mediante bloqueos o estrategias de concurrencia.
- Escalabilidad: Adaptar la API para despliegues en entornos distribuidos o en la nube.
- Seguridad: Mejorar la protección contra ataques (SQL Injection, XSS, etc.) y optimizar el manejo de autenticación y autorización.
¡Las contribuciones son bienvenidas! Si deseas colaborar en el proyecto, sigue estos pasos:
- Realiza un fork del repositorio.
- Crea una rama para tu funcionalidad:
git checkout -b feature/nueva-funcionalidad
. - Realiza tus cambios y haz commit.
- Envía un pull request describiendo los cambios realizados.
Este proyecto se distribuye bajo la Licencia MIT.