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, andehvypln-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-beapi:ehvypln-journeyapi:ehvypln-om-be
Typical Data Flow:
- A frontend client makes a request to the endpoint exposed by Google Cloud Endpoints.
- Cloud Endpoints validates authentication (e.g., Azure AD token) and forwards the request to the
ehvypln-bffservice in GKE. - A NestJS controller receives the request.
- 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.
- The service consolidates the response and returns it to the controller.
- The controller sends the HTTP response to the client.
Architecture Diagram:
Ideally, a link to a visual architecture diagram would be placed here.

Technologies and Dependencies
- Language: TypeScript
- Runtime: Node.js 18 (based on
Dockerfileandpackage.json) - Framework: NestJS (
@nestjs/core,@nestjs/common, etc.) - Package Manager: npm
- Database (Primary): MongoDB (through Mongoose, per
.env.exampleand 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
-
Clone the repository: Follow these steps
-
Install project dependencies:
npm install -
Configure local environment variables: Copy the example file and, if necessary, adjust the values for the local environment.
cp .env.example ./environments/local.envImportant values in
environments/local.envfor local development (the default values in.env.exampleare usually suitable for the Docker Compose setup):FIRESTORE_EMULATOR_HOST=[::1]:8200PROJECT_ID=dummy-project-idKAFKA_BROKER=localhost:9092MONGO_CONNECTION_STRING="mongodb://localhost"DB_HOST=127.0.0.1DB_USERNAME=adminDB_PASSWORD=1234DB_NAME=test# ... among others. -
Start dependent services (Kafka, Firestore Emulator, Redis, etc.): From the project root, run:
docker-compose up -dThis will start the services defined in
docker-compose.yml. -
Run the application in local mode with auto-reload:
npm run start:localThe BFF application will be available at
http://localhost:5000(or the port defined inprocess.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
- Docker Image Build: The Jenkins pipeline builds the Docker image using the project's
Dockerfile. - Image Publishing: The image is tagged and published to a container registry (e.g., Google Container Registry - GCR).
- Helm Deployment: Krane (internal tool) or Helm directly uses the Helm templates (located in
deploy/helm/emx-helm-chart/- inferred) and the target environment'svalues.yaml.erbfile to generate Kubernetes manifests. - GKE Application: The manifests are applied to the corresponding GKE cluster.
- Cloud Endpoints Configuration: The Google Cloud Endpoints service is configured using the OpenAPI definition in
deploy/endpoints/openapi.yaml.erbto 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).
| Method | Route (after /bff) | Description | Suggested Authentication |
|---|---|---|---|
| GET | /api/healthz | Application health check endpoint. | None or API Key |
| GET | /crf/bff/get/{id} | Finds a "chain" based on the provided ID. | Azure AD Token |
| GET | /test | Test 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_STRINGenvironment variable. For local development withdocker-compose.yml(if thepostgresservice is actually MongoDB or if a MongoDB service is added), something likemongodb://localhost:27017/ehvypln-bff-dbwould be used. The.env.exampletemplate suggestsMONGO_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_USERNAMEandKAFKA_PASSWORD. - Locally, the Kafka broker (
kafka0) and Kafka UI are defined indocker-compose.yml.
- Main environment variables:
- NestJS Modules:
KafkaModule(customized insrc/infra/kafka/),ClientsModulefrom@nestjs/microservices,kafkajs. - Implementation:
src/infra/kafka/kafka.utils.tsprovides the logic to generate the Kafka client configuration.src/infra/kafka/kafka-decorator-processor.service.tsenables the use of the@KafkaTopicdecorator to bind controller methods to Kafka topics dynamically.- Example usage in
src/alerts/controller/alerts.controller.tswhich consumes from theALERTS_TOPICtopic.
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.ymlis used (firestore_emulatorservice on[::1]:8200). - Collections used:
ALERTS_FIRESTORE_COLLECTION,AIRCRAFT_MESSAGES_FIRESTORE_COLLECTION.
- Environment variables:
- Implementation:
src/infra/firestore/firestore.client.tsprovides 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.ymland accessible atlocalhost:6379.
- Locally, the Redis service is started by
- NestJS Modules:
@nestjs/cache-manager,CacheModule. - Implementation: The NestJS
CacheModuleis used, configured withcache-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.
- Environment variables for export (e.g., to Honeycomb):
- Implementation:
- Initialization and configuration in
src/infra/telemetry/opentelemetry/open-telemetry.ts. - Automatically instruments HTTP, Express, and NestJS.
- Uses
OTLPTraceExporterto send trace data.
- Initialization and configuration in
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 usesupertestandTestcontainersfor 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:
The report is generated in thenpm run test:cov
coverage/directory. - Run E2E tests:
The specific E2E configuration is found innpm run test:e2e
test/jest-e2e.json. - Debug tests:
npm run test:debug
Test Configuration
- General Jest configuration in
package.json(jestsection). - 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(seesrc/auth/azure-ad.strategy.tsandAzureADGuard). - CORS (Cross-Origin Resource Sharing): Configured in
src/main.tsto 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.
- Credentials and API keys (e.g.,
- 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.erbfiles.
- In deployed environments (GKE), secrets are managed by Kubernetes Secrets, referenced in the Helm
- Input Validation:
class-validatorand NestJSValidationPipeare 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.