Verificando autenticación…

Saltar al contenido principal

Template NestJS

Propósito y Alcance

Este proyecto, es un Backend For Frontend (BFF) desarrollado con NestJS. Su propósito principal es servir como una capa de agregación y adaptación entre los servicios frontend y diversos servicios backend del sistema EMX_STPLANNG.

Problema que resuelve: Simplifica la comunicación para los clientes frontend al proporcionar una única interfaz que orquesta y consolida datos de múltiples microservicios backend. Esto reduce la complejidad en el lado del cliente y optimiza las peticiones de red.

Alcance del proyecto:

  • Exposición de endpoints API RESTful para consumo de los frontends.
  • Integración con servicios backend como ehvypln-chain-management-be, ehvypln-journey, y ehvypln-om-be.
  • Gestión de la lógica de presentación y agregación de datos.
  • Procesamiento de mensajes de Kafka (ej. para alertas).
  • Interacción con Google Cloud Firestore para almacenamiento de datos específicos (ej. alertas, mensajes de aeronaves).
  • Autenticación y autorización de peticiones mediante Azure AD.
  • Manejo de configuración por entorno.
  • Observabilidad a través de OpenTelemetry.

Arquitectura

El proyecto sigue una arquitectura modular basada en el framework NestJS, implementando el patrón Backend For Frontend (BFF).

Componentes Principales:

  • API Gateway (Cloud Endpoints): Gestiona la exposición pública de la API, autenticación, y otras políticas.
  • Aplicación NestJS (ehvypln-bff):
    • Controladores: Exponen los endpoints HTTP y manejan las solicitudes/respuestas.
    • Servicios: Contienen la lógica de negocio, orquestación de llamadas a otros servicios, y procesamiento de datos.
    • Módulos de Infraestructura:
      • Kafka: Para consumir mensajes de tópicos específicos (ej. alertas).
      • Firestore: Cliente para interactuar con la base de datos Firestore.
      • HTTP Client (Axios): Para comunicarse con otros servicios REST.
      • OpenTelemetry: Para tracing y métricas.
      • Mongoose: Para interactuar con MongoDB (base de datos principal de la aplicación, inferido por MONGO_CONNECTION_STRING).

Dependencias Externas (Servicios Backend): Según catalog-info.yml, el BFF depende de:

  • api:ehvypln-chain-management-be
  • api:ehvypln-journey
  • api:ehvypln-om-be

Flujo de Datos Típico:

  1. Un cliente frontend realiza una petición al endpoint expuesto por Google Cloud Endpoints.
  2. Cloud Endpoints valida la autenticación (ej. Azure AD token) y redirige la petición al servicio ehvypln-bff en GKE.
  3. Un controlador NestJS recibe la petición.
  4. El servicio correspondiente procesa la solicitud, posiblemente:
    • Realizando llamadas HTTP a uno o más servicios backend.
    • Consultando o guardando datos en Firestore.
    • Consultando o guardando datos en MongoDB.
  5. El servicio consolida la respuesta y la devuelve al controlador.
  6. El controlador envía la respuesta HTTP al cliente.

Diagrama de Arquitectura: Idealmente, aquí se enlazaría a un diagrama visual de la arquitectura. ![Diagrama de Arquitectura](https://enlace-al-diagrama-de-arquitectura.com/diagrama.png)

Tecnologías y Dependencias

  • Lenguaje: TypeScript
  • Runtime: Node.js 18 (basado en Dockerfile y package.json)
  • Framework: NestJS (@nestjs/core, @nestjs/common, etc.)
  • Gestor de Paquetes: npm
  • Base de Datos (Principal): MongoDB (a través de Mongoose, según .env.example y dependencias)
  • Base de Datos (Secundaria/Almacenamiento específico): Google Cloud Firestore (@google-cloud/firestore)
  • Mensajería Asíncrona: Apache Kafka (kafkajs, @nestjs/microservices)
  • Cache: Redis (cache-manager-redis-yet, @nestjs/cache-manager)
  • Cliente HTTP: Axios (@nestjs/axios)
  • Autenticación: Azure AD (passport-azure-ad, @nestjs/passport)
  • Documentación API: Swagger (@nestjs/swagger)
  • Gestión de Configuración: @nestjs/config, dotenv, envalid
  • Seguridad HTTP: Helmet
  • Observabilidad: OpenTelemetry (@opentelemetry/*)
  • Feature Flags: Unleash (unleash-client)
  • Containerización: Docker
  • Orquestación (Despliegue): Google Kubernetes Engine (GKE) mediante Helm (basado en deploy/)
  • CI/CD: Jenkins (basado en Jenkinsfile)
  • Testing: Jest, Supertest, ts-jest, Testcontainers
  • Linting/Formatting: ESLint, Prettier

Configuración Local

Prerrequisitos

  • Node.js v18.15.0 o superior
  • npm (generalmente incluido con Node.js)
  • NestJS CLI global: npm i -g @nestjs/cli
  • Docker y Docker Compose

Pasos de Configuración

  1. Clonar el repositorio: Sigue los siguientes pasos

  2. Instalar dependencias del proyecto:

    npm install
  3. Configurar variables de entorno locales: Copiar el archivo de ejemplo y, si es necesario, ajustar los valores para el entorno local.

    cp .env.example ./environments/local.env

    Valores importantes en environments/local.env para desarrollo local (los valores por defecto en .env.example suelen ser adecuados para el setup con Docker Compose):

    FIRESTORE_EMULATOR_HOST=[::1]:8200
    PROJECT_ID=dummy-project-id
    KAFKA_BROKER=localhost:9092
    MONGO_CONNECTION_STRING="mongodb://localhost"
    DB_HOST=127.0.0.1
    DB_USERNAME=admin
    DB_PASSWORD=1234
    DB_NAME=test
    # ... entre otros.
  4. Iniciar servicios dependientes (Kafka, Firestore Emulator, Redis, etc.): Desde la raíz del proyecto, ejecutar:

    docker-compose up -d

    Esto levantará los servicios definidos en docker-compose.yml.

  5. Ejecutar la aplicación en modo local con auto-recarga:

    npm run start:local

    La aplicación BFF estará disponible en http://localhost:5000 (o el puerto definido en process.env.PORT). El global prefix es /bff.

Despliegue

El despliegue de ehvypln-bff se realiza en Google Kubernetes Engine (GKE) y es gestionado por pipelines de Jenkins.

Pipeline de Jenkins

El Jenkinsfile utiliza la pipeline pipelineLatamEMX("gke-krane-nestjs") para orquestar el build y despliegue.

Configuración por Entorno

El proyecto utiliza Helm para los despliegues en Kubernetes. La configuración específica para cada entorno (dev, intg, cert, prod) se encuentra en los archivos values.yaml.erb dentro de las carpetas deploy/helm/<entorno>/. Estos archivos definen:

  • Número de réplicas.
  • Recursos (CPU, memoria).
  • Variables de entorno específicas del ambiente.
  • Configuración de Google Cloud Endpoints (nombre del servicio, imagen del ESPv2).
  • Conexión a Cloud SQL Proxy (aunque la app usa Mongo, el template de deployment incluye CloudSQL Proxy).
  • Si se usan nodos spot o GKE Autopilot Compute Class.

Proceso General de Despliegue

  1. Construcción de Imagen Docker: El pipeline de Jenkins construye la imagen Docker utilizando el Dockerfile del proyecto.
  2. Publicación de Imagen: La imagen se etiqueta y se publica en un registro de contenedores (ej. Google Container Registry - GCR).
  3. Despliegue con Helm: Krane (herramienta interna) o Helm directamente utiliza las plantillas de Helm (ubicadas en deploy/helm/emx-helm-chart/ - inferido) y el archivo values.yaml.erb del entorno destino para generar los manifiestos de Kubernetes.
  4. Aplicación en GKE: Los manifiestos se aplican al clúster de GKE correspondiente.
  5. Configuración de Cloud Endpoints: El servicio de Google Cloud Endpoints se configura utilizando la definición OpenAPI en deploy/endpoints/openapi.yaml.erb para exponer la API.

Endpoints de la API

La API se expone con un prefijo global /bff. La documentación Swagger UI está disponible en la ruta /bff/api/description (relativa al host del servicio desplegado).

MétodoRuta (después de /bff)DescripciónAutenticación Sugerida
GET/api/healthzEndpoint de chequeo de salud de la aplicación.Ninguna o API Key
GET/crf/bff/get/{id}Busca una "chain" (cadena) basada en el ID proporcionado.Azure AD Token
GET/testEndpoint de prueba sin parámetros.Azure AD Token
GET/test/{id}Endpoint de prueba que recibe un ID.Azure AD Token

Autenticación

El servicio soporta varios mecanismos de autenticación definidos en deploy/endpoints/openapi.yaml.erb y gestionados por Google Cloud Endpoints:

  • API Key (api_key): Para identificación del proyecto llamante.
  • Google ID Token (google_id_token): Para usuarios autenticados con cuentas Google.
  • Service Account JWT (serviceaccount_jwt): Para autenticación entre servicios.
  • Azure AD Token (azure_id_token): Mecanismo principal utilizado por la aplicación para autenticar usuarios mediante tokens emitidos por Azure AD.

El backend (NestJS) utiliza passport-azure-ad para validar los tokens de Azure AD.

Componentes Específicos

MongoDB (con Mongoose)

  • Propósito: Persistencia principal de datos para la aplicación.
  • Configuración: A través de la variable de entorno MONGO_CONNECTION_STRING. Para desarrollo local con docker-compose.yml (si el servicio postgres es en realidad un MongoDB o si se añade un servicio MongoDB), se usaría algo como mongodb://localhost:27017/ehvypln-bff-db. El template .env.example sugiere MONGO_CONNECTION_STRING="mongodb://localhost".
  • Módulos NestJS: @nestjs/mongoose, MongooseModule.
  • Implementación: Definición de Schemas y Models de Mongoose para las entidades de la aplicación (ej. Test).

Kafka

  • Propósito: Consumo de mensajes de tópicos para procesamiento asíncrono (ej. recepción de alertas).
  • Configuración:
    • Variables de entorno principales: KAFKA_BROKER, KAFKA_ALERT_CLIENT_ID, KAFKA_ALERT_CONSUMER_GROUP, ALERTS_TOPIC.
    • Para entornos productivos, se configura SSL y SASL (PLAIN) mediante KAFKA_USERNAME y KAFKA_PASSWORD.
    • Localmente, el broker Kafka (kafka0) y Kafka UI están definidos en docker-compose.yml.
  • Módulos NestJS: KafkaModule (customizado en src/infra/kafka/), ClientsModule de @nestjs/microservices, kafkajs.
  • Implementación:
    • src/infra/kafka/kafka.utils.ts provee la lógica para generar la configuración del cliente Kafka.
    • src/infra/kafka/kafka-decorator-processor.service.ts permite el uso del decorador @KafkaTopic para vincular métodos de controladores a tópicos de Kafka dinámicamente.
    • Ejemplo de uso en src/alerts/controller/alerts.controller.ts que consume del tópico ALERTS_TOPIC.

Google Cloud Firestore

  • Propósito: Almacenamiento NoSQL para datos específicos como alertas y mensajes de aeronaves.
  • Configuración:
    • Variables de entorno: PROJECT_ID, FIRESTORE_EMULATOR_HOST (para desarrollo local).
    • Localmente, se utiliza el emulador de Firestore definido en docker-compose.yml (servicio firestore_emulator en [::1]:8200).
    • Colecciones usadas: ALERTS_FIRESTORE_COLLECTION, AIRCRAFT_MESSAGES_FIRESTORE_COLLECTION.
  • Implementación:
    • src/infra/firestore/firestore.client.ts provee un cliente customizado para interactuar con Firestore.
    • Este cliente se inyecta y utiliza en servicios como AlertsService.

Redis (Cache)

  • Propósito: Almacenamiento en caché para mejorar el rendimiento de la aplicación.
  • Configuración:
    • Localmente, el servicio Redis es levantado por docker-compose.yml y accesible en localhost:6379.
  • Módulos NestJS: @nestjs/cache-manager, CacheModule.
  • Implementación: Se utiliza el CacheModule de NestJS, configurado con cache-manager-redis-yet, para operaciones de caching estándar (get, set, delete).

OpenTelemetry (Observabilidad)

  • Propósito: Recopilación y exportación de trazas y métricas para monitoreo y debugging.
  • Configuración:
    • Variables de entorno para exportación (ej. a Honeycomb): HONEYCOMB_URL, HONEYCOMB_API_KEY.
  • Implementación:
    • Inicialización y configuración en src/infra/telemetry/opentelemetry/open-telemetry.ts.
    • Instrumenta automáticamente HTTP, Express y NestJS.
    • Utiliza OTLPTraceExporter para enviar datos de trazas.

Pruebas

El proyecto utiliza Jest como framework de pruebas.

Tipos de Pruebas

  • Pruebas Unitarias (*.spec.ts): Prueban unidades aisladas de código (clases, funciones).
  • Pruebas End-to-End (*.e2e-spec.ts): Prueban el flujo completo de la aplicación a través de sus endpoints HTTP. Usan supertest y Testcontainers para un entorno de prueba más realista.

Comandos para Ejecutar Pruebas

  • Ejecutar todas las pruebas (unitarias y de integración):
    npm run test
  • Ejecutar pruebas en modo observador (watch mode):
    npm run test:watch
  • Generar reporte de cobertura de pruebas:
    npm run test:cov
    El reporte se genera en el directorio coverage/.
  • Ejecutar pruebas E2E:
    npm run test:e2e
    La configuración específica para E2E se encuentra en test/jest-e2e.json.
  • Debuggear pruebas:
    npm run test:debug

Configuración de Pruebas

  • Configuración general de Jest en package.json (sección jest).
  • Configuración E2E en test/jest-e2e.json.
  • Setup adicional para Jest (mocks, etc.) en src/test/setup-jest.ts.

Linting y Formato

El proyecto utiliza ESLint y Prettier para mantener la calidad y consistencia del código. Estos se ejecutan como un hook pre-commit configurado con Husky y lint-staged (.husky/pre-commit).

  • Lint: npm run lint
  • Format: npm run format

Consideraciones de Seguridad

  • Helmet: Se utiliza para configurar varias cabeceras HTTP que ayudan a proteger la aplicación de vulnerabilidades web comunes.
  • Autenticación Azure AD: La autenticación de usuarios se maneja principalmente mediante tokens JWT emitidos por Azure AD, validados usando passport-azure-ad (ver src/auth/azure-ad.strategy.ts y AzureADGuard).
  • CORS (Cross-Origin Resource Sharing): Configurado en src/main.ts para permitir solicitudes desde orígenes específicos, previniendo CSRF y otros ataques relacionados con el origen.
  • Gestión de Secretos:
    • Las credenciales y claves API (ej. KAFKA_PASSWORD, HONEYCOMB_API_KEY) se gestionan como secretos.
    • En desarrollo local, se cargan desde environments/local.env (que no debe ser comiteado si contiene secretos reales).
    • En entornos desplegados (GKE), los secretos son gestionados por Kubernetes Secrets, referenciados en los values.yaml.erb de Helm.
  • Validación de Entradas: Se utiliza class-validator y ValidationPipe de NestJS para validar los DTOs y payloads de entrada, previniendo ataques basados en datos malformados.
  • Google Cloud Endpoints: Actúa como una capa de API Gateway, pudiendo aplicar políticas de seguridad adicionales, cuotas y autenticación antes de que las solicitudes lleguen al backend.