Verificando autenticación…

Skip to main content

NestJS Template

Purpose and Scope

This project is a Backend For Frontend (BFF) developed with NestJS. Its main purpose is to serve as an aggregation and adaptation layer between frontend services and various backend services of the EMX_STPLANNG system.

Problem it solves: It simplifies communication for frontend clients by providing a single interface that orchestrates and consolidates data from multiple backend microservices. This reduces complexity on the client side and optimizes network requests.

Project scope:

  • Exposure of RESTful API endpoints for frontend consumption.
  • Integration with backend services such as ehvypln-chain-management-be, ehvypln-journey, and ehvypln-om-be.
  • Management of presentation logic and data aggregation.
  • Processing of Kafka messages (e.g., for alerts).
  • Interaction with Google Cloud Firestore for specific data storage (e.g., alerts, aircraft messages).
  • Authentication and authorization of requests through Azure AD.
  • Environment-based configuration management.
  • Observability through OpenTelemetry.

Architecture

The project follows a modular architecture based on the NestJS framework, implementing the Backend For Frontend (BFF) pattern.

Main Components:

  • API Gateway (Cloud Endpoints): Manages public API exposure, authentication, and other policies.
  • NestJS Application (ehvypln-bff):
    • Controllers: Expose HTTP endpoints and handle requests/responses.
    • Services: Contain business logic, orchestration of calls to other services, and data processing.
    • Infrastructure Modules:
      • Kafka: To consume messages from specific topics (e.g., alerts).
      • Firestore: Client to interact with the Firestore database.
      • HTTP Client (Axios): To communicate with other REST services.
      • OpenTelemetry: For tracing and metrics.
      • Mongoose: To interact with MongoDB (main application database, inferred from MONGO_CONNECTION_STRING).

External Dependencies (Backend Services): According to catalog-info.yml, the BFF depends on:

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

Typical Data Flow:

  1. A frontend client makes a request to the endpoint exposed by Google Cloud Endpoints.
  2. Cloud Endpoints validates authentication (e.g., Azure AD token) and forwards the request to the ehvypln-bff service in GKE.
  3. A NestJS controller receives the request.
  4. The corresponding service processes the request, possibly:
    • Making HTTP calls to one or more backend services.
    • Querying or saving data in Firestore.
    • Querying or saving data in MongoDB.
  5. The service consolidates the response and returns it to the controller.
  6. The controller sends the HTTP response to the client.

Architecture Diagram: Ideally, a link to a visual architecture diagram would be placed here. ![Architecture Diagram](https://enlace-al-diagrama-de-arquitectura.com/diagrama.png)

Technologies and Dependencies

  • Language: TypeScript
  • Runtime: Node.js 18 (based on Dockerfile and package.json)
  • Framework: NestJS (@nestjs/core, @nestjs/common, etc.)
  • Package Manager: npm
  • Database (Primary): MongoDB (through Mongoose, per .env.example and dependencies)
  • Database (Secondary/Specific storage): Google Cloud Firestore (@google-cloud/firestore)
  • Asynchronous Messaging: Apache Kafka (kafkajs, @nestjs/microservices)
  • Cache: Redis (cache-manager-redis-yet, @nestjs/cache-manager)
  • HTTP Client: Axios (@nestjs/axios)
  • Authentication: Azure AD (passport-azure-ad, @nestjs/passport)
  • API Documentation: Swagger (@nestjs/swagger)
  • Configuration Management: @nestjs/config, dotenv, envalid
  • HTTP Security: Helmet
  • Observability: OpenTelemetry (@opentelemetry/*)
  • Feature Flags: Unleash (unleash-client)
  • Containerization: Docker
  • Orchestration (Deployment): Google Kubernetes Engine (GKE) via Helm (based on deploy/)
  • CI/CD: Jenkins (based on Jenkinsfile)
  • Testing: Jest, Supertest, ts-jest, Testcontainers
  • Linting/Formatting: ESLint, Prettier

Local Setup

Prerequisites

  • Node.js v18.15.0 or higher
  • npm (usually included with Node.js)
  • NestJS CLI globally: npm i -g @nestjs/cli
  • Docker and Docker Compose

Setup Steps

  1. Clone the repository: Follow these steps

  2. Install project dependencies:

    npm install
  3. Configure local environment variables: Copy the example file and, if necessary, adjust the values for the local environment.

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

    Important values in environments/local.env for local development (the default values in .env.example are usually suitable for the Docker Compose setup):

    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
    # ... among others.
  4. Start dependent services (Kafka, Firestore Emulator, Redis, etc.): From the project root, run:

    docker-compose up -d

    This will start the services defined in docker-compose.yml.

  5. Run the application in local mode with auto-reload:

    npm run start:local

    The BFF application will be available at http://localhost:5000 (or the port defined in process.env.PORT). The global prefix is /bff.

Deployment

The deployment of ehvypln-bff is performed on Google Kubernetes Engine (GKE) and is managed by Jenkins pipelines.

Jenkins Pipeline

The Jenkinsfile uses the pipelineLatamEMX("gke-krane-nestjs") pipeline to orchestrate the build and deployment.

Environment Configuration

The project uses Helm for Kubernetes deployments. Environment-specific configuration for each environment (dev, intg, cert, prod) is found in the values.yaml.erb files within the deploy/helm/<environment>/ folders. These files define:

  • Number of replicas.
  • Resources (CPU, memory).
  • Environment-specific environment variables.
  • Google Cloud Endpoints configuration (service name, ESPv2 image).
  • Cloud SQL Proxy connection (although the app uses Mongo, the deployment template includes Cloud SQL Proxy).
  • Whether spot nodes or GKE Autopilot Compute Class are used.

General Deployment Process

  1. Docker Image Build: The Jenkins pipeline builds the Docker image using the project's Dockerfile.
  2. Image Publishing: The image is tagged and published to a container registry (e.g., Google Container Registry - GCR).
  3. Helm Deployment: Krane (internal tool) or Helm directly uses the Helm templates (located in deploy/helm/emx-helm-chart/ - inferred) and the target environment's values.yaml.erb file to generate Kubernetes manifests.
  4. GKE Application: The manifests are applied to the corresponding GKE cluster.
  5. Cloud Endpoints Configuration: The Google Cloud Endpoints service is configured using the OpenAPI definition in deploy/endpoints/openapi.yaml.erb to expose the API.

API Endpoints

The API is exposed with a global prefix /bff. Swagger UI documentation is available at the /bff/api/description route (relative to the deployed service host).

MethodRoute (after /bff)DescriptionSuggested Authentication
GET/api/healthzApplication health check endpoint.None or API Key
GET/crf/bff/get/{id}Finds a "chain" based on the provided ID.Azure AD Token
GET/testTest endpoint without parameters.Azure AD Token
GET/test/{id}Test endpoint that receives an ID.Azure AD Token

Authentication

The service supports several authentication mechanisms defined in deploy/endpoints/openapi.yaml.erb and managed by Google Cloud Endpoints:

  • API Key (api_key): To identify the calling project.
  • Google ID Token (google_id_token): For users authenticated with Google accounts.
  • Service Account JWT (serviceaccount_jwt): For service-to-service authentication.
  • Azure AD Token (azure_id_token): Main mechanism used by the application to authenticate users through tokens issued by Azure AD.

The backend (NestJS) uses passport-azure-ad to validate Azure AD tokens.

Specific Components

MongoDB (with Mongoose)

  • Purpose: Primary data persistence for the application.
  • Configuration: Through the MONGO_CONNECTION_STRING environment variable. For local development with docker-compose.yml (if the postgres service is actually MongoDB or if a MongoDB service is added), something like mongodb://localhost:27017/ehvypln-bff-db would be used. The .env.example template suggests MONGO_CONNECTION_STRING="mongodb://localhost".
  • NestJS Modules: @nestjs/mongoose, MongooseModule.
  • Implementation: Definition of Mongoose Schemas and Models for application entities (e.g., Test).

Kafka

  • Purpose: Consumption of topic messages for asynchronous processing (e.g., receiving alerts).
  • Configuration:
    • Main environment variables: KAFKA_BROKER, KAFKA_ALERT_CLIENT_ID, KAFKA_ALERT_CONSUMER_GROUP, ALERTS_TOPIC.
    • For production environments, SSL and SASL (PLAIN) are configured through KAFKA_USERNAME and KAFKA_PASSWORD.
    • Locally, the Kafka broker (kafka0) and Kafka UI are defined in docker-compose.yml.
  • NestJS Modules: KafkaModule (customized in src/infra/kafka/), ClientsModule from @nestjs/microservices, kafkajs.
  • Implementation:
    • src/infra/kafka/kafka.utils.ts provides the logic to generate the Kafka client configuration.
    • src/infra/kafka/kafka-decorator-processor.service.ts enables the use of the @KafkaTopic decorator to bind controller methods to Kafka topics dynamically.
    • Example usage in src/alerts/controller/alerts.controller.ts which consumes from the ALERTS_TOPIC topic.

Google Cloud Firestore

  • Purpose: NoSQL storage for specific data such as alerts and aircraft messages.
  • Configuration:
    • Environment variables: PROJECT_ID, FIRESTORE_EMULATOR_HOST (for local development).
    • Locally, the Firestore emulator defined in docker-compose.yml is used (firestore_emulator service on [::1]:8200).
    • Collections used: ALERTS_FIRESTORE_COLLECTION, AIRCRAFT_MESSAGES_FIRESTORE_COLLECTION.
  • Implementation:
    • src/infra/firestore/firestore.client.ts provides a customized client to interact with Firestore.
    • This client is injected and used in services such as AlertsService.

Redis (Cache)

  • Purpose: Cache storage to improve application performance.
  • Configuration:
    • Locally, the Redis service is started by docker-compose.yml and accessible at localhost:6379.
  • NestJS Modules: @nestjs/cache-manager, CacheModule.
  • Implementation: The NestJS CacheModule is used, configured with cache-manager-redis-yet, for standard caching operations (get, set, delete).

OpenTelemetry (Observability)

  • Purpose: Collection and export of traces and metrics for monitoring and debugging.
  • Configuration:
    • Environment variables for export (e.g., to Honeycomb): HONEYCOMB_URL, HONEYCOMB_API_KEY.
  • Implementation:
    • Initialization and configuration in src/infra/telemetry/opentelemetry/open-telemetry.ts.
    • Automatically instruments HTTP, Express, and NestJS.
    • Uses OTLPTraceExporter to send trace data.

Testing

The project uses Jest as the testing framework.

Test Types

  • Unit Tests (*.spec.ts): Test isolated units of code (classes, functions).
  • End-to-End Tests (*.e2e-spec.ts): Test the complete application flow through its HTTP endpoints. They use supertest and Testcontainers for a more realistic test environment.

Commands to Run Tests

  • Run all tests (unit and integration):
    npm run test
  • Run tests in watch mode:
    npm run test:watch
  • Generate test coverage report:
    npm run test:cov
    The report is generated in the coverage/ directory.
  • Run E2E tests:
    npm run test:e2e
    The specific E2E configuration is found in test/jest-e2e.json.
  • Debug tests:
    npm run test:debug

Test Configuration

  • General Jest configuration in package.json (jest section).
  • E2E configuration in test/jest-e2e.json.
  • Additional Jest setup (mocks, etc.) in src/test/setup-jest.ts.

Linting and Formatting

The project uses ESLint and Prettier to maintain code quality and consistency. These run as a pre-commit hook configured with Husky and lint-staged (.husky/pre-commit).

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

Security Considerations

  • Helmet: Used to configure various HTTP headers that help protect the application from common web vulnerabilities.
  • Azure AD Authentication: User authentication is primarily handled through JWT tokens issued by Azure AD, validated using passport-azure-ad (see src/auth/azure-ad.strategy.ts and AzureADGuard).
  • CORS (Cross-Origin Resource Sharing): Configured in src/main.ts to allow requests from specific origins, preventing CSRF and other origin-related attacks.
  • Secret Management:
    • Credentials and API keys (e.g., KAFKA_PASSWORD, HONEYCOMB_API_KEY) are managed as secrets.
  • In local development, they are loaded from environments/local.env (which should not be committed if it contains real secrets).
    • In deployed environments (GKE), secrets are managed by Kubernetes Secrets, referenced in the Helm values.yaml.erb files.
  • Input Validation: class-validator and NestJS ValidationPipe are used to validate DTOs and input payloads, preventing attacks based on malformed data.
  • Google Cloud Endpoints: Acts as an API Gateway layer, able to apply additional security policies, quotas, and authentication before requests reach the backend.