T U T O R I A L P A S O A P A S O — S E N A
A D S O 2 0 2 6
Construye tu primera Aplicación Web
MEAN STACK
Gestión de Empleados
Angular 19+ Standalone • MongoDB • Express • [Link]
VS Code • MongoDB Compass • Postman
Programa: Análisis y Desarrollo de Software (ADSO)
Servicio Nacional de Aprendizaje — SENA — 2026
Centro De Comercio y Turismo
SENA Regional Quindio
Instructor: CARLOS ALBERTO FUEL TULCAN
Versión actualizada para Angular 19+ (Standalone — sin NgModules)
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
1. ¿Qué vamos a construir?
Vamos a crear una aplicación web completa para la gestión de empleados (CRUD). Usaremos el stack
MEAN:
• MongoDB: Base de datos NoSQL.
• Express: Framework web para [Link].
• Angular 19+ Standalone: Framework Frontend de Google (sin NgModules).
• [Link]: Entorno JavaScript del lado del servidor.
FRONTEND API REST BASE DE DATOS
Angular 19+ ↔ Express + [Link] ↔ MongoDB
Puerto 4200 Puerto 3000 Puerto 27017
2. Requisitos Previos
Instala estos programas desde sus sitios oficiales:
• [Link] v20 LTS — [Link]
• MongoDB Community v7+ — [Link]
• MongoDB Compass — [Link]
• Visual Studio Code — [Link]
• Postman — [Link]
$ node --version
v20.11.0
$ npm --version
10.2.4
MongoDB debe estar corriendo
Asegúrate de que el servicio de MongoDB esté activo antes de continuar.
3. Estructura General del Proyecto
Estructura de carpetas
SENA — ADSO 2026 | Página 2
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
gestion-empleados/
├── BackEnd/
│ ├── [Link] # Servidor principal
│ ├── [Link] # Conexión MongoDB
│ ├── models/[Link] # Esquema
│ ├── controllers/[Link]
│ └── routes/[Link]
├── frontend/src/app/
│ ├── [Link] # Componente raíz
│ ├── [Link] # Template raíz
│ ├── [Link] # Config global (reemplaza [Link])
│ ├── components/empleados/ # Componente
│ ├── models/ # Clase Empleado
│ └── services/ # Servicio HTTP
└── [Link]
SENA — ADSO 2026 | Página 3
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
PARTE 1 — CONSTRUCCIÓN DEL BACKEND (API REST)
4. Inicializar el Proyecto con npm
Abre VS Code, crea la carpeta gestion-empleados, ábrela y ejecuta en la terminal:
$ npm init -y
$ mkdir -p BackEnd/models BackEnd/controllers BackEnd/routes
5. Instalar Dependencias del Backend
$ npm install express mongoose morgan cors
$ npm install nodemon --save-dev
• express: Framework web para [Link].
• mongoose: Conexión y modelado de datos con MongoDB.
• morgan: Logger de peticiones HTTP en terminal.
• cors: Permite comunicación Frontend:4200 → Backend:3000.
• nodemon: Reinicio automático del servidor al guardar cambios.
Edita [Link] — agrega el script de inicio:
[Link]
{ "name": "gestion-empleados",
"scripts": { "dev": "nodemon BackEnd/[Link]" },
"dependencies": {
"cors": "^2.8.5", "express": "^4.21.0",
"mongoose": "^8.9.0", "morgan": "^1.10.0" },
"devDependencies": { "nodemon": "^3.1.0" } }
6. Crear [Link] (Servidor Principal)
Crea BackEnd/[Link]:
BackEnd/[Link]
SENA — ADSO 2026 | Página 4
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
// Importar módulos
const express = require('express');
const morgan = require('morgan');
const cors = require('cors');
const app = express();
const { mongoose } = require('./database');
// Configuraciones
[Link]('port', [Link] || 3000);
// Middlewares
[Link](morgan('dev'));
[Link]([Link]());
[Link](cors({ origin: '[Link] }));
// Rutas
[Link]('/api/empleados',
require('./routes/[Link]'));
// Iniciar servidor
[Link]([Link]('port'), () => {
[Link]('Servidor activo en puerto',
[Link]('port'));
});
7. Configurar Conexión a MongoDB
Crea BackEnd/[Link]:
BackEnd/[Link]
const mongoose = require('mongoose');
const URI = 'mongodb://localhost:27017/empleados';
[Link](URI)
.then(db => [Link]('BD conectada'))
.catch(err => [Link]('Error BD:', err));
[Link] = mongoose;
SENA — ADSO 2026 | Página 5
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
MongoDB crea la BD automáticamente
La base de datos 'empleados' se crea sola al insertar el primer registro.
8. Crear el Modelo de Empleado
Crea BackEnd/models/[Link]:
BackEnd/models/[Link]
const mongoose = require('mongoose');
const { Schema } = mongoose;
const EmpleadoSchema = new Schema({
name: { type: String, required: true },
position: { type: String, required: true },
office: { type: String, required: true },
salary: { type: Number, required: true },
});
[Link] = [Link]('Empleado',
EmpleadoSchema);
9. Crear el Controlador (CRUD)
Crea BackEnd/controllers/[Link]:
BackEnd/controllers/[Link]
const Empleado = require('../models/empleado');
const ctrl = {};
// GET todos los empleados
[Link] = async (req, res) => {
const empleados = await [Link]();
[Link](empleados);
};
// POST crear empleado
[Link] = async (req, res) => {
const empleado = new Empleado([Link]);
await [Link]();
[Link]({ status: 'Empleado guardado' });
SENA — ADSO 2026 | Página 6
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
};
// GET un empleado por ID
[Link] = async (req, res) => {
const e = await [Link]([Link]);
[Link](e);
};
// PUT actualizar empleado
[Link] = async (req, res) => {
const { id } = [Link];
const edit = { name: [Link],
position: [Link],
office: [Link],
salary: [Link] };
await [Link](id,
{ $set: edit }, { new: true });
[Link]({ status: 'Empleado Actualizado' });
};
// DELETE eliminar empleado
[Link] = async (req, res) => {
await [Link]([Link]);
[Link]({ status: 'Empleado Eliminado' });
};
[Link] = ctrl;
10. Definir las Rutas de la API
Crea BackEnd/routes/[Link]:
BackEnd/routes/[Link]
const express = require('express');
const router = [Link]();
const ctrl = require(
'../controllers/[Link]');
[Link]('/', [Link]);
[Link]('/', [Link]);
SENA — ADSO 2026 | Página 7
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
[Link]('/:id', [Link]);
[Link]('/:id', [Link]);
[Link]('/:id', [Link]);
[Link] = router;
11. Probar la API con Postman
$ npm run dev
Servidor activo en puerto 3000
BD conectada
En Postman — Crear empleado (POST):
1. Método: POST
2. URL: [Link]
3. Body → raw → JSON:
Body POST
{ "name": "Santiago",
"position": "Desarrollador Web",
"office": "Colombia",
"salary": 3500000 }
4. Clic en Send. Respuesta: { "status": "Empleado guardado" }
12. Verificar en MongoDB Compass
1. Abre MongoDB Compass
2. Conexión: mongodb://localhost:27017
3. Clic en la BD empleados → colección empleados
4. Verás el registro de Santiago
¡Backend completado!
Tu API REST funciona. Ahora construiremos el Frontend.
SENA — ADSO 2026 | Página 8
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
PARTE 2 — FRONTEND (ANGULAR 19+ STANDALONE)
Dos terminales necesarias
Mantén el Backend corriendo (npm run dev) en Terminal 1. Usa Terminal 2 para Angular.
13. Instalar Angular CLI y Crear Proyecto
$ npm install -g @angular/cli
$ ng version
Angular CLI: 19.x.x
Crear el proyecto (desde la carpeta raíz gestion-empleados):
$ ng new frontend
? Which stylesheet format? CSS
? Enable SSR? N
Angular 19+ usa Standalone por defecto
Ya no existe [Link]. En su lugar: [Link] para configuración global. Los archivos usan nombres
concisos: [Link], [Link] (estilo 2025). Si tu versión genera [Link], el código es idéntico, solo
cambian los nombres.
$ cd frontend
$ ng serve
Compiled successfully.
localhost:4200
14. Generar Componentes, Modelo y Servicio
Dentro de frontend/:
$ ng g c components/empleados
CREATE src/app/components/empleados/[Link]
CREATE src/app/components/empleados/[Link]
SENA — ADSO 2026 | Página 9
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
$ ng g class models/empleado
CREATE src/app/models/[Link]
$ ng g s services/empleado
CREATE src/app/services/[Link]
Nombres en Angular 19+ (estilo 2025)
Archivos: [Link] (no .[Link]), [Link] en services (no .[Link]). Clases: el componente
raíz se llama 'App' (no 'AppComponent'). Los componentes generados sí mantienen sufijo:
EmpleadosComponent, EmpleadoService. Las importaciones deben coincidir con los nombres reales de los
archivos: from '../../services/empleado' (sin .service).
15. Incorporar Materialize CSS
Edita frontend/src/[Link]:
frontend/src/[Link]
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<title>Gestión de Empleados</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CDN Materialize CSS -->
<link rel="stylesheet"
href="[Link]
materialize/1.0.0/css/[Link]">
<!-- CDN Material Icons -->
<link href="[Link]
icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<app-root></app-root>
<script src="[Link]
libs/materialize/1.0.0/js/[Link]">
</script>
</body></html>
SENA — ADSO 2026 | Página 10
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
16. Configurar [Link] (Plantilla Principal)
Borra todo el contenido por defecto de [Link] y escribe:
Nombre del archivo según tu versión
Si tu proyecto muestra [Link] → edita ese. Si muestra [Link] → edita ese. El contenido es
idéntico.
frontend/src/app/[Link]
<!-- Barra de navegación -->
<nav class="nav-wrapper blue darken-2">
<div class="container">
<a href="/" class="brand-logo">
GESTIÓN DE EMPLEADOS</a>
</div>
</nav>
<!-- Contenedor: carga componente empleados -->
<div class="container" style="margin-top:20px">
<app-empleados></app-empleados>
</div>
17. Configurar [Link] (Proveedores)
En Angular 19+ ya no existe [Link]. Edita [Link]:
frontend/src/app/[Link]
// CONFIGURACIÓN GLOBAL (reemplaza [Link])
import { ApplicationConfig }
from '@angular/core';
import { provideRouter }
from '@angular/router';
import { provideHttpClient }
from '@angular/common/http';
import { routes } from './[Link]';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
SENA — ADSO 2026 | Página 11
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
provideHttpClient(), // <-- AGREGAR
// Reemplaza al antiguo HttpClientModule
]
};
¿Qué cambió vs. el tutorial original?
provideHttpClient() reemplaza a HttpClientModule. FormsModule se importa directamente en cada
componente que lo necesite (no en un módulo central). ¡Más limpio y modular!
También edita [Link] (componente raíz) para importar el componente empleados:
IMPORTANTE — Reemplaza TODO el contenido de [Link]
Selecciona todo el contenido del archivo (Ctrl+A), bórralo y pega el código de abajo. No mezcles con lo que ya
había.
frontend/src/app/[Link]
// COMPONENTE RAÍZ DE LA APLICACIÓN
// Angular 19+ genera la clase como 'App' (no 'AppComponent')
// [Link] importa esta clase para arrancar la app
import { Component } from '@angular/core';
import { EmpleadosComponent }
from './components/empleados/empleados';
@Component({
selector: 'app-root',
imports: [EmpleadosComponent], // <-- AGREGAR
templateUrl: './[Link]',
styleUrl: './[Link]',
})
export class App { // <-- OJO: 'App', NO 'AppComponent'
title = 'frontend';
}
Sobre [Link] (NO lo modifiques si no es necesario)
Angular genera [Link] así: import { App } from './app/app'; y luego bootstrapApplication(App, appConfig). Si
cambiaste el nombre de la clase en [Link] (por ejemplo a AppComponent), debes cambiar también [Link]
para que coincida. Lo más fácil: usa el nombre 'App' como muestra el código de arriba y no toques [Link].
SENA — ADSO 2026 | Página 12
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
18. Definir el Modelo [Link]
Edita frontend/src/app/models/[Link] — reemplaza TODO el contenido:
models/[Link]
export class Empleado {
constructor(
_id='', name='', position='',
office='', salary=0) {
this._id = _id;
[Link] = name;
[Link] = position;
[Link] = office;
[Link] = salary;
}
_id: string; // Viene de MongoDB
name: string;
position: string;
office: string;
salary: number;
}
19. Crear el Servicio HTTP
Edita services/[Link] — reemplaza TODO el contenido:
services/[Link]
import { Injectable } from '@angular/core';
import { HttpClient }
from '@angular/common/http';
import { Empleado }
from '../models/empleado';
@Injectable({ providedIn: 'root' })
export class EmpleadoService {
selectedEmpleado: Empleado;
empleados: Empleado[];
readonly URL_API =
'[Link]
SENA — ADSO 2026 | Página 13
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
constructor(private http: HttpClient) {
[Link] = new Empleado();
[Link] = [];
}
getEmpleados() {
return [Link](this.URL_API); }
postEmpleado(e: Empleado) {
return [Link](this.URL_API, e); }
putEmpleado(e: Empleado) {
return [Link](
this.URL_API+`/${e._id}`, e); }
deleteEmpleado(_id: string) {
return [Link](
this.URL_API+`/${_id}`); }
}
20. Componente [Link] (Lógica)
Cambio clave: FormsModule se importa directamente en el componente standalone.
Reemplaza TODO el contenido del archivo
Selecciona todo con Ctrl+A, borra y pega el código de abajo. NO mezcles con el código que Angular generó
automáticamente, ya que tendrá imports duplicados y causará errores.
components/empleados/[Link]
import { Component, OnInit }
from '@angular/core';
import { FormsModule, NgForm }
from '@angular/forms';
import { EmpleadoService }
from '../../services/empleado';
import { Empleado }
from '../../models/empleado';
declare var M: any; // Materialize Toast
@Component({
selector: 'app-empleados',
imports: [FormsModule], // <-- CLAVE
SENA — ADSO 2026 | Página 14
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
templateUrl: './[Link]',
styleUrl: './[Link]',
providers: [EmpleadoService]
})
export class EmpleadosComponent
implements OnInit {
constructor(
public empleadoService:
EmpleadoService) { }
ngOnInit(): void { }
agregarEmpleado(form?: NgForm) {
[Link]
.postEmpleado(form?.value)
.subscribe(res => {
[Link](form);
[Link]({
html:'Empleado guardado'});
});
}
resetForm(form?: NgForm) {
if (form) {
[Link]();
[Link]
.selectedEmpleado =
new Empleado();
}
}
}
imports dentro de @Component
En standalone, cada componente declara sus dependencias en el arreglo imports. FormsModule se importa
aquí directamente, no en un módulo centralizado.
21. Formulario HTML ([Link])
Edita components/empleados/[Link]:
SENA — ADSO 2026 | Página 15
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
[Link]
<div class="container">
<div class="row">
<div class="col s5">
<div class="card">
<div class="card-content">
<form #empleadoForm="ngForm"
(ngSubmit)="agregarEmpleado(
empleadoForm)">
<div class="row">
<!-- Nombre -->
<div class="input-field col s12">
<input type="text" name="name"
#name="ngModel"
[(ngModel)]="empleadoService
.[Link]"
placeholder="Ingrese nombre">
</div>
<!-- Cargo -->
<div class="input-field col s12">
<input type="text" name="position"
#position="ngModel"
[(ngModel)]="empleadoService
.[Link]"
placeholder="Ingrese cargo">
</div>
<!-- Oficina -->
<div class="input-field col s12">
<input type="text" name="office"
#office="ngModel"
[(ngModel)]="empleadoService
.[Link]"
placeholder="Ingrese oficina">
</div>
<!-- Salario -->
<div class="input-field col s12">
<input type="number" name="salary"
#salary="ngModel"
[(ngModel)]="empleadoService
.[Link]"
SENA — ADSO 2026 | Página 16
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
placeholder="Ingrese salario">
</div>
<!-- Botones -->
<div class="card-action">
<div class="input-field col s12">
<button class="btn"
type="submit">Guardar</button>
<button class="btn right"
type="button"
(click)="resetForm(
empleadoForm)">
Limpiar</button>
</div>
</div>
</div>
</form>
</div></div></div>
<div class="col s7">
<!-- Lista de empleados (ejercicio) -->
</div>
</div>
</div>
22. Ejecutar la Aplicación Completa
Terminal 1 (Backend): npm run dev
Terminal 2 (Frontend): cd frontend && ng serve
Abre [Link] y verás:
• Barra azul: GESTIÓN DE EMPLEADOS
• Formulario con 4 campos: nombre, cargo, oficina, salario
• Botones Guardar y Limpiar
Llena los campos, clic en Guardar → Toast confirma el guardado. Verifica en MongoDB Compass.
¡Felicidades! Aplicación MEAN Stack funcionando
Frontend Angular 19+ Standalone + Backend Express/[Link] + MongoDB. ¡Todo conectado!
SENA — ADSO 2026 | Página 17
Tutorial MEAN Stack — Gestión de Empleados (Angular 19+ Standalone)
23. Resumen y Próximos Pasos
Lo que aprendiste:
• Servidor [Link] con Express y middlewares
• Conexión a MongoDB con Mongoose
• Modelos (schemas), controladores CRUD, rutas REST
• Pruebas con Postman y verificación en MongoDB Compass
• Proyecto Angular 19+ Standalone (sin NgModules)
• [Link] con provideHttpClient()
• Componentes standalone con imports directos (FormsModule)
• Formularios con ngModel (enlace bidireccional)
• Estilos con Materialize CSS
Retos para seguir practicando:
• Mostrar lista: Tabla con *ngFor en la columna derecha.
• Editar: Clic en un empleado → cargar datos en el formulario.
• Eliminar: Botón eliminar en cada fila.
• Validación: No permitir campos vacíos.
• Responsive: Ajustar con clases de Materialize para móviles.
Recursos de apoyo:
• [Link]: [Link]
• Express: [Link]
• Mongoose: [Link]
• Angular: [Link]
• Materialize: [Link]
SENA — ADSO 2026 | Construcción de Aplicaciones Web | Angular 19+ Standalone
SENA — ADSO 2026 | Página 18