Proyecto web full stack culminado: SweetLab
SweetLab es una aplicación completa para gestión de recetas, pensada como práctica integral de desarrollo web moderno. Incluye backend (Node.js + Express + MongoDB) y frontend (Angular), con despliegue en producción y documentación detallada.
Permite crear, ver, editar y eliminar recetas de cocina, con autenticación y control de roles. El frontend muestra recetas desde un archivo local o desde la base de datos, según la configuración. El backend expone una API REST segura y validada.
Para detalles técnicos y explicación profunda de cada parte, consulta la Guía Explicativa o el PDF equivalente.
-
Clona el repositorio y entra a la carpeta:
git clone https://github.com/MirelSIG/SweetLab.git cd SweetLab -
Arranca el backend:
cd backend npm install node src/server.jsEl backend conecta a MongoDB (local o Atlas) y expone la API en el puerto 4000.
-
Arranca el frontend en otra terminal:
cd frontend npm install npm startEl frontend abre automáticamente en http://localhost:4200.
-
(Opcional) Ejecuta los tests del backend:
cd backend npm test
- El frontend Angular permite visualizar, buscar, crear, editar y eliminar recetas. Si el backend está activo, usa la API; si no, muestra recetas ficticias desde un JSON local.
- El backend Express gestiona usuarios, autenticación y recetas en MongoDB, con validaciones y control de acceso por roles.
- El sistema está pensado para aprender y practicar el ciclo completo de una app web: desde la interfaz hasta la base de datos.
Para detalles de endpoints, validaciones, estructura de carpetas y más, revisa la guía explicativa incluida en el proyecto.
En palabras simples:
- El frontend es la parte visual que ves en el navegador.
- El backend es la parte que procesa datos y habla con la base de datos.
- backend API REST con Express y Mongoose.
- frontend Aplicacion Angular standalone.
- docs Notas del proyecto (backlog, checklist, etc.).
- backend/src/server.js Arranca el servidor y conecta a MongoDB.
- backend/src/app.js Configura middlewares y monta rutas.
- backend/src/routes/recipeRoutes.js Define endpoints de recetas.
- backend/src/controllers/recipeController.js Logica de negocio y validaciones de body/id.
- backend/src/models/Recipe.js Esquema de receta en MongoDB.
- frontend/src/main.ts Punto de entrada de Angular.
- frontend/src/app/app.component.ts Componente principal (estado, filtros, seleccion).
- frontend/src/app/recipe.service.ts Servicio que hace llamadas HTTP a la API del backend.
- frontend/src/assets/recipes.json Datos ficticios locales (como fallback o referencia).
Necesitas tener instalado:
- Node.js 18 o superior
- npm (viene con Node)
- Conexion a internet (para instalar paquetes)
Opcional pero recomendado:
- MongoDB Atlas configurado (ya se usa mediante MONGO_URI en el backend)
Desde la carpeta backend:
cd backend
npm install
node src/server.jsSi todo va bien, deberias ver mensajes de conexion a MongoDB y servidor en puerto 4000.
Para ejecutar los tests automatizados de autenticacion:
cd backend
npm install
npm testPara ver el reporte de cobertura de código:
cd backend
npm run test:covEsto genera un reporte HTML en coverage/lcov-report/index.html que puedes abrir en el navegador.
Desde otra terminal, en la carpeta frontend:
cd frontend
npm install
npm startAngular levanta un servidor de desarrollo (normalmente en puerto 4200).
Base URL local:
http://localhost:4000/api
Antes de usar rutas de recetas, inicia sesión en:
- POST /auth/login
Body esperado:
{
"role": "admin",
"username": "admin",
"password": "SweetLab@2026!"
}Credenciales por defecto (desarrollo):
- admin: username
admin, passwordSweetLab@2026!
Permisos:
- admin: lectura + crear + editar + eliminar
Puedes cambiar credenciales desde variables de entorno del backend:
ADMIN_USERNAMEADMIN_PASSWORDJWT_SECRETJWT_EXPIRES_INJWT_REFRESH_SECRETJWT_REFRESH_EXPIRES_INMAX_LOGIN_ATTEMPTSLOCK_TIME_MINUTES
Seed de usuarios en MongoDB (recomendado al iniciar):
cd backend
npm install
npm run seed:usersEl login devuelve token (acceso) y refreshToken (renovación).
Si expira el access token, el frontend intenta renovar automáticamente con POST /auth/refresh.
Tras varios intentos de login fallidos, el backend aplica bloqueo temporal por identidad (usuario + IP).
Rutas:
- POST /auth/login
- POST /auth/refresh
- POST /auth/logout
- GET /recipes Lista todas las recetas.
- GET /recipes/:id Obtiene una receta por id.
- POST /recipes Crea una receta nueva.
- PUT /recipes/:id Actualiza receta existente.
- DELETE /recipes/:id Elimina receta por id.
Ejemplo minimo de body para crear receta:
{
"title": "Tarta de manzana",
"ingredients": ["2 manzanas", "harina", "azucar"],
"steps": ["mezclar", "hornear"],
"tags": ["postre"]
}curl -X POST http://127.0.0.1:4000/api/recipes \
-H "Content-Type: application/json" \
-d '{
"title": "Brownies Clásicos",
"ingredients": ["200g chocolate", "150g mantequilla", "2 huevos", "1 taza harina", "azúcar"],
"steps": ["Derretir chocolate y mantequilla", "Mezclar con huevos y azúcar", "Incorporar harina", "Hornear 25 minutos a 180°C"],
"tags": ["chocolate", "postre", "rápido"]
}'Respuesta esperada (si todo va bien):
{
"_id": "665a1b2c3d4e5f6g7h8i9j0k",
"title": "Brownies Clásicos",
"ingredients": ["200g chocolate", "150g mantequilla", "2 huevos", "1 taza harina", "azúcar"],
"steps": ["Derretir chocolate y mantequilla", "Mezclar con huevos y azúcar", "Incorporar harina", "Hornear 25 minutos a 180°C"],
"tags": ["chocolate", "postre", "rápido"],
"createdAt": "2026-04-02T08:19:13.000Z",
"updatedAt": "2026-04-02T08:19:13.000Z"
}curl -X POST http://127.0.0.1:4000/api/recipes \
-H "Content-Type: application/json" \
-d '{
"title": "Tiramisú",
"ingredients": ["Mascarpone", "Café fuerte", "Bizcochos de soletilla", "Cacao en polvo", "Azúcar"],
"steps": ["Preparar crema mascarpone con azúcar", "Mojar bizcochos en café", "Montar capas: crema, bizcochos, crema", "Refrigerar 4 horas", "Espolvorear cacao antes de servir"],
"tags": ["frío", "postre", "italiano"]
}'¿Como sería ese flujo?
- Crear un script Node.js que lea docs/recipes-example.json.
- Hacer un POST a
http://127.0.0.1:4000/api/recipespor cada receta.
Ejemplo de script (si quisieras automatizar):
// archivo: import-recipes.js
const fs = require('fs');
const recipes = JSON.parse(fs.readFileSync('./docs/recipes-example.json', 'utf8'));
recipes.forEach(recipe => {
fetch('http://127.0.0.1:4000/api/recipes', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(recipe)
})
.then(r => r.json())
.then(data => console.log('✅ Creada:', data.title))
.catch(err => console.error('❌ Error:', err));
});Para ejecutar:
node import-recipes.jsUna vez creadas, lista todas las recetas:
curl http://127.0.0.1:4000/api/recipesDeberias ver un array con Brownies y Tiramisú más sus ids.
En backend/src/controllers/recipeController.js se agregaron validaciones para evitar errores confusos:
- Si el body viene vacio, devuelve 400 con mensaje claro.
- Si faltan campos obligatorios en creacion, devuelve 400.
- Si el id no es un ObjectId valido, devuelve 400 en rutas por id.
- Si no existe receta con ese id valido, devuelve 404.
Esto ayuda mucho cuando estas aprendiendo porque los errores son mas entendibles.
Con el servidor levantado, prueba:
curl -i http://127.0.0.1:4000/api/recipesRespuesta esperada inicial:
- HTTP 200
- Body [] (si aun no hay recetas guardadas)
- Levanta backend y frontend por separado.
- Entiende la ruta completa de una receta: frontend -> servicio -> API -> controlador -> modelo -> MongoDB.
- Prueba CRUD con Postman o curl.
- Crea 1 pantalla nueva en Angular (por ejemplo, formulario de alta).
- Conecta esa pantalla al endpoint POST del backend.
Si haces eso, vas a entender la base real de una app web full stack.
- API REST: interfaz de URLs para pedir o guardar datos.
- Endpoint: cada URL de la API con una accion especifica.
- CRUD: Create, Read, Update, Delete.
- JSON: formato de texto para representar datos.
- Componente (Angular): bloque reutilizable de interfaz y logica.
- Servicio (Angular): clase para centralizar tareas como llamadas HTTP.
- Mongoose: libreria para modelar datos de MongoDB en Node.js.
- Frontend Angular funcionando con recetas ficticias en JSON local.
- Backend Express funcionando en puerto 4000 con MongoDB.
- CRUD de recetas implementado.
- Validaciones mejoradas para body vacio e id invalido.
El frontend Angular ahora está conectado con la API del backend. Los cambios que se hicieron fueron:
- Cambio de URL: de
assets/recipes.jsonahttp://localhost:4000/api/recipes - Se agregaron métodos para CRUD completo:
getRecipeById(),createRecipe(),updateRecipe(),deleteRecipe()
- Se hicieron todos los campos opcionales (excepto title, ingredients, steps)
- Se agregó soporte para
_idde MongoDB además deid - Se agregaron campos como
createdAtyupdatedAt
- Se actualizó el manejo de errores para que avise si el backend no está corriendo
- Se extrae la lógica de carga en método
loadRecipes()
- Se usan comparaciones condicionales con
_idyid - Los campos opcionales solo muestran si existen
- Titulo actualizado para reflejar lectura desde MongoDB
- Asegúrate que el backend esté corriendo:
cd backend
node src/server.js- En otra terminal, arranca el frontend Angular:
cd frontend
npm start-
Abre Sweetlab en el navegador.
-
Si el backend no responde, verás este mensaje:
❌ No se pudo conectar a la API. Verifica que el backend esté corriendo en http://localhost:4000
- Si todo funciona, deberías ver las recetas que agregaste a MongoDB (si es que agregaste algunas).
- Angular hace GET a http://localhost:4000/api/recipes
- El backend responde con recetas desde MongoDB
- El frontend mapea
_id→idinternamente - Los campos opcionales se muestran solo si existen
Para seguir aprendiendo, el proximo paso seria construir:
- Input para crear receta nueva
- Botones para actualizar receta seleccionada
- Botones para eliminar receta
- Métodos en el componente que usen
createRecipe(),updateRecipe(),deleteRecipe()
Esto te permitirá practicar Angular two-way binding y events.
El frontend está configurado para desplegarse automáticamente en GitHub Pages.
Para activar:
- Ve a Settings → Pages en tu repositorio de GitHub
- Selecciona "GitHub Actions" como fuente de deploy
- Haz push a la rama main
Tu app estará disponible en: https://MirelSIG.github.io/SweetLab/
Ver guía completa en: docs/github-pages-setup.md
Ahora puedes editar cualquier receta que hayas seleccionado:
- Selecciona una receta en la lista
- Presiona el botón ** Editar**
- Modifica los campos que quieras (título, ingredientes, pasos, tags, tiempo, dificultad)
- Presiona Guardar cambios
Los cambios se envían a la API y se reflejan inmediatamente en la lista.
Para eliminar una receta:
- Selecciona la receta que quieres eliminar
- Presiona el botón ** Eliminar**
- Confirma que quieres eliminarla en el diálogo
- La receta se eliminará de MongoDB y desaparecerá de la lista
El frontend ahora abre automáticamente el navegador cuando inicias el servidor:
cd frontend
npm startEl navegador se abrirá automáticamente en http://localhost:4200 (o en el puerto configurado).
- Create (Crear): Botón "Añadir receta" con formulario amigable o JSON
- Read (Leer): Lista de recetas con búsqueda y selección
- Update (Editar): Botón "Editar" en cada receta
- Delete (Eliminar): Botón "Eliminar" con confirmación
- **Sitio en producción: https://sweetlab-kf27.onrender.com
- Visualización: Cualquiera puede ver las imágenes que se incluyen en
frontend/src/assetsy las imágenes asociadas a cada receta desde la interfaz pública. - Edición / Subida de recetas e imágenes: Solo los usuarios con rol admin pueden crear, subir o editar recetas (incluyendo adjuntar imágenes). Las rutas de creación/actualización/eliminación (
POST,PUT,DELETE) están protegidas por el middlewarerequireRole('admin')en el backend. - Reglas de contraseña: Al registrar una cuenta nueva, la contraseña debe tener al menos 8 caracteres y contener al menos una letra mayúscula, una letra minúscula y un número.
