Documentación Frontend

Documentación Desarrollo Trexsas Frontend

Guía completa de arquitectura, estructura y configuración del proyecto Angular

Proyecto Transporte
Autor Elder Daniel Agudelo Pita
Fecha 4/12/2025
Versión 1.1
01

Resumen Ejecutivo

Este documento presenta la arquitectura técnica completa del proyecto frontend desarrollado con Angular. El sistema está diseñado siguiendo principios de desarrollo empresarial, garantizando escalabilidad, mantenibilidad y seguridad a través de una estructura modular bien definida.

El proyecto implementa un sistema de gestión integral con control de acceso basado en roles, autenticación mediante tokens JWT, y una arquitectura de componentes reutilizables que facilita el desarrollo colaborativo y el mantenimiento a largo plazo.

02

Introducción

2.1 Propósito del Documento

Este documento técnico tiene como objetivo proporcionar una guía exhaustiva sobre la arquitectura, estructura y configuración del proyecto frontend. Está diseñado para servir como referencia principal para:

  • Desarrolladores que se integren al proyecto
  • Arquitectos de software que necesiten evaluar decisiones técnicas
  • Equipos de QA para comprender la estructura de pruebas
  • Personal de soporte técnico
  • Auditores de seguridad

2.2 Alcance

La documentación cubre los siguientes aspectos del proyecto:

Arquitectura

Arquitectura general del sistema frontend

Estructura

Estructura de directorios y organización del código

Configuración

Configuración de entornos de desarrollo y producción

Seguridad

Implementación de seguridad y control de acceso

Patrones

Patrones de diseño aplicados

Routing

Estrategias de routing y navegación

2.3 Audiencia

Este documento está dirigido a profesionales técnicos con conocimientos en:

  • Desarrollo web con Angular (versión 8+)
  • TypeScript y JavaScript ES6+
  • Arquitectura de aplicaciones SPA (Single Page Application)
  • Conceptos de seguridad web y autenticación
  • Herramientas de desarrollo frontend modernas
03

Arquitectura del Sistema

3.1 Visión General

El proyecto implementa una arquitectura de Single Page Application (SPA) basada en el framework Angular. La aplicación sigue el patrón arquitectónico MVC (Model-View-Controller) adaptado a las mejores prácticas de Angular:

M

Model

Interfaces TypeScript y modelos de datos

V

View

Templates HTML con Angular templating

C

Controller

Componentes TypeScript con lógica de presentación

3.2 Stack Tecnológico

Tecnología Versión Propósito
Angular 8+ Framework principal
TypeScript 3.5+ Lenguaje de programación
RxJS 6+ Programación reactiva
PrimeNG Latest Biblioteca de componentes UI
Node.js 12+ Entorno de ejecución
npm 6+ Gestor de paquetes

3.3 Patrones de Diseño

El proyecto implementa los siguientes patrones:

Patrón Observable: Para manejo de eventos asíncronos y comunicación entre componentes
Patrón Singleton: En servicios inyectables
Patrón Guard: Para protección de rutas
Patrón Module: Para organización y lazy loading
Patrón Dependency Injection: Para inyección de dependencias
04

Estructura del Proyecto

4.1 Organización de Carpetas

Estructura de Directorios
proyecto/
│
├── .vscode/              # Configuraciones del IDE
├── assets/               # Recursos estáticos
├── dist/                 # Código compilado
├── e2e/                  # Pruebas end-to-end
├── node_modules/         # Dependencias
├── src/                  # Código fuente
│   ├── app/
│   │   ├── components/   # Componentes visuales
│   │   ├── constants/    # Constantes globales
│   │   ├── guards/       # Guardias de ruta
│   │   ├── models/       # Modelos de datos
│   │   └── services/     # Servicios
│   ├── assets/           # Recursos de la aplicación
│   └── environments/     # Configuraciones de entorno
├── angular.json          # Configuración de Angular CLI
├── package.json          # Dependencias del proyecto
└── tsconfig.json         # Configuración de TypeScript

4.2 Directorio .vscode

Propósito

Configuraciones específicas del IDE Visual Studio Code.

Contenido principal:

  • launch.json: Define configuraciones de depuración que permiten lanzar Google Chrome automáticamente apuntando a la aplicación local (http://localhost:4200)

Beneficios:

  • Estandarización del entorno de desarrollo
  • Facilita la depuración del equipo
  • Acelera la configuración inicial para nuevos desarrolladores

4.3 Directorio assets

Propósito

Almacenamiento de recursos estáticos que se cargan al iniciar la aplicación.

Contenido:

  • Imágenes del proyecto (logos, iconos, backgrounds)
  • Archivos de íconos (.ico)
  • Recursos visuales que no cambian dinámicamente

Características:

  • Los archivos se sirven directamente sin procesamiento
  • Se copian tal cual al directorio dist/ durante el build
  • Optimizados para carga inicial de la aplicación

4.4 Directorio dist

4.4.1 Subdirectorio dist/frontend

Propósito

Contiene la versión final, optimizada y lista para producción del proyecto.

Características:

  • Código JavaScript transpilado y minificado
  • Archivos CSS consolidados y optimizados
  • HTML procesado y optimizado
  • Source maps para depuración (opcional)

Destinos de despliegue:

Servidores web Nginx, Apache, IIS
Cloud Firebase, AWS S3, Azure
Contenedores Docker
CDN Content Delivery Networks

4.4.2 Subdirectorio dist/assets

Contenido:

  • Imágenes optimizadas (PNG, JPG, ICO, SVG)
  • Íconos y fuentes de PrimeNG/PrimeIcons
  • Archivos de configuración JSON
  • Archivos de licencias
  • Archivo de configuración global para labels de formularios
Nota importante

Este directorio incluye el archivo de configuración global que centraliza los nombres de campos, labels de variables de formularios e IDs requeridos en el proyecto, facilitando la internacionalización y el mantenimiento.

4.5 Directorio e2e

Propósito

Contiene las pruebas end-to-end (E2E) del proyecto Angular.

Las pruebas E2E simulan la interacción real del usuario con la aplicación completa desplegada en un navegador, validando:

  • Navegación entre páginas
  • Componentes visibles y su comportamiento
  • Flujos funcionales completos
  • Integración frontend-backend
  • Casos de uso de extremo a extremo
Estado actual: Las pruebas E2E no se ejecutan actualmente en este entorno.
Nota histórica: Estas pruebas tradicionalmente se ejecutaban con Protractor, que Angular incluía por defecto en versiones antiguas. Las versiones modernas de Angular utilizan otras herramientas como Cypress o Playwright.

4.6 Directorio node_modules

Propósito

Almacena todas las dependencias del proyecto instaladas vía npm.

Contenido:

  • Dependencias declaradas en package.json
  • Dependencias transitivas (dependencias de las dependencias)
  • Herramientas del framework Angular
  • Librerías para compilar TypeScript
  • Angular CLI y sus herramientas
  • Polyfills para compatibilidad con navegadores

Paquetes de desarrollo incluidos:

TypeScript (compilador) Webpack (bundler) Karma (test runner) Jasmine (framework de pruebas) Compodoc (generador de documentación) ESLint/TSLint (linters)
Nota: Este directorio no se versiona en el control de código fuente (incluido en .gitignore) y se regenera con npm install.

4.7 Directorio src (Sources)

Propósito

Contiene todo el código fuente de la aplicación.

Este directorio es el corazón del proyecto y contiene la lógica de negocio, componentes visuales, servicios, modelos y configuraciones que definen el comportamiento de la aplicación.

05

Componentes del Sistema

5.1 Directorio components

Propósito

Contiene todos los componentes visuales que conforman las interfaces del proyecto.

Funciones principales:

  • Gestionar vistas y pantallas
  • Controlar formularios, tablas, modales y elementos UI
  • Conectar con servicios para obtener datos
  • Representar la lógica de presentación del sistema
  • Manejar la interacción del usuario

Estructura de un componente:

Estructura de Directorios
component-name/
├── component-name.component.ts       # Lógica del componente
├── component-name.component.html     # Template
├── component-name.component.css      # Estilos
└── component-name.component.spec.ts  # Pruebas unitarias

Generación de componentes:

bash
ng generate component components/nombre-componente
# o forma corta:
ng g c components/nombre-componente

5.2 Directorio constants

Propósito

Centraliza valores globales reutilizables en toda la aplicación.

Este directorio mantiene configuraciones estáticas que deben ser consistentes en toda la aplicación:

  • Formatos de fecha y hora
  • Rutas a archivos de configuración
  • Longitudes mínimas y máximas para validaciones
  • Tipos de notificación del sistema
  • Nombres de acciones y operaciones
  • Códigos de estado y respuesta
  • Mensajes de sistema predefinidos

Beneficios:

  • Evita "magic strings" en el código
  • Reduce errores por cadenas mal escritas
  • Facilita el mantenimiento centralizado
  • Mejora la legibilidad del código
  • Simplifica cambios globales

Ejemplo de uso:

TypeScript constants/app.constants.ts
// constants/app.constants.ts
export const DATE_FORMAT = 'DD/MM/YYYY';
export const MAX_FILE_SIZE = 5242880; // 5MB
export const NOTIFICATION_TYPES = {
  SUCCESS: 'success',
  ERROR: 'error',
  WARNING: 'warning'
};

5.3 Directorio guards

Propósito

Implementa guardias de rutas para proteger secciones del sistema según permisos y autenticación.

Generación de guards:

bash
ng generate guard guards/nombre-del-guard
# o forma corta:
ng g guard guards/nombre-del-guard

Archivos generados:

  • nombre.guard.ts: Lógica del servicio
  • nombre.guard.spec.ts: Pruebas unitarias

5.3.1 Tipos de Guards Implementados

AccesocentralGuard - Validación de Sesión Principal
Sesión/Token

Propósito: Permite acceso solo a rutas del módulo principal si el usuario tiene sesión activa.

Funcionamiento:

  1. Verifica si existe un token JWT almacenado en el storage
  2. Si no existe token → redirige a / (login)
  3. Si existe token, lo valida con el backend: Token inválido/expirado → cierre de sesión + retorno a login. Token válido → permite entrada

Uso: Protege la ruta /central y toda la estructura funcional del sistema.

TypeScript
canActivate(): boolean {
  const token = this.authService.getToken();
  if (!token) {
    this.router.navigate(['/']);
    return false;
  }
  return this.authService.validateToken(token);
}
AccesochildGuard - Permisos para Módulos con Rutas Hijas
Permisos/Rutas Hijas

Propósito: Verifica permisos del usuario dentro de áreas específicas del sistema.

Características:

  • Se aplica a rutas secundarias dentro de /central/...
  • Depende del servicio CentralService.obtenerAcceso()
  • Valida permisos granulares por módulo

Flujo de validación:

  1. Obtiene permisos del usuario desde el servicio
  2. Compara con los permisos requeridos para la ruta
  3. Permite o deniega acceso según coincidencia
AccesoparametrizacionGuard - Acceso a Configuración del Sistema
Rol/Privilegios

Propósito: Restringe acceso a módulos de parametrización y configuración global.

Características:

  • Valida que el usuario pertenezca al rol de administrador
  • Si el usuario no tiene permisos → redirección automática a /central
  • Evita que usuarios sin privilegios modifiquen parámetros críticos del sistema

Casos de uso:

  • Configuración de catálogos
  • Parametrización de procesos
  • Ajustes de sistema
  • Gestión de roles y permisos
AccesoOrdenServicioGuard - Validación para Órdenes de Servicio
Permisos Específicos

Propósito: Permite acceso solo si el usuario tiene permisos para gestionar órdenes de servicio.

Características avanzadas:

  • Detecta IDs numéricos en la URL usando expresiones regulares
  • Busca coincidencias en uriHija con distintos niveles de truncamiento (substr 3/6/8)
  • Validación dinámica según el ID de la orden
TypeScript
canActivate(route: ActivatedRouteSnapshot): boolean {
  const orderId = route.params['id'];
  const hasAccess = this.validateOrderAccess(orderId);
  if (!hasAccess) {
    this.router.navigate(['/central']);
    return false;
  }
  return true;
}
AccesopasajeroGuard - Control de Acceso a Pasajeros
Módulo Específico

Propósito: Valida acceso al módulo de gestión de pasajeros.

Características:

  • Verifica permisos específicos para el módulo /pasajeros
  • Si el permiso no coincide → redirección a /central/clientes
  • Mantiene al usuario dentro de módulos permitidos

5.3.2 Tabla Resumen de Guards

Guard Tipo de Validación Función Principal
AccesocentralGuard Sesión/Token Determina si el usuario está autenticado
AccesochildGuard Permisos/Rutas Hijas Determina si puede acceder a un módulo específico
AccesoparametrizacionGuard Rol/Privilegios Restringe acceso a configuración del sistema
AccesoOrdenServicioGuard Permisos Específicos Valida acceso a órdenes de servicio
AccesopasajeroGuard Módulo Específico Controla acceso al módulo de pasajeros

5.4 Directorio models

Propósito

Define las estructuras de datos del sistema mediante interfaces y modelos TypeScript.

Funciones:

  • Representar entidades del dominio
  • Garantizar consistencia tipada
  • Facilitar la comunicación entre componentes y servicios
  • Documentar la estructura de datos
  • Habilitar autocompletado en el IDE

Ejemplo de modelo:

TypeScript models/usuario.model.ts
// models/usuario.model.ts
export interface Usuario {
  id: number;
  nombreUsuario: string;
  email: string;
  rol: string;
  activo: boolean;
  fechaCreacion: Date;
}

Beneficios:

  • Type safety en tiempo de desarrollo
  • Detección temprana de errores
  • Mejor mantenibilidad del código
  • Documentación implícita de la estructura de datos

5.5 Directorio services

Propósito

Capa encargada de la comunicación con el backend y lógica de negocio compartida.

Responsabilidades:

  • Comunicación HTTP con APIs backend
  • Manejo de lógica de negocio compleja
  • Gestión de tokens de autenticación
  • Control de loaders y spinners
  • Validaciones de negocio
  • Almacenamiento temporal de datos
  • Funciones reutilizables entre componentes
  • Manejo de estado de la aplicación

Generación de servicios:

bash
ng generate service services/nombre-del-servicio
# o forma corta:
ng g s services/nombre

Ejemplo de servicio:

TypeScript
@Injectable({
  providedIn: 'root'
})
export class UsuarioService {
  constructor(private http: HttpClient) {}
  
  obtenerUsuarios(): Observable<Usuario[]> {
    return this.http.get<Usuario[]>(`${API_URL}/usuarios`);
  }
}
06

Configuración y Routing

6.1 App Routing Module

Archivo: app-routing.module.ts

Propósito

Define la estructura de navegación del sistema, controlando qué componente cargar según la URL.

Funcionalidades:

  • Asignación de guards para control de acceso
  • Definición de rutas hijas
  • Separación entre rutas públicas y privadas
  • Lazy loading de módulos
  • Redirecciones y rutas por defecto

6.1.1 Rutas Públicas (Acceso Sin Autenticación)

Ruta Componente Uso
"" (raíz) LoginComponent Ruta inicial, ingreso al sistema
/encuesta EncuestaComponent Acceso directo al formulario de encuesta
/fuecInfo/:qr InformacionFuecQRComponent Consulta información desde código QR
/recoverypass PassrecupComponent Recuperación de contraseña vía correo
/changepass/:id ChangepassComponent Cambio de contraseña con token

6.1.2 Rutas Privadas Principales (Requieren Autenticación)

Ruta Componente Uso
/central PlantillaComponent Módulo funcional principal del sistema post-login

Protección de rutas: Todas las rutas privadas están protegidas con múltiples guards según el nivel de acceso:

  • AccesocentralGuard: Validación de sesión activa
  • AccesochildGuard: Permisos para módulos específicos
  • AccesoparametrizacionGuard: Acceso a configuración
  • AccesopasajeroGuard: Acceso al módulo de pasajeros

Estructura de routing con guards:

TypeScript
{
  path: 'central',
  component: PlantillaComponent,
  canActivate: [AccesocentralGuard],
  children: [
    {
      path: 'modulo',
      component: ModuloComponent,
      canActivate: [AccesochildGuard]
    }
  ]
}

6.2 Environments

Propósito

Gestionar configuraciones específicas para diferentes entornos de ejecución.

6.2.1 Archivos de Configuración

Archivo Propósito
environment.ts Configuración por defecto para desarrollo (uso con ng serve)
environment.prod.ts Configuración para producción (uso con ng build --prod)

Contenido típico:

TypeScript
export const environment = {
  production: false,
  apiUrl: 'http://localhost:8080/api',
  tokenKey: 'auth_token',
  apiTimeout: 30000
};

6.2.2 Sustitución de Archivos

La sustitución de environment.ts por environment.prod.ts se configura en angular.json:

JSON
"fileReplacements": [
  {
    "replace": "src/environments/environment.ts",
    "with": "src/environments/environment.prod.ts"
  }
]

Flujo:

  • Desarrollo: ng serve → usa environment.ts
  • Producción: ng build --prod → usa environment.prod.ts

6.3 Angular.json

Propósito

Archivo de configuración principal que controla cómo Angular CLI compila, sirve y construye la aplicación.

Importancia

Este archivo afecta directamente al proceso de construcción y estructura final del proyecto. Debe modificarse con precaución.

6.3.1 Secciones Principales

Sección Propósito
projects Define aplicaciones y librerías del workspace
architect → build Configuración del proceso de compilación (sección más crítica)
assets / styles / scripts Archivos estáticos, CSS globales y scripts externos
fileReplacements Sustitución de archivos según entorno
serve Configuración para desarrollo local
configurations: production Optimizaciones para build productivo

6.3.2 Configuración de Build

Elementos clave:

JSON
{
  "build": {
    "builder": "@angular-devkit/build-angular:browser",
    "options": {
      "outputPath": "dist/frontend",
      "index": "src/index.html",
      "main": "src/main.ts",
      "assets": [
        "src/favicon.ico",
        "src/assets"
      ],
      "styles": [
        "src/styles.css"
      ],
      "scripts": []
    }
  }
}

Configuraciones de producción:

  • optimization: true
  • sourceMap: false
  • extractCss: true
  • buildOptimizer: true
  • aot: true (Ahead of Time compilation)
07

Seguridad y Control de Acceso

7.1 Estrategia de Autenticación

El sistema implementa autenticación basada en tokens JWT (JSON Web Tokens) con las siguientes características:

Flujo de autenticación:

1 Usuario envía credenciales
2 Backend valida y retorna JWT
3 Frontend almacena token
4 Token en cada petición HTTP
5 Guards validan token

Ventajas:

  • Stateless (sin sesión en servidor)
  • Escalable horizontalmente
  • Compatible con microservicios
  • Permite expiración automática

7.2 Guards Implementados

El sistema cuenta con 5 guards principales que trabajan en conjunto para proporcionar seguridad multinivel:

  1. AccesocentralGuard: Primera línea de defensa (sesión válida)
  2. AccesochildGuard: Segunda capa (permisos por módulo)
  3. AccesoparametrizacionGuard: Protección de configuración crítica
  4. AccesoOrdenServicioGuard: Control granular por registro
  5. AccesopasajeroGuard: Aislamiento de módulos sensibles

7.3 Gestión de Tokens

Almacenamiento:

  • Token guardado en localStorage para persistencia
  • Renovación automática antes de expiración
  • Eliminación al cerrar sesión

Validación:

  • Verificación de expiración en cada navegación
  • Validación de firma contra backend
  • Cierre automático de sesión si el token es inválido

Interceptores HTTP:

Recomendación de uso

Es altamente recomendable implementar un HttpInterceptor para gestionar automáticamente el envío del token en todas las peticiones HTTP. Esto evita repetir lógica en los servicios, mejora la organización interna del proyecto y asegura una aplicación más consistente y segura.

Ventajas:

  • Centraliza la lógica de autenticación y encabezados.
  • Reduce la duplicación de código en los servicios.
  • Permite manejo global de errores como 401 o 403.
  • Facilita implementar refresh tokens laterales.

En general, el uso de interceptores es una buena práctica esencial en Angular, especialmente en aplicaciones que manejan autenticación basada en tokens o múltiples servicios REST.

TypeScript
@Injectable()
  export class AuthInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler) {
      const token = this.authService.getToken();
      if (token) {
        req = req.clone({
          setHeaders: { Authorization: `Bearer ${token}` }
        });
      }
      return next.handle(req);
    }
}
              
08

Pruebas y Calidad

8.1 Tipos de Pruebas

Pruebas Unitarias

  • Framework: Jasmine
  • Runner: Karma
  • Cobertura objetivo: >80%

Pruebas E2E

  • Framework histórico: Protractor (deprecado)
  • Alternativas modernas: Cypress, Playwright
  • Estado: Por implementar

8.2 Ejecución de Pruebas

bash
# Pruebas unitarias
ng test

# Pruebas con cobertura
ng test --code-coverage

# Pruebas E2E (si están configuradas)
ng e2e
9

Buenas Prácticas

9.1 Código

  • Seguir la guía de estilos oficial de Angular
  • Usar TypeScript en modo strict
  • Implementar Lazy Loading para módulos grandes
  • Evitar lógica de negocio en componentes
  • Usar OnPush change detection cuando sea posible

9.2 Componentes

  • Un componente, una responsabilidad
  • Componentes pequeños y reutilizables
  • Comunicación padre-hijo vía @Input/@Output
  • Uso de servicios para estado compartido

9.3 Servicios

  • Servicios singleton con providedIn: 'root'
  • Manejo de errores consistente
  • Uso de RxJS operators para transformación de datos
  • Implementar retry logic para peticiones HTTP
10

Despliegue

10.1 Build de Producción

bash
ng build --prod

Optimizaciones aplicadas:

  • Minificación de código
  • Tree shaking (eliminación de código no usado)
  • AOT compilation
  • Lazy loading de módulos
  • Compresión de assets

10.2 Configuración de Servidor

Nginx ejemplo:

nginx
server {
  listen 80;
  server_name example.com;
  root /var/www/frontend/dist/frontend;
  index index.html;
  
  location / {
    try_files $uri $uri/ /index.html;
  }
}
11

Referencias

12

Anexos

Anexo A: Comandos CLI Útiles

bash
# Desarrollo
ng serve                          # Iniciar servidor de desarrollo
ng serve --port 4200             # Especificar puerto
ng serve --open                  # Abrir navegador automáticamente

# Generación de Código
ng g c components/nombre         # Generar componente
ng g s services/nombre           # Generar servicio
ng g guard guards/nombre         # Generar guard
ng g module modules/nombre       # Generar módulo
ng g interface models/nombre     # Generar interface

# Build
ng build                         # Build de desarrollo
ng build --prod                  # Build de producción
ng build --prod --aot            # Build con AOT compilation

# Pruebas
ng test                          # Ejecutar pruebas unitarias
ng test --code-coverage          # Pruebas con reporte de cobertura
ng e2e                           # Ejecutar pruebas E2E

# Análisis
ng lint                          # Ejecutar linter
ng build --prod --stats-json     # Generar estadísticas de bundle

Anexo B: Estructura de Componente Completa

TypeScript ejemplo.component.ts
// ejemplo.component.ts
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { EjemploService } from '../../services/ejemplo.service';

@Component({
  selector: 'app-ejemplo',
  templateUrl: './ejemplo.component.html',
  styleUrls: ['./ejemplo.component.css']
})
export class EjemploComponent implements OnInit {
  @Input() datos: any;
  @Output() accionRealizada = new EventEmitter<any>();

  constructor(private ejemploService: EjemploService) { }

  ngOnInit(): void {
    this.cargarDatos();
  }

  cargarDatos(): void {
    this.ejemploService.obtenerDatos().subscribe(
      response => {
        // Manejar respuesta exitosa
      },
      error => {
        // Manejar error
      }
    );
  }

  ejecutarAccion(): void {
    this.accionRealizada.emit({ tipo: 'accion', datos: this.datos });
  }
}

Anexo C: Ejemplo de Servicio HTTP

TypeScript ejemplo.service.ts
// ejemplo.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, map, retry } from 'rxjs/operators';
import { environment } from '../../environments/environment';

@Injectable({
  providedIn: 'root'
})
export class EjemploService {
  private apiUrl = environment.apiUrl;

  constructor(private http: HttpClient) { }

  obtenerDatos(): Observable<any[]> {
    return this.http.get<any[]>(`${this.apiUrl}/datos`).pipe(
      retry(2),
      catchError(this.handleError)
    );
  }

  crearRegistro(datos: any): Observable<any> {
    const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
    return this.http.post(`${this.apiUrl}/datos`, datos, { headers }).pipe(
      catchError(this.handleError)
    );
  }

  actualizarRegistro(id: number, datos: any): Observable<any> {
    return this.http.put(`${this.apiUrl}/datos/${id}`, datos).pipe(
      catchError(this.handleError)
    );
  }

  eliminarRegistro(id: number): Observable<any> {
    return this.http.delete(`${this.apiUrl}/datos/${id}`).pipe(
      catchError(this.handleError)
    );
  }

  private handleError(error: any): Observable<never> {
    console.error('Error en la petición:', error);
    return throwError('Ocurrió un error en la operación');
  }
}

Anexo D: Ejemplo de Guard Completo

TypeScript auth.guard.ts
// auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router }
from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  
  constructor(
    private authService: AuthService,
    private router: Router
  ) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean> | boolean {
    
    const token = this.authService.getToken();
    
    if (!token) {
      this.router.navigate(['/login']);
      return false;
    }

    if (this.authService.isTokenExpired(token)) {
      this.authService.logout();
      this.router.navigate(['/login']);
      return false;
    }

    return true;
  }
}

Anexo E: Configuración de Interceptor HTTP

TypeScript auth.interceptor.ts
// auth.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  
  constructor(private authService: AuthService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = this.authService.getToken();
    
    if (token) {
      const clonedRequest = req.clone({
        headers: req.headers.set('Authorization', `Bearer ${token}`)
      });
      return next.handle(clonedRequest);
    }
    
    return next.handle(req);
  }
}