API Backend para la aplicación de pedido a domicilio MDK Burguer construida con NestJS. Esta API proporciona endpoints para gestionar:
- Autenticación y autorización de usuarios
- Categorías y productos del menú
- Procesamiento y gestión de pedidos
- Funcionalidades específicas para empleados
-
Autenticación robusta:
- JWT (JSON Web Tokens) para seguridad
- Sistema de roles (público y empleado)
- Tokens de acceso y refresco
- Validación de tokens en tiempo real
-
Gestión de usuarios:
- Registro y autenticación de usuarios
- Perfil de usuario personalizable
- Gestión de contraseñas segura
- Sistema de confirmación por correo
-
Sistema de pedidos:
- Creación y gestión de pedidos en tiempo real
- Sistema SSE (Server-Sent Events) para actualizaciones
- Historial de pedidos por usuario
- Estado de pedidos en tiempo real
-
Gestión de productos:
- Catálogo de productos dinámico
- Sistema de categorías
- Gestión de ingredientes
- Subida de imágenes de productos
-
Integraciones:
- Base de datos PostgreSQL en AWS Supabase
- Servicio de correo electrónico
- Almacenamiento de imágenes en Imgur
- API RESTful y documentada
-
Documentación Swagger:
- Documentación interactiva de la API disponible en
/api
- Endpoints agrupados por funcionalidad (usuarios, productos, pedidos, etc.)
- Documentación interactiva de la API disponible en
-
Seguridad:
- Validación de datos
- Protección contra inyecciones SQL
- Rate limiting
- CORS configurado
- Descripción: Obtener usuario por ID
- Requiere autenticación: Sí
- Parámetros:
id
(path): ID del usuario
- Respuesta:
{ "id": number, "email": string, "first_name": string, "last_name": string, "phone": string, "points": number, "created_at": string, "employee": boolean, "activated": boolean }
- Descripción: Login de usuario
- Requiere autenticación: No
- Cuerpo de entrada:
{ "email": string, "password": string }
- Respuesta:
{ "success": boolean, "token": string | null, "message": string | null }
- Descripción: Crear nuevo usuario
- Requiere autenticación: No
- Cuerpo de entrada:
{ "email": string, "password": string, "first_name": string, "last_name": string, "phone": string }
- Respuesta:
{ "lastInsertId": number, "affectedRows": number, "error": string | null }
- Descripción: Cambiar contraseña
- Requiere autenticación: Sí
- Cuerpo de entrada:
{ "currentPassword": string, "newPassword": string }
- Respuesta: Mensaje de éxito
- Descripción: Actualizar información del usuario
- Requiere autenticación: Sí
- Cuerpo de entrada:
{ "first_name": string, "last_name": string, "phone": string }
- Respuesta: Mensaje de éxito
- Descripción: Eliminar usuario
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Parámetros:
id
(path): ID del usuario
- Respuesta: Mensaje de éxito
- Descripción: Obtener todos los pedidos
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Respuesta:
[ { "id": number, "id_user": number, "delivery": boolean, "address": string, "date_ordered": string, "date_aprox_recollect": string, "payment_method": "cash" | "card" | "paypal" | "other", "delivered": boolean, "state": "pending" | "in_progress" | "completed" | "in_kitchen" | "in_delivery" | "delivered", "orderProducts": [ { "id": number, "amount": number, "product": { "id": number, "name": string, "price": number } } ] } ]
- Descripción: Endpoint SSE para pedidos en tiempo real
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Respuesta: Stream de eventos
- Descripción: Obtener pedidos del usuario
- Requiere autenticación: Sí
- Parámetros:
userId
(path): ID del usuario
- Respuesta: Lista de pedidos del usuario
- Descripción: Endpoint SSE para pedidos del usuario
- Requiere autenticación: Sí
- Parámetros:
userId
(path): ID del usuario
- Respuesta: Stream de eventos
- Descripción: Crear nuevo pedido
- Requiere autenticación: Sí
- Cuerpo de entrada:
{ "id_user": number, "delivery": boolean, "address": string, "date_aprox_recollect": string, "payment_method": "cash" | "card" | "paypal" | "other", "orderProducts": [ { "product": { "id": number }, "amount": number } ] }
- Respuesta:
{ "lastInsertId": number, "affectedRows": number }
- Descripción: Actualizar pedido
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Cuerpo de entrada:
{ "id": number, "state": "pending" | "in_progress" | "completed" | "in_kitchen" | "in_delivery" | "delivered" }
- Respuesta: Pedido actualizado
- Descripción: Eliminar pedido
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Parámetros:
id
(path): ID del pedido
- Respuesta: Mensaje de éxito
- Descripción: Obtener todos los productos
- Requiere autenticación: No
- Respuesta: Lista de productos
- Descripción: Crear nuevo producto
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Cuerpo de entrada:
{ "name": string, "description": string, "price": number, "category": { "id": number }, "ingredientsToAdd": [ { "id": number } ] }
- Respuesta: Producto creado
- Descripción: Actualizar producto
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Cuerpo de entrada:
{ "id": number, "name": string, "description": string, "price": number, "category": { "id": number } }
- Respuesta: Producto actualizado
- Descripción: Eliminar producto
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Parámetros:
id
(path): ID del producto
- Respuesta: Mensaje de éxito
- Descripción: Subir imagen del producto
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Parámetros:
id
(path): ID del producto
- Cuerpo de entrada: Archivo de imagen
- Respuesta: URL de la imagen
- Descripción: Servir imagen del producto
- Requiere autenticación: No
- Parámetros:
filename
(path): Nombre del archivo
- Respuesta: Redirección a la imagen
- Descripción: Obtener todas las categorías
- Requiere autenticación: No
- Respuesta: Lista de categorías
- Descripción: Crear nueva categoría
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Cuerpo de entrada:
{ "name": string, "description": string }
- Respuesta: Categoría creada
- Descripción: Actualizar categoría
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Cuerpo de entrada:
{ "id": number, "name": string, "description": string }
- Respuesta: Categoría actualizada
- Descripción: Eliminar categoría
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Parámetros:
id
(path): ID de la categoría
- Respuesta: Mensaje de éxito
- Descripción: Obtener todos los ingredientes
- Requiere autenticación: Sí
- Respuesta: Lista de ingredientes
- Descripción: Crear nuevo ingrediente
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Cuerpo de entrada:
{ "name": string, "description": string }
- Respuesta: Ingrediente creado
- Descripción: Actualizar ingrediente
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Cuerpo de entrada:
{ "id": number, "name": string, "description": string }
- Respuesta: Ingrediente actualizado
- Descripción: Eliminar ingrediente
- Requiere autenticación: Sí
- Requiere empleado: Sí
- Parámetros:
id
(path): ID del ingrediente
- Respuesta: Mensaje de éxito
- Todos los endpoints excepto los marcados como
público
requieren autenticación - Endpoints exclusivos de empleados requieren autenticación y privilegios de empleado
- La autenticación se maneja mediante JWT tokens
La API está desplegada en Render y está accesible en la siguiente URL:
- URL de producción: https://takeaway-backend-879t.onrender.com/
Nota sobre el modo suspensión:
- La API entra en modo suspensión después de 15 minutos sin recibir solicitudes al tener un plan gratuito
- La primera solicitud después del periodo de suspensión puede tardar aproximadamente 1 minuto en responder mientras el servidor se reinicia
La base de datos está alojada en Supabase.
- Node.js 20 o superior
- Docker (para despliegue)
- pnpm (gestor de paquetes recomendado)
La configuración de la aplicación se maneja a través del archivo .env
. Las variables más importantes son:
DB_HOST
: Host de la base de datos en AWS SupabaseDB_PORT
: Puerto de la base de datos (6543 en Supabase)DB_USER
: Usuario de la base de datosDB_PASSWORD
: Contraseña de la base de datosDB_NAME
: Nombre de la base de datosJWT_SECRET
: Clave secreta para JWT necesita ser la misma que la del frontendJWT_EXPIRES_IN
: Tiempo de expiración del token JWTIMGUR_CLIENT_ID
: ID de cliente para subir imágenesIMGUR_CLIENT_SECRET
: Clave secreta de ImgurEMAIL_HOST
: Host del servidor de correoEMAIL_PORT
: Puerto del servidor de correoEMAIL_HOST_USER
: Usuario del servidor de correoEMAIL_HOST_PASSWORD
: Contraseña del servidor de correo
Este proyecto incluye un Dockerfile para facilitar el despliegue. La base de datos está alojada en AWS Supabase, por lo que no es necesario crear un contenedor separado para la base de datos.
Para construir y ejecutar la aplicación:
# Construir la imagen
$ docker build -t takeaway-backend .
# Ejecutar el contenedor
$ docker run -d -p 4000:4000 --name takeaway-backend takeaway-backend
La aplicación estará disponible en http://localhost:4000
.
Para desarrollo local:
# Instalar dependencias
$ pnpm install
# Copiar el archivo .env.example a .env
$ cp .env.example .env
# Iniciar en modo desarrollo
$ pnpm run start:dev
# Iniciar en modo producción
$ pnpm run start:prod
- Docker
- Docker Compose
- Proyecto Backend y Frontend clonados en la misma carpeta
- Crear un archivo docker-compose.yml en la raíz del proyecto es decir fuera de la carpeta takeaway-frontend y fuera de takeaway-backend y poner el siguiente contenido:
services:
backend:
build:
context: ./takeaway-backend # Ruta al directorio donde está el Dockerfile del backend
ports:
- "4000:4000"
env_file:
- ./takeaway-backend/.env
networks:
- app-network
frontend:
build:
context: ./takeaway-frontend # Ruta al directorio donde está el Dockerfile del frontend
ports:
- "3000:3000"
env_file:
- ./takeaway-frontend/.env
depends_on:
- backend
networks:
- app-network
networks:
app-network:
driver: bridge
- Asignar en el archivo .env del frontend la variable NEXT_PUBLIC_API_URL a la url del backend
NEXT_PUBLIC_API_URL="http://backend:4000"
- Construir la imagen:
docker-compose up --build
- Ejecutar el contenedor:
docker-compose up
Este proyecto está bajo licencia. Consulta el archivo LICENSE.md para más detalles.