Servidor backend moderno para una plataforma de e-commerce construido con Express.js, MongoDB y Socket.io. Este proyecto implementa un sistema completo de gestión de productos y carritos de compra con soporte para tiempo real.
- Características
- Estructura del Proyecto
- Arquitectura del Sistema
- Instalación
- Uso
- Endpoints API
- Flujos de Aplicación
- Tecnologías
- Scripts Disponibles
- Autor
✅ Gestión de Productos
- Crear, leer, actualizar y eliminar productos (CRUD)
- Paginación, filtrado y ordenamiento
- Disponibilidad y categorización
✅ Sistema de Carritos
- Crear carritos de compra
- Agregar/eliminar productos
- Actualizar cantidades
- Limpiar carrito
✅ Real-time con WebSockets
- Conexión Socket.io para actualizaciones en tiempo real
- Soporte para múltiples clientes simultáneos
✅ Vistas Dinámicas
- Renderizado con Handlebars
- Interfaz responsiva con Bootstrap
- Múltiples vistas (Home, Productos, Carrito, Real-Time)
✅ Base de Datos
- MongoDB con Mongoose
- Schema validación
- Paginación integrada
Server/
├── app.js # Entrada principal de la aplicación
├── socket.js # Configuración de Socket.io
├── products.json # Datos de productos iniciales
├── package.json # Dependencias y scripts
│
├── config/ # Configuración de la aplicación
│ ├── db/
│ │ └── connect.config.js # Conexión a MongoDB
│ └── models/
│ ├── product.js # Schema de Productos
│ └── cart.js # Schema de Carritos
│
├── controllers/ # Lógica de negocio
│ ├── products.controller.js # Controlador de productos
│ └── carts.controller.js # Controlador de carritos
│
├── routes/ # Definición de rutas
│ ├── products.router.js # Rutas API de productos
│ ├── carts.router.js # Rutas API de carritos
│ ├── home.router.js # Ruta de inicio
│ └── views.router.js # Rutas de vistas renderizadas
│
├── views/ # Plantillas Handlebars
│ ├── home.hbs # Vista de inicio
│ ├── products.hbs # Vista de productos
│ ├── cart.hbs # Vista del carrito
│ ├── realTimeProducts.hbs # Vista de productos en tiempo real
│ └── layouts/
│ └── main.hbs # Layout principal
│
├── public/ # Archivos estáticos
│ ├── css/
│ │ └── styles.css # Estilos personalizados
│ └── img/ # Imágenes del proyecto
│
├── postman/ # Colecciones de Postman
│ ├── Productos.postman_collection.json
│ └── Carritos.postman_collection.json
│
└── README.md # Este archivo
graph TB
subgraph Client["🌐 Cliente"]
Browser["Navegador Web"]
Postman["Postman/API Client"]
end
subgraph Express["🚀 Express Server<br/>port 3000"]
subgraph Middleware["Middlewares"]
Parser["JSON Parser"]
Static["Static Files"]
IO["Socket.io Injector"]
end
subgraph Routing["Rutas"]
API["API Routes"]
Views["View Routes"]
Home["Home Route"]
end
subgraph Controllers["Controladores"]
ProdCtrl["Products Controller"]
CartCtrl["Carts Controller"]
end
subgraph Models["Modelos & Schemas"]
Product["Product Schema"]
Cart["Cart Schema"]
end
end
subgraph Database["💾 MongoDB"]
ProdDB["Colección: products"]
CartDB["Colección: carts"]
end
subgraph RealTime["⚡ WebSockets"]
SocketIO["Socket.io"]
end
subgraph Views["🎨 Vistas Renderizadas"]
Handlebars["Handlebars/HBS"]
Bootstrap["Bootstrap CSS"]
end
Browser -->|HTTP Requests| API
Postman -->|API Calls| API
Browser -->|WebSocket| SocketIO
API --> Middleware
Middleware --> Routing
API --> Controllers
Views --> Controllers
Controllers --> Models
Models --> Database
SocketIO --> Database
Routing --> Views
Views --> Handlebars
Handlebars --> Bootstrap
Bootstrap -->|HTML Response| Browser
graph TB
Client["📱 Capa de Presentación<br/>Cliente"]
Express["🚀 Capa de Aplicación<br/>Express.js"]
Business["⚙️ Capa de Lógica Negocio<br/>Controllers"]
Data["💾 Capa de Datos<br/>Models & MongoDB"]
Client -->|Request/Response| Express
Express -->|Validación| Business
Business -->|CRUD Ops| Data
Data -->|Datos| Business
Business -->|Response| Express
Express -->|HTML/JSON| Client
style Client fill:#e1f5ff
style Express fill:#f3e5f5
style Business fill:#fff3e0
style Data fill:#e8f5e9
- Node.js v16 o superior
- MongoDB local o remoto
- npm o yarn
-
Clonar el repositorio
git clone https://github.com/Emmanu2288/Backend-I.git cd "Backend 1/Server"
-
Instalar dependencias
npm install
-
Configurar la base de datos
- Asegúrate de que MongoDB esté corriendo en
localhost:27017 - Base de datos:
ecommerce - Si deseas cambiar la conexión, edita
config/db/connect.config.js
- Asegúrate de que MongoDB esté corriendo en
-
Ejecutar el servidor
# Desarrollo (con nodemon) npm run dev # Producción npm start
-
Verificar instalación
- Accede a
http://localhost:3000/homeen tu navegador - Deberías ver la página de inicio
- Accede a
Modo Desarrollo (con hot-reload):
npm run devModo Producción:
npm start| Ruta | Método | Descripción |
|---|---|---|
/home |
GET | Página de inicio con productos |
/products |
GET | Listado de productos con paginación |
/carts/:cid |
GET | Vista del carrito específico |
/realtimeproducts |
GET | Vista en tiempo real de productos |
Productos:
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/products |
Obtener todos los productos |
| GET | /api/products/:pid |
Obtener producto por ID |
| POST | /api/products |
Crear nuevo producto |
| PUT | /api/products/:pid |
Actualizar producto |
| DELETE | /api/products/:pid |
Eliminar producto |
Carritos:
| Método | Endpoint | Descripción |
|---|---|---|
| POST | /api/carts |
Crear nuevo carrito |
| GET | /api/carts/:cid |
Obtener carrito con productos |
| POST | /api/carts/:cid/products/:pid |
Agregar producto al carrito |
| PUT | /api/carts/:cid/products/:pid |
Actualizar cantidad de producto |
| DELETE | /api/carts/:cid/products/:pid |
Eliminar producto del carrito |
| PUT | /api/carts/:cid |
Actualizar todos los productos |
| DELETE | /api/carts/:cid |
Vaciar carrito |
Obtiene lista de productos con paginación, filtrado y ordenamiento.
Parámetros de Query:
page(number, default: 1) - Número de páginalimit(number, default: 10) - Productos por páginasort(string: 'asc' | 'desc') - Ordenar por precioquery(string) - Filtrar por categoría o 'available'
Ejemplo:
GET /api/products?page=1&limit=10&sort=asc&query=electronicsRespuesta (200):
{
"status": "success",
"payload": [
{
"_id": "507f1f77bcf86cd799439011",
"name": "Laptop",
"price": 999.99,
"category": "electronics",
"available": true,
"createdAt": "2024-03-19T10:30:00.000Z",
"updatedAt": "2024-03-19T10:30:00.000Z"
}
],
"totalPages": 5,
"page": 1,
"hasPrevPage": false,
"hasNextPage": true,
"prevLink": null,
"nextLink": "/api/products?page=2"
}Obtiene un producto específico por su ID.
Ejemplo:
GET /api/products/507f1f77bcf86cd799439011Respuesta (200):
{
"status": "success",
"payload": {
"_id": "507f1f77bcf86cd799439011",
"name": "Laptop",
"price": 999.99,
"category": "electronics",
"available": true
}
}Crea un nuevo producto.
Body (JSON):
{
"name": "Laptop",
"price": 999.99,
"category": "electronics",
"available": true
}Respuesta (201):
{
"status": "success",
"payload": {
"_id": "507f1f77bcf86cd799439011",
"name": "Laptop",
"price": 999.99,
"category": "electronics",
"available": true,
"createdAt": "2024-03-19T10:30:00.000Z"
}
}Actualiza un producto existente.
Body (JSON):
{
"price": 899.99,
"available": false
}Respuesta (200):
{
"status": "success",
"payload": {
"_id": "507f1f77bcf86cd799439011",
"name": "Laptop",
"price": 899.99,
"category": "electronics",
"available": false
}
}Elimina un producto.
Respuesta (200):
{
"status": "success",
"payload": {
"_id": "507f1f77bcf86cd799439011",
"name": "Laptop",
"price": 999.99
}
}Crea un nuevo carrito vacío.
Respuesta (201):
{
"status": "success",
"payload": {
"_id": "507f1f77bcf86cd799439012",
"products": [],
"__v": 0
}
}Obtiene un carrito con todos los productos poblados.
Ejemplo:
GET /api/carts/507f1f77bcf86cd799439012Respuesta (200):
{
"status": "success",
"payload": {
"_id": "507f1f77bcf86cd799439012",
"products": [
{
"_id": "507f1f77bcf86cd799439013",
"product": {
"_id": "507f1f77bcf86cd799439011",
"name": "Laptop",
"price": 999.99,
"category": "electronics"
},
"quantity": 2
}
]
}
}Agrega un producto al carrito o incrementa su cantidad.
Body (JSON):
{
"quantity": 2
}Respuesta (200):
{
"products": [
{
"_id": "507f1f77bcf86cd799439013",
"product": "507f1f77bcf86cd799439011",
"quantity": 2
}
]
}Actualiza la cantidad de un producto específico en el carrito.
Body (JSON):
{
"quantity": 5
}Respuesta (200):
{
"status": "success",
"payload": {
"_id": "507f1f77bcf86cd799439012",
"products": [
{
"product": "507f1f77bcf86cd799439011",
"quantity": 5
}
]
}
}Elimina un producto específico del carrito.
Respuesta (200):
{
"status": "success",
"payload": {
"_id": "507f1f77bcf86cd799439012",
"products": []
}
}Actualiza todos los productos del carrito.
Body (JSON):
{
"products": [
{
"product": "507f1f77bcf86cd799439011",
"quantity": 3
}
]
}Respuesta (200):
{
"status": "success",
"payload": {
"_id": "507f1f77bcf86cd799439012",
"products": [...]
}
}Vacía completamente el carrito.
Respuesta (200):
{
"status": "success",
"payload": {
"_id": "507f1f77bcf86cd799439012",
"products": []
}
}graph TD
A["🏠 Usuario entra a /home"] --> B["📋 Ve lista de productos"]
B --> C["✅ Selecciona productos"]
C --> D{¿Tiene carrito?}
D -->|No| E["📦 POST /api/carts<br/>Crear nuevo carrito"]
D -->|Sí| F["Usar carrito existente"]
E --> G["Carrito creado"]
G --> H["🛒 GET /api/carts/:cid<br/>Ver carrito vacío"]
F --> H
H --> I["➕ POST /api/carts/:cid/products/:pid<br/>Agregar producto 1"]
I --> J["➕ POST /api/carts/:cid/products/:pid<br/>Agregar producto 2"]
J --> K["✏️ PUT /api/carts/:cid/products/:pid<br/>Cambiar cantidad"]
K --> L["👁️ GET /api/carts/:cid<br/>Ver carrito actualizado"]
L --> M{¿Continuar?}
M -->|Sí| N["❌ DELETE /api/carts/:cid/products/:pid<br/>Eliminar producto"]
N --> L
M -->|No| O["💳 Proceder al pago"]
O --> P["✅ Compra exitosa"]
style A fill:#e1f5ff
style B fill:#e1f5ff
style C fill:#e1f5ff
style P fill:#c8e6c9
graph LR
A["🔑 Admin"] --> B{Acción}
B -->|Crear| C["📝 POST /api/products"]
C --> D["✅ Producto creado"]
B -->|Leer| E["👁️ GET /api/products"]
E --> F["📊 Lista de productos"]
B -->|Actualizar| G["✏️ PUT /api/products/:pid"]
G --> H["✅ Producto actualizado"]
B -->|Eliminar| I["🗑️ DELETE /api/products/:pid"]
I --> J["✅ Producto eliminado"]
F --> K["📊 Visualizar"]
K --> L["🔍 Filtrar/Paginar/Ordenar"]
style D fill:#c8e6c9
style H fill:#c8e6c9
style J fill:#c8e6c9
style F fill:#bbdefb
graph TD
Client["🌐 Cliente"]
Express["Express Router"]
Controller["Products Controller"]
Model["Product Model"]
MongoDB["MongoDB"]
Client -->|GET /api/products?page=1&limit=10| Express
Express -->|Pasa a| Controller
Controller -->|Extrae params:<br/>page, limit, sort, query| Controller
Controller -->|Construye filter<br/>y options| Controller
Controller -->|Product.paginate<br/>filter, options| Model
Model -->|Consulta en<br/>MongoDB| MongoDB
MongoDB -->|Retorna docs<br/>y metadata| Model
Model -->|Retorna resultado| Controller
Controller -->|Respuesta JSON<br/>con status:success| Express
Express -->|Status 200| Client
style Client fill:#e1f5ff
style Express fill:#f3e5f5
style Controller fill:#fff3e0
style Model fill:#f1f8e9
style MongoDB fill:#eceff1
graph TB
Browser["🌐 Navegador"]
WebSocket["⚡ WebSocket"]
SocketIO["Socket.io Server"]
DB["💾 MongoDB"]
Browser -->|Conecta| WebSocket
WebSocket -->|socket on connection| SocketIO
SocketIO -->|Emite 'Nuevo cliente conectado'| SocketIO
Browser -->|Escucha eventos| SocketIO
SocketIO -->|socket on disconnect| SocketIO
SocketIO -->|Emite 'Cliente desconectado'| SocketIO
style Browser fill:#e1f5ff
style WebSocket fill:#f3e5f5
style SocketIO fill:#fff3e0
style DB fill:#e8f5e9
{
_id: ObjectId,
name: String (requerido),
price: Number (requerido),
category: String (requerido),
available: Boolean (default: true),
createdAt: Timestamp,
updatedAt: Timestamp
}Ejemplo:
{
"_id": "507f1f77bcf86cd799439011",
"name": "Laptop Dell",
"price": 1299.99,
"category": "electronics",
"available": true,
"createdAt": "2024-03-19T10:30:00.000Z",
"updatedAt": "2024-03-19T10:30:00.000Z"
}{
_id: ObjectId,
products: [
{
product: ObjectId (referencia a Product),
quantity: Number (default: 1)
}
]
}Ejemplo:
{
"_id": "507f1f77bcf86cd799439012",
"products": [
{
"_id": "507f1f77bcf86cd799439013",
"product": "507f1f77bcf86cd799439011",
"quantity": 2
},
{
"_id": "507f1f77bcf86cd799439014",
"product": "507f1f77bcf86cd799439015",
"quantity": 1
}
]
}Propósito: Archivo principal de la aplicación
- Configuración de Express
- Setup de Handlebars
- Conexión a MongoDB
- Creación del servidor HTTP con Socket.io
- Definición de rutas
Propósito: Configuración de Socket.io
- Manejo de conexiones
- Eventos de desconexión
- Estructura para emitir eventos en tiempo real
Propósito: Conexión a MongoDB
- Conexión a la base de datos
ecommerce - Manejo de errores de conexión
Propósito: Schema del producto
- Validación de campos requeridos
- Plugin de paginación
- Timestamps automáticos
Propósito: Schema del carrito
- Referencia a productos
- Array de productos con cantidades
- Validación de estructura
Propósito: Lógica de negocio para productos
getProducts()- Listado con paginacióngetProductById()- Obtener producto individualcreateProduct()- Crear productoupdateProduct()- Actualizar productodeleteProduct()- Eliminar producto
Propósito: Lógica de negocio para carritos
createCart()- Inicializar carritoaddProductToCart()- Agregar/incrementar productogetCartById()- Obtener carrito con datosupdateCart()- Actualizar todos los productosupdateProductQuantity()- Cambiar cantidad específicadeleteProductFromCart()- Eliminar productoclearCart()- Vaciar carrito
- products.router.js - Rutas API de productos
- carts.router.js - Rutas API de carritos
- home.router.js - Ruta de inicio
- views.router.js - Rutas de vistas renderizadas
- home.hbs - Página de inicio
- products.hbs - Listado de productos
- cart.hbs - Vista del carrito
- realTimeProducts.hbs - Productos en tiempo real
- layouts/main.hbs - Layout base
| Tecnología | Versión | Propósito |
|---|---|---|
| Node.js | - | Runtime JavaScript |
| Express.js | ^5.2.1 | Framework web |
| MongoDB | - | Base de datos NoSQL |
| Mongoose | ^9.2.2 | ODM para MongoDB |
| Socket.io | ^4.8.3 | WebSockets en tiempo real |
| Nodemon | 3.1.11 | Hot reload en desarrollo |
| Tecnología | Propósito |
|---|---|
| Handlebars | Motor de plantillas |
| Bootstrap | 5.3.0 - Framework CSS |
| HTML5 | Estructura |
| CSS3 | Estilos |
| Herramienta | Propósito |
|---|---|
| Postman | Testing de API |
| MongoDB Compass | Visualización de BD |
| Git | Control de versiones |
Inicia la aplicación en modo producción.
npm startInicia la aplicación en modo desarrollo con nodemon (hot-reload).
npm run devScript para ejecutar tests (actualmente no configurado).
npm testProducto no encontrado (404):
{
"status": "error",
"message": "Producto no encontrado"
}Carrito no encontrado (404):
{
"status": "error",
"message": "Carrito no encontrado"
}Error del servidor (500):
{
"status": "error",
"message": "Descripción del error"
}- Los campos requeridos se validan a nivel de schema Mongoose
- Se retornan errores descriptivos en JSON
- Validación automática de tipos de datos
Autor: Emmanuel Alejandro Lopez Vergara
Repositorio: Backend-I
Licencia: MIT
Este proyecto está bajo la licencia MIT. Ver LICENSE para más detalles.
- Express.js por el excelente framework
- MongoDB por la flexibilidad en datos
- Socket.io por WebSockets simplificado
- Handlebars por templating elegante
- Bootstrap por el CSS responsive
Última actualización: Marzo 19, 2024
Versión: 1.0.0