broly-software-core
v1.2.3
Published
Library infra by Broly software
Readme
🗺️ Índice
- Broly Infra
- 📄 Requirements
- 🚀 Instalación
- 🌎 Publicación
- 📖 Project Structure
- Usage and Examples
- 📝 Environment Variables
- 🛠️ Scripts Disponibles
- 🚀 Deployment
- 😁 Authors
Broly Infra
NestJS is a utility and package library designed to simplify and standardize the development of microservices with a hexagonal or n-tier architecture, using NestJS and TypeScript. Package management is handled with pnpm, ensuring rapid installation and efficient use of disk space.
📄 Requirements
- Node.js >= 22.14.0
- pnpm >= 10.x
🚀 Installation
# Install dependencies
pnpm install
# Development
pnpm run start:dev
# Production
pnpm run start:prod
# Build
pnpm run build🌎 Publication
# Increase a version path (1.0.0) -> (1.0.1)
$ pnpm version patch
# Increase a minor version (1.0.0) -> (1.1.0)
$ pnpm version minor
# Increase a major version (1.0.0) -> (2.0.0)
$ pnpm version major
# Increase a specific version (1.0.0) -> (3.1.1)
$ pnpm version <version>
# Publish the package
$ pnpm publish📖 Project Structure
The repository is organized into two main directories:
libs/: Contains reusable modules and packages for various functionalities.src/: Includes the source code for how to use these libraries and how to test them.
[libs]/
├── [adapter]/ # [Adapters for external transport services, such as NATS, Kafka, SMTP, for microservices.]
├── [cdecorator]/ # [Provides custom decorators for NestJS.]
├── [common-cache]/ # [Functions for cache management, such as REDIS or local.]
├── [common-database]/ # [This module facilitates interaction with the database]
├── [common-encrypted]/ # [Utilities for data encryption and decryption.]
├── [common-http]/ # [Centralizes utilities for handling HTTP requests and responses]
├── [common-keyvault]/ # [Loads and injects secrets from a remote key vault provider (e.g. Infisical) into process.env at bootstrap time.]
├── [common-logger]/ # [Provides a unified logging system, crucial for application monitoring and debugging.]
├── [common-response]/ # [Standardized response structures for APIs, Events, such as success and error.]
├── [common-search]/ # [Advanced search logic, with respect to databases.]
├── [server-started]/ # [Centralizes and standardizes the NestJS application bootstrap (HTTP and NATS microservice).]
└── index.ts # [Main entry point]Usage/Examples
adapter
Adapters for external transport services, such as NATS, Kafka, SMTP, for microservices.
Use:
The way to inject the module:
natsTransport.module.ts
import { Module } from '@nestjs/common';
import { ClientsModule } from '@nestjs/microservices';
import { AdapterModule, Adapter } from 'caserita-infra/packages/adapter';
import { NATS_MS_SERVICE_INJECT } from '@app/utils/constants.util'
@Module({
imports: [
AdapterModule,
ClientsModule.registerAsync([
{
name: NATS_MS_SERVICE_INJECT,
useFactory: (adapter: Adapter) => {
const natsConfig = adapter.config();
return natsConfig;
},
inject: [Adapter],
},
]),
],
exports: [ClientsModule],
})
export class NatsTransportModule {}
How to use the module on the client:
caseritaTaxidentityvalidationMsEvent.client.ts
import { Inject, Injectable } from "@nestjs/common";
import { ConfigService } from '@nestjs/config';
import { ClientProxy } from '@nestjs/microservices';
import { firstValueFrom } from 'rxjs';
import { NATS_MS_SERVICE_INJECT } from '@app/utils/constants.util';
import { CaseritaTaxidentityvalidationMsService } from "@domain/caseritaTaxidentityvalidationMs.service";
import { CaseritaTaxidentityvalidationMsFindCompanyByRucRequest } from "@domain/interfaces/caseritaTaxidentityvalidationMsFindCompanyByRucRequest.interface";
import { CaseritaTaxidentityvalidationMsFindCompanyByRucResponse } from "@domain/interfaces/caseritaTaxidentityvalidationMsFindCompanyByRucResponse.interface";
@Injectable()
export class CaseritaTaxidentityvalidationMsEventClient implements CaseritaTaxidentityvalidationMsService {
private caseritaTaxIdentityValidationMsFindCompayByRuc: string;
private caseritaTaxIdentityValidationMsFindLegalRepresentativeByRuc: string;
private caseritaTaxIdentityValidationMsFindPersonByDni: string;
constructor(
private readonly configService: ConfigService,
@Inject(NATS_MS_SERVICE_INJECT) private readonly client: ClientProxy
) {
this.caseritaTaxIdentityValidationMsFindCompayByRuc = this.configService.get<string>('CASERITA_TAXIDENTITYVALIDATION_MS_FIND_COMPANY_BY_RUC');
this.caseritaTaxIdentityValidationMsFindLegalRepresentativeByRuc = this.configService.get<string>('CASERITA_TAXIDENTITYVALIDATION_MS_FIND_LEGAL_REPRESENTATIVE_BY_RUC');
this.caseritaTaxIdentityValidationMsFindPersonByDni = this.configService.get<string>('CASERITA_TAXIDENTITYVALIDATION_MS_FIND_PERSON_BY_DNI');
}
findCompanyByRuc(input: CaseritaTaxidentityvalidationMsFindCompanyByRucRequest): Promise<CaseritaTaxidentityvalidationMsFindCompanyByRucResponse> {
const { ruc } = input;
return firstValueFrom(this.client.send({ cmd: this.caseritaTaxIdentityValidationMsFindCompayByRuc }, { ruc }));
}
}
Environments:
This package uses the following variables:
.env .env.development.local
NATS_SERVERS="nats://localhost:4222"
cdecorator
Provides custom decorators for NestJS.
Use:
How to use the module on the controller:
store.controller.ts
import { Controller, Post } from '@nestjs/common';
import { CommandBus, QueryBus } from '@nestjs/cqrs';
import { ValidateBody } from 'caserita-infra/packages/cdecorator';
import { CreateCommandImpl } from '@app/commands/impl/create-command.impl';
import { CreateInputValidator } from '@infra/validators/create.input.validator';
import { CreateStoreRequest } from '@domain/interfaces/createStoreRequest.interface';
@Controller('stores')
export class StoreController {
constructor(
private readonly commandBus: CommandBus,
private readonly queryBus: QueryBus,
) {}
@Post('/create')
create(@ValidateBody(CreateInputValidator) input: CreateStoreRequest) {
return this.commandBus.execute(new CreateCommandImpl(input));
}
}
common-cache
Functions for cache management, such as REDIS or local.
Use:
The way to inject the module:
app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CommonCacheModule } from '@caserita/common-cache';
import { AppController } from './app.controller';
import { AppHandler } from './app.handler';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, cache: true }),
CommonCacheModule,
],
controllers: [AppController, AppHandler],
providers: [AppService, AppRepository],
})
export class AppModule {}
How to use the module on the service:
app.service.ts
import { ConfigService } from '@nestjs/config';
import { Injectable } from '@nestjs/common';
import { RedisCacheService } from '@caserita/common-cache';
import { AppRepository } from './app.repository';
@Injectable()
export class AppService {
private baseUrl: string;
constructor(
private readonly configService: ConfigService,
private readonly cacheService: RedisCacheService,
private readonly appRepository: AppRepository,
) {
this.baseUrl = this.configService.get<string>('BASE_URL_DATTEBAYO');
}
async getRedisCloud() {
return this.cacheService.get('HOLA:1236');
}
async setRedisCloud() {
await this.cacheService.set('HOLA:1239', { A: '1234', B: 'xyz' }, 300); //ttl 300 equivale a 5 minutos
}
}
Environments:
This package uses the following variables:
.env .env.development.local
REDIS_CLOUD_HOST=example.redis-cloud.com
REDIS_CLOUD_PORT=18472
REDIS_CLOUD_PASSWORD=vHqWgOtqqZXoA18km0Y76XiI4iNnr8DZ
REDIS_CLOUD_TTL= 300
REDIS_NUMBER_DB=
common-database
This module facilitates interaction with the database
Use:
The way to inject the module:
app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import {
CommonDatabaseModule,
DatabaseConnectionType,
DatabaseEnumType,
} from '@caserita/common-database';
// import { CommonCacheModule } from '@caserita/common-cache';
import { CommonEncryptedModule, EncryptedProviderType, ValueTransformer, HashTransformer } from '@caserita/common-encrypted';
import { AppController } from './app.controller';
import { AppHandler } from './app.handler';
import { EntityModule } from './entity/entity.module';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';
import { AppEntity } from './entity/app.entity';
import { AppPostgresEntity } from './entity/appPostgres.entity';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, cache: true }),
CommonDatabaseModule.register([
{
name: DatabaseConnectionType.MONGODB_CONNECTION,
type: DatabaseEnumType.MONGODB,
entities: [AppEntity],
},
{
name: DatabaseConnectionType.POSTGRES_CONNECTION,
type: DatabaseEnumType.POSTGES,
entities: [AppPostgresEntity],
// If you need to encrypt data in SQL
imports: [CommonEncryptedModule.register(EncryptedProviderType.DATABASE)],
inject: [ValueTransformer, HashTransformer],
columnsTransformers: ['fieldencrypt', 'fieldencrypt_index', 'fieldencrypttwo'],
},
]),
EntityModule,
],
controllers: [AppController, AppHandler],
providers: [AppService, AppRepository],
})
export class AppModule {}
How to use the module on the entity:
entity.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { DatabaseConnectionType } from '@caserita/common-database';
import { AppEntity } from './app.entity';
import { AppPostgresEntity } from './appPostgres.entity';
// The "forFeature" already creates the providers (the repositories)
const mongoRepositoryModule = TypeOrmModule.forFeature([AppEntity], DatabaseConnectionType.MONGODB_CONNECTION);
const postgresRepositoryModule = TypeOrmModule.forFeature([AppPostgresEntity], DatabaseConnectionType.POSTGRES_CONNECTION);
@Module({
imports: [mongoRepositoryModule, postgresRepositoryModule],
// This is where the change lies: you must export the entity classes that act as
// tokens for the repositories. This causes TypeOrmModule to expose the repositories
// created in the "imports" process.
exports: [mongoRepositoryModule, postgresRepositoryModule],
})
export class EntityModule {}
Environments:
This package uses the following variables:
.env .env.development.local
# MONGO DATABASE
DB_USER_MONGO=example
DB_KEY_MONGO=7247uriu2482rw247
DB_HOST_MONGO=example.mongodb.net
DB_CONTAINER_NAME_MONGO=cstainfradbdev
DB_SYNCHRONIZE_MONGO=true
# POSTGRES DATABASE
DB_HOST_POSTGRES=example.supabase.com
DB_PORT_POSTGRES=6543
DB_USERNAME_POSTGRES=postgres.qsyvlxmwyodpyevujbgx
DB_PASSWORD_POSTGRES=7247uriu2482rw247
DB_CONTAINER_NAME_POSTGRES=cstainfradbdev
DB_SYNCHRONIZE_POSTGRES=true
# ENCRYPTION DATBASE SQL
ENCRYPT_DATABASE_SECRET_KEY=xDkjHdp132nRLBjUOcvHGAJzb7dGmt
common-encrypted
Utilities for data encryption and decryption.
Use:
The way to inject the module:
app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CommonEncryptedModule, EncryptedProviderType } from '@caserita/common-encrypted';
import { AppController } from './app.controller';
import { AppHandler } from './app.handler';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, cache: true }),
CommonEncryptedModule.register(EncryptedProviderType.APP),
],
controllers: [AppController, AppHandler],
providers: [AppService, AppRepository],
})
export class AppModule {}
How to use the module on the service:
app.service.ts
import { ConfigService } from '@nestjs/config';
import { Injectable } from '@nestjs/common';
import { CipherEngine } from '@caserita/common-encrypted';
import { AppRepository } from './app.repository';
@Injectable()
export class AppService {
private baseUrl: string;
constructor(
private readonly configService: ConfigService,
private readonly cipherEngine: CipherEngine,
private readonly appRepository: AppRepository,
) {
this.baseUrl = this.configService.get<string>('BASE_URL_DATTEBAYO');
}
async encryption(entry: string) {
return this.cipherEngine.encrypt(entry);
}
async decryptyion(entry: string) {
return this.cipherEngine.decrypt(entry);
}
}
Environments:
This package uses the following variables:
.env .env.development.local
ENCRYPT_SECRET_KEY=WwMIK54FypnmSR1JPSCdcwxcwCl2cA
ENCRYPT_DATABASE_SECRET_KEY=xDkjHdp132nRLBjUOcvHGAJzb7dGmt
common-http
Centralizes utilities for handling HTTP requests and responses
Use:
The way to inject the module:
app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CommonHttpModule } from '@caserita/common-http';
import { AppController } from './app.controller';
import { AppHandler } from './app.handler';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, cache: true }),
CommonHttpModule,
],
controllers: [AppController, AppHandler],
providers: [AppService, AppRepository],
})
export class AppModule {}
How to use the module on the client:
app.service.ts
import { ConfigService } from '@nestjs/config';
import { HttpException, Injectable } from '@nestjs/common';
import { catchError, firstValueFrom } from 'rxjs';
import { AxiosError } from 'axios';
import { HttpClient } from '@caserita/common-http';
@Injectable()
export class AppService {
private baseUrl: string;
constructor(
private readonly httpClient: HttpClient,
private readonly configService: ConfigService,
) {
this.baseUrl = this.configService.get<string>('BASE_URL_DATTEBAYO');
}
async proxy() {
return firstValueFrom(
this.httpClient.get(`${this.baseUrl}/characters/1344`).pipe(
catchError((error: AxiosError) => {
throw new HttpException(
{
errorCode: error.code,
message: error.response.data,
stack: error.stack,
},
error.status,
);
}),
),
);
}
}
common-logger
Provides a unified logging system, crucial for application monitoring and debugging.
Use:
The way to inject the module:
app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { CommonLoggerModule } from '@caserita/common-logger';
import { AppController } from './app.controller';
import { AppHandler } from './app.handler';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, cache: true }),
CommonLoggerModule,
],
controllers: [AppController, AppHandler],
providers: [AppService, AppRepository],
})
export class AppModule {}
How to use the module on the use-case:
create-command.handler.ts
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { Logger } from '@nestjs/common';
import { CreateCommandImpl } from '@app/commands/impl/create-command.impl';
import { ExpedientService } from '@domain/expedient.service';
import { CaseritaBusinessAccountMsService } from '@domain/caseritaBusinessAccountMs.service';
import { Expedient } from '@domain/entities/expedient.entity';
import { ExpedientTracing } from '@domain/entities/expedientTracing.entity';
import { DatosEmpresa } from '@domain/entities/datosEmpresa';
import { DatosRepresentanteLegal } from '@domain/entities/datosRepresentanteLegal';
import { Archivo } from '@domain/entities/archivo.entity';
import { EstadoExpediente } from '@domain/emun/estadoExpediente.enum';
import { TipoDocumento } from '@domain/emun/tipoDocumento.enum';
@CommandHandler(CreateCommandImpl)
export class CreateCommandHandler implements ICommandHandler<CreateCommandImpl> {
private readonly logger = new Logger('CreateCommandHandler');
constructor(
private readonly service: ExpedientService,
private readonly caseritaBusinessAccountMs: CaseritaBusinessAccountMsService,
) {}
async execute({ command }: CreateCommandImpl): Promise<void> {
const expedient = new Expedient();
const expedientTracing = new ExpedientTracing();
const datosEmpresa = new DatosEmpresa();
const datosRepresentanteLegal = new DatosRepresentanteLegal();
const archivo = new Archivo();
const archivos: Archivo[] = [];
expedient.estado = EstadoExpediente.CREADO;
expedient.codigoExpediente = this.generateCodeExpediente(
command.datosEmpresa.numeroDocumento,
command.datosRepresentanteLegal.numeroDocumento,
);
datosEmpresa.tipoDocumento = TipoDocumento.RUC;
datosEmpresa.numeroDocumento = command.datosEmpresa.numeroDocumento;
datosRepresentanteLegal.tipoDocumento = TipoDocumento.DNI;
datosRepresentanteLegal.numeroDocumento = command.datosRepresentanteLegal.numeroDocumento;
datosRepresentanteLegal.fechaNacimiento = command.datosRepresentanteLegal.fechaNacimiento;
datosRepresentanteLegal.correoElectronico = command.datosRepresentanteLegal.correoElectronico;
datosRepresentanteLegal.direccion = command.datosRepresentanteLegal.direccion;
datosRepresentanteLegal.telefono = command.datosRepresentanteLegal.telefono;
for (const a of command.archivos) {
archivo.nombreArchivo = a.nombreArchivo;
archivo.url = a.url;
archivo.tipoArchivo = a.tipoArchivo;
archivo.fechaSubida = a.fechaSubida;
archivos.push(archivo);
}
expedient.datosEmpresa = datosEmpresa;
expedient.datosRepresentanteLegal = datosRepresentanteLegal;
expedient.archivos = archivos;
const result = await this.service.create(expedient);
this.logger.log('[CreateCommandImpl - CREATE EXPEDIENTE]: Se creo el expediente con éxito');
// Envio mensaje service bus para proceso asincrono de creacion de cuenta negocio
this.logger.log('[CreateCommandImpl - SEND CREATE ASYNC BUSINESS ACCOUNT]');
this.caseritaBusinessAccountMs.create({ idExpediente: expedient.idExpediente, idEmpresa: expedient.codigoExpediente });
expedientTracing.codigoExpediente = result.codigoExpediente;
expedientTracing.estado = EstadoExpediente.CREADO;
expedientTracing.ruc = datosEmpresa.numeroDocumento;
expedientTracing.dni = datosRepresentanteLegal.numeroDocumento;
expedientTracing.fechaCreacion = result.fechaCreacion.toISOString();
await this.service.createTracing(expedientTracing);
this.logger.log(
'[CreateCommandImpl - CREATE EXPEDIENTE TRACING]: Se creo el trazado del expediente con éxito',
);
}
private generateCodeExpediente(rucNumber: string, dniNumber: string) {
return `${TipoDocumento.RUC}${rucNumber}${TipoDocumento.DNI}${dniNumber}`;
}
}
Environments:
This package uses the following variables:
.env .env.development.local
LOGGER_LEVEL=info
LOGGER_ENABLED=true # false
LOGGER_CLOUD=logtail # local -> TOKEN_LOGTAIL_LOGGER is empty
TOKEN_LOGTAIL_LOGGER=82jk4y28y283yru2734728
common-response
Standardized response structures for APIs, Events, such as success and error. It exposes a global exception filter (AppErrorResponseFilter) and a success interceptor (SuccessResponseInterceptor) that wrap every controller response (and unhandled error) in a consistent envelope.
Use:
The way to inject the module and wire the global filter/interceptor:
main.ts
import { NestFactory } from '@nestjs/core';
import {
CommonResponseModule,
AppErrorResponseFilter,
SuccessResponseInterceptor,
} from '@caserita/common-response';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(app.get(AppErrorResponseFilter));
app.useGlobalInterceptors(app.get(SuccessResponseInterceptor));
await app.listen(3000);
}
bootstrap();
app.module.ts
import { Module } from '@nestjs/common';
import { CommonResponseModule } from '@caserita/common-response';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [CommonResponseModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
ℹ️ Note:
bootstrap()from@caserita/server-startedalready wiresAppErrorResponseFilterandSuccessResponseInterceptorfor you — see theserver-startedsection below.
common-search
Advanced search logic, with respect to databases. Provides shared query-building utilities (filtering, pagination, sorting) reused across repositories/adapters.
Use:
The way to inject the module:
app.module.ts
import { Module } from '@nestjs/common';
import { CommonSearchModule } from '@caserita/common-search';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AppRepository } from './app.repository';
@Module({
imports: [CommonSearchModule],
controllers: [AppController],
providers: [AppService, AppRepository],
})
export class AppModule {}
common-keyvault
Loads secrets from a remote key vault provider (currently Infisical, with Azure/AWS reserved for future support) and injects them into process.env at application startup, keeping local .env files as the source of truth for development.
Use:
The way to inject the module (registers the provider so it can be used via DI, e.g. KeyvaultEngine):
app.module.ts
import { Module } from '@nestjs/common';
import { CommonKeyvaultModule, KeyvaultProviderType } from '@caserita/common-keyvault';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
CommonKeyvaultModule.register(KeyvaultProviderType.INFISICAL),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
How to bootstrap secrets before the Nest application starts (loads secrets straight into process.env, so ConfigService can read them right after):
main.ts
import { KeyvaultBootstrap, KeyvaultProviderType } from '@caserita/common-keyvault';
async function bootstrap() {
const NODE_ENV = process.env.NODE_ENV || 'development';
await KeyvaultBootstrap.load(KeyvaultProviderType.INFISICAL, {
isLocal: NODE_ENV === 'development', // skip remote fetch in local/dev
overrideLocal: NODE_ENV !== 'development', // remote secrets win over local .env in prod/CI
});
// ...continue with NestFactory.create(AppModule)
}
bootstrap();
ℹ️ Note:
bootstrap()from@caserita/server-startedalready callsKeyvaultBootstrap.load(...)for you — see theserver-startedsection below.
Environments:
This package uses the following variables:
.env .env.development.local
KEYVAULT_INFISICAL_CLIENT_ID=******
KEYVAULT_INFISICAL_CLIENT_SECRET=******
KEYVAULT_INFISICAL_PROJECT_ID=******
KEYVAULT_INFISICAL_ENVIRONMENT=dev
KEYVAULT_INFISICAL_SITE_URL=https://us.infisical.com
server-started
Centralizes and standardizes the application bootstrap: reads APP_RUNNING_ENV to start either an HTTP server or a NATS microservice, wires the global filters/interceptors/pipes, loads secrets via common-keyvault, and prints a startup banner (via figlet) plus version/author info from your project's package.json.
Use:
Because this module lives in a library, it doesn't know the file structure of the project that installs it. For that reason, bootstrap() doesn't resolve anything on its own (AppModule, package.json, etc.) — everything is injected explicitly by the consumer project:
main.ts
import { KeyvaultBootstrap, KeyvaultProviderType } from '@caserita/common-keyvault';
import { AppLoggerService, Logger, LoggerInterceptor } from '@caserita/common-logger';
import { AppErrorResponseFilter, SuccessResponseInterceptor } from '@caserita/common-response';
import { bootstrap } from '@caserita/server-started';
import { AppModule } from './app.module';
import * as fs from 'fs';
import * as path from 'path';
const pkg = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'));
bootstrap({
AppModule,
GlobalPrefix: 'v1', // or null to disable the global prefix
KeyvaultBootstrap,
KeyvaultProviderType,
AppErrorResponseFilter,
LoggerInterceptor,
SuccessResponseInterceptor,
AppLoggerService,
Logger,
pkg,
});
Depending on APP_RUNNING_ENV, bootstrap() will:
HTTP: create a regular Nest HTTP application (NestFactory.create), applyGlobalPrefix, enable CORS, register the global error filter and interceptors, and listen onPORT.NATS: create a Nest microservice over NATS (NestFactory.createMicroservice) usingNATS_SERVERS, and register the logger interceptor.
In both cases it also applies a global ValidationPipe({ whitelist: true, forbidNonWhitelisted: true }), resolves the app logger, and — in development — prints the running environment, NODE_ENV, and the version/author fields taken from the pkg you passed in.
Environments:
This package uses the following variables:
.env .env.development.local
APPLICATION_NAME=INFRA
APP_RUNNING_ENV=HTTP # NATS
PORT=8080
NATS_SERVERS="nats://localhost:4222"
📝 Environment Variables
To run this project, you will need to add the following environment variables to your .env.development.local file
.env.development.local
# APP
APPLICATION_NAME=INFRA
APP_RUNNING_ENV=HTTP # NATS
NODE_ENV=development # production
PORT=8080
# NATS
NATS_SERVERS="nats://localhost:4222"
# LOGGER
LOGGER_LEVEL=info
LOGGER_ENABLED=true
LOGGER_CLOUD=logtail
TOKEN_LOGTAIL_LOGGER=******
# DATABASE
DB_USER_MONGO=******
DB_KEY_MONGO=******
DB_HOST_MONGO=******
DB_CONTAINER_NAME_MONGO=******
# POSTGRES DATABASE
DB_HOST_POSTGRES=******
DB_PORT_POSTGRES=******
DB_USERNAME_POSTGRES=******
DB_PASSWORD_POSTGRES=******
DB_CONTAINER_NAME_POSTGRES=******
DB_SYNCHRONIZE_POSTGRES=******
# ENCRYPTION
ENCRYPT_SECRET_KEY=******
ENCRYPT_DATABASE_SECRET_KEY=******
# CACHE REDIS
REDIS_CLOUD_HOST=******
REDIS_CLOUD_PORT=******
REDIS_CLOUD_PASSWORD=******
REDIS_CLOUD_TTL= 300
REDIS_NUMBER_DB=
# KEYVAULT
KEYVAULT_INFISICAL_CLIENT_ID=******
KEYVAULT_INFISICAL_CLIENT_SECRET=******
KEYVAULT_INFISICAL_PROJECT_ID=******
KEYVAULT_INFISICAL_ENVIRONMENT=dev
KEYVAULT_INFISICAL_SITE_URL=https://us.infisical.com
# PROXIES
BASE_URL_DATTEBAYO=https://dattebayo-api.onrender.com
🛠️ Scripts Disponibles
Here are some related projects
# Desarrollo
pnpm run start:dev # Ejecuta en modo desarrollo con watch
pnpm run start # Ejecuta en modo normal
pnpm run start:prod # Ejecuta en modo producción
# Build
pnpm run build # Compila el proyecto
# Testing
pnpm run test # Ejecuta tests unitarios
pnpm run test:watch # Ejecuta tests en modo watch
pnpm run test:e2e # Ejecuta tests end-to-end
pnpm run test:cov # Ejecuta tests con coverage
# Linting y Formato
pnpm run lint # Ejecuta ESLint
pnpm run format # Formatea código con Prettier
🚀 Deployment
To deploy this project with docker:
FROM node:18-alpine
WORKDIR /app
# Instalar pnpm
RUN npm install -g pnpm
# Copiar archivos de dependencias
COPY package.json pnpm-lock.yaml ./
# Instalar dependencias
RUN pnpm install --frozen-lockfile
# Copiar código fuente
COPY . .
# Build
RUN pnpm run build
# Exponer puerto
EXPOSE 3000
# Comando de inicio
CMD ["pnpm", "run", "start:prod"]
docker-compose:
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:password@db:5432/caserita
depends_on:
- db
- redis
db:
image: postgres:15
environment:
POSTGRES_DB: caserita
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
😁 Authors
- Desarrollado con ❤️ por BrolyDev
