Microservice Setup Guide
Overview
Section titled “Overview”This system follows a microservices architecture with Bounded Context (BC) patterns. Each microservice:
- Owns its domain data (Single Source of Truth)
- Exposes both HTTP REST APIs and TCP microservice endpoints
- Communicates with other services via TCP transport
- Uses standardized bootstrap configuration
- Integrates with Redis (stateful JWT sessions), PostgreSQL (primary-replica), and object storage
Step-by-Step Setup Process
Section titled “Step-by-Step Setup Process”Step 1: Generate New Application
Section titled “Step 1: Generate New Application”Use the NestJS CLI to generate a new application in the monorepo:
# For Bounded Context services (business domains)nest g app <business>-bc
# Examples:nest g app data-owner-bc # Data Owner Bounded Contextnest g app data-consumer-bc # Data Consumer Bounded Contextnest g app reporting-bc # Reporting BC
# For non-BC services (infrastructure/support services)nest g app <service-name>
# Examples:nest g app auth # Authentication servicenest g app iam # Identity & Access Managementnest g app storage # File storage serviceNaming Convention:
- Use
kebab-casefor application names - Suffix business domain services with
-bc(Bounded Context) - Infrastructure services (auth, storage, etc.) don’t use
-bcsuffix
What this creates:
apps/<service-name>/├── src/│ ├── <service-name>.controller.ts│ ├── <service-name>.module.ts│ ├── <service-name>.service.ts│ └── main.ts├── test/│ └── app.e2e-spec.ts├── tsconfig.app.json└── package.json (if standalone)Step 2: Create Bootstrap Configuration
Section titled “Step 2: Create Bootstrap Configuration”Replace the default main.ts with a standardized bootstrap using the bootstrapApplication() utility.
2.1 Import Required Dependencies
Create apps/<service-name>/src/main.ts:
import { DocAuthKey } from '@lib/common/enum/auth/doc-auth-key.enum';import { bootstrapApplication } from '@lib/common/utils/bootstrap.util';
import { YourBCModule } from './your-bc.module';
async function bootstrap(): Promise<void> { await bootstrapApplication({ // Configuration options... });}
bootstrap();2.2 Configure Bootstrap Options
The bootstrapApplication() function accepts a configuration object with the following parameters:
await bootstrapApplication({ // Module Configuration module: YourBCModule, // Your root module class
// Environment Variable Keys (for ConfigService) globalPrefixNameEnv: 'YOUR_PREFIX_NAME', // e.g., 'DATA_OWNER_PREFIX_NAME' globalPrefixVersionEnv: 'YOUR_PREFIX_VERSION', // e.g., 'DATA_OWNER_PREFIX_VERSION' httpPortEnv: 'YOUR_BC_MODULE_HTTP_PORT', // e.g., 'DATA_OWNER_BC_HTTP_PORT' microservicePortEnv: 'YOUR_BC_MODULE_MICROSERVICE_PORT', // Optional for microservices
// Default Values (fallbacks if env vars not set) defaultGlobalPrefixName: 'your-bc', // URL prefix: /your-bc/v1 defaultGlobalPrefixVersion: 'v1', // API version
// Swagger/OpenAPI Documentation swagger: { title: 'Your BC API', description: 'The API documentation for Your Bounded Context.', version: '1.0', // Optional, defaults to '1.0' tag: 'Your BC Service', },
// JWT Authentication (for protected APIs) jwtAuth: { name: DocAuthKey.JwtName, // Must match @ApiBearerAuth() decorator description: 'Enter your bearer token to authenticate', },});2.3 Complete Example (Data Owner BC)
import { DocAuthKey } from '@lib/common/enum/auth/doc-auth-key.enum';import { bootstrapApplication } from '@lib/common/utils/bootstrap.util';
import { DataOwnerBCModule } from './data-owner-bc.module';
async function bootstrap(): Promise<void> { await bootstrapApplication({ module: DataOwnerBCModule, globalPrefixNameEnv: 'DATA_OWNER_PREFIX_NAME', globalPrefixVersionEnv: 'DATA_OWNER_PREFIX_VERSION', defaultGlobalPrefixName: 'data-owner-bc', defaultGlobalPrefixVersion: 'v1', httpPortEnv: 'DATA_OWNER_BC_MODULE_HTTP_PORT', microservicePortEnv: 'DATA_OWNER_BC_MODULE_MICROSERVICE_PORT', swagger: { title: 'Data Owner API', description: 'The API documentation for the Data Owner Bounded Context.', tag: 'Data Owner BC', }, jwtAuth: { name: DocAuthKey.JwtName, description: 'Enter your bearer token to authenticate', }, });}
bootstrap();What Bootstrap Automatically Configures:
- CORS enabled
- Global prefix:
/{prefix}/{version}(e.g.,/data-owner-bc/v1) - Global exception filter (
AllExceptionsFilter) - Response transformation interceptor (
TransformInterceptor) - Authentication guards (
AuthGuard,PermissionsGuard) - Validation pipe with DTO validation
- Swagger/OpenAPI documentation
- TCP microservice listener (if
microservicePortEnvprovided) - Health check endpoint at
/health
Step 3: Add Environment Variables to ConfigModule
Section titled “Step 3: Add Environment Variables to ConfigModule”The ConfigModule uses Joi for validation. Add your service’s environment variables.
3.1 Open Configuration File
File: libs/config/src/config.module.ts
3.2 Add Validation Schema
Add your service’s variables to the Joi validation schema:
validationSchema: Joi.object({ // ... existing variables ...
// Your New Service YOUR_PREFIX_NAME: Joi.string().required(), YOUR_PREFIX_VERSION: Joi.string().required(), YOUR_BC_MODULE_MICROSERVICE_PORT: Joi.number().required(), YOUR_BC_MODULE_HTTP_PORT: Joi.number().required(),}),Example (Reporting BC):
// Reporting Bounded Context (BC)REPORTING_PREFIX_NAME: Joi.string().required(),REPORTING_PREFIX_VERSION: Joi.string().required(),REPORTING_BC_MODULE_MICROSERVICE_PORT: Joi.number().required(),REPORTING_BC_MODULE_HTTP_PORT: Joi.number().required(),Validation Rules:
- Use
.required()for mandatory variables - Use
.default(value)for optional variables with fallbacks - Use appropriate Joi types:
.string(),.number(),.boolean()
Step 4: Add Environment Variables to .env
Section titled “Step 4: Add Environment Variables to .env”Add your service’s runtime configuration to the .env file.
4.1 Port Allocation Strategy
Port Ranges:
- Microservice TCP Ports: 3000–3999, 5000–5999
- HTTP Ports: 4000–4999, 6000–6999
Convention: Assign microservice and HTTP ports sequentially — if the TCP port is 3003, the HTTP port should be 4003.
4.2 Add Configuration
#--- Your Service Name ---#YOUR_PREFIX_NAME=your-serviceYOUR_PREFIX_VERSION=v1YOUR_BC_MODULE_MICROSERVICE_PORT=3003 # Choose available portYOUR_BC_MODULE_HTTP_PORT=4003 # HTTP = Microservice + 1000Example (Reporting BC):
#--- Reporting BC Service ---#REPORTING_PREFIX_NAME=reporting-bcREPORTING_PREFIX_VERSION=v1REPORTING_BC_MODULE_MICROSERVICE_PORT=3003REPORTING_BC_MODULE_HTTP_PORT=4003Best Practices:
- Keep microservice and HTTP ports sequential (e.g., 3003 and 4003)
- Document port allocation in comments
- Update
.env.exampleas well for team reference
Step 5: Register Microservice in Enum
Section titled “Step 5: Register Microservice in Enum”Add your service to the microservice registry for inter-service communication.
5.1 Open Enum File
File: libs/common/src/enum/app-microservice.enum.ts
5.2 Define Service Constants
// Add your service constantexport const YourServiceMCS = { name: 'YOUR_SERVICE_NAME', cmd: { // Define message patterns for inter-service communication GetResource: 'yourService.getResource', CreateResource: 'yourService.createResource', },};
// Update AppMicroservice objectexport const AppMicroservice = { Auth: AuthMCS, Iam: IamMCS, MasterData: MasterDataMCS, Storage: StorageMCS, SystemAdmin: SystemAdminMCS, YourService: YourServiceMCS, // Add your service here};Example (Reporting BC):
export const ReportingMCS = { name: 'REPORTING_SERVICE', cmd: { GetReportById: 'reporting.getReportById', GenerateReport: 'reporting.generateReport', GetScheduledReports: 'reporting.getScheduledReports', },};
export const AppMicroservice = { Auth: AuthMCS, Iam: IamMCS, MasterData: MasterDataMCS, Storage: StorageMCS, SystemAdmin: SystemAdminMCS, Reporting: ReportingMCS,};Naming Conventions:
- Service name:
SCREAMING_SNAKE_CASE - Message patterns:
camelCasewith dot notation (service.action) - Pattern format:
{serviceName}.{resourceOrAction}.{operation}
Step 6: Register Microservice Client in CommonModule
Section titled “Step 6: Register Microservice Client in CommonModule”Enable other services to communicate with your new microservice.
6.1 Open CommonModule File
File: libs/common/src/common.module.ts
6.2 Add Client Registration
ClientsModule.registerAsync([ // ... existing services ...
// Your New Service Client { name: AppMicroservice.YourService.name, imports: [ConfigModule], useFactory: (configService: ConfigService) => ({ transport: Transport.TCP, options: { host: 'localhost', port: configService.get<number>( 'YOUR_BC_MODULE_MICROSERVICE_PORT', 3003, // Default fallback port ), }, }), inject: [ConfigService], },]),Configuration Details:
name: Must match the name inAppMicroserviceenumtransport: Currently usingTransport.TCP(can be REDIS, KAFKA, etc.)host:localhostfor development, configure for productionport: Read from environment with fallback default
Step 7: Register API Documentation in Docs Gateway
Section titled “Step 7: Register API Documentation in Docs Gateway”Add your service’s Swagger documentation to the centralized docs aggregator.
7.1 Open Docs Gateway Main File
File: apps/docs-gateway/src/main.ts
7.2 Add Service Documentation Source
const scalarOptions: ApiReferenceOptions = { sources: [ // ... existing services ...
// Your New Service { url: `http://localhost:${configService.get<number>('YOUR_BC_MODULE_HTTP_PORT')}/${configService.get<string>('YOUR_PREFIX_NAME')}/${configService.get<string>('YOUR_PREFIX_VERSION')}/${swaggerJsonEndpoint}`, title: 'Your Service Name', }, ],};URL Construction:
- Format:
http://localhost:{HTTP_PORT}/{PREFIX_NAME}/{PREFIX_VERSION}/{JSON_ENDPOINT} - Example:
http://localhost:4003/reporting-bc/v1/json-docs
Documentation Access:
- Aggregated Docs:
http://localhost:9999/api-docs(all services) - Individual Service:
http://localhost:{HTTP_PORT}/{prefix}/{version}/api-docs
Step 8: Update NestJS CLI Configuration (Auto-generated)
Section titled “Step 8: Update NestJS CLI Configuration (Auto-generated)”The nest-cli.json file is automatically updated when you run nest g app <name>. Verify the entry exists:
8.1 Check nest-cli.json
File: nest-cli.json
{ "projects": { "your-service": { "type": "application", "root": "apps/your-service", "entryFile": "main", "sourceRoot": "apps/your-service/src", "compilerOptions": { "tsConfigPath": "apps/your-service/tsconfig.app.json", "plugins": ["@nestjs/swagger"] } } }}Key Points:
entryFile: Must be"main"(not"main.ts")plugins: Include"@nestjs/swagger"for automatic Swagger metadata generation
Step 9: Add NPM Scripts
Section titled “Step 9: Add NPM Scripts”Add convenience scripts to package.json for running your service.
9.1 Development Scripts
{ "scripts": { "start:dev:your-service": "nest start your-service --watch", "build:your-service": "nest build your-service", "test:your-service": "jest --config ./apps/your-service/test/jest-e2e.json" }}Step 9.2: Add Entity Paths to TypeORM Data Sources
Once your microservice has entities that need to be migrated, register them in the TypeORM data source configuration files.
9.2.1 Update Core Database Data Source
File: libs/database/src/data-source.core.ts
export const coreConfig: DataSourceOptions = { type: 'postgres', database: AppDatabases.APP_CORE, synchronize: false, logging: true,
entities: [ 'apps/data-owner-bc/src/**/*.entity.ts', 'apps/data-consumer-bc/src/**/*.entity.ts', 'apps/admin-bc/src/**/*.entity.ts', 'apps/your-service-bc/src/**/*.entity.ts', // ← ADD THIS LINE ],
migrations: ['libs/database/src/migrations/core/*.ts'],};9.2.2 Create Migration Directory Structure
# For APP_CORE databasemkdir -p apps/your-service-bc/migrations/core
# For secondary databases (if applicable)mkdir -p apps/your-service-bc/migrations/secondaryKey Points:
- The entity path pattern
'apps/<service>/src/**/*.entity.ts'must match your actual entity file locations - Add paths before running migrations
- TypeORM uses these paths to auto-detect entities for schema generation
- Each service should have its own migration directory to avoid conflicts
Step 9.3: Add Microservice Configuration to PM2 (Production)
Section titled “Step 9.3: Add Microservice Configuration to PM2 (Production)”For production deployment with PM2, register your microservice in the ecosystem configuration.
File: ecosystem.config.js (root directory)
{ name: 'your-service-bc', script: './dist/apps/your-service-bc/main.js', instances: 1, exec_mode: 'cluster', env: { NODE_ENV: 'production', YOUR_PREFIX_NAME: 'your-service', YOUR_PREFIX_VERSION: 'v1', YOUR_BC_MODULE_HTTP_PORT: 4003, YOUR_BC_MODULE_MICROSERVICE_PORT: 3003, },},Key Configuration Details:
name: Unique identifier for the processscript: Path to compiled main.js fileinstances: Number of process instances (1 for single instance,'max'for auto-scaling)exec_mode:'cluster'for multi-core,'fork'for single process
PM2 Commands:
pm2 start ecosystem.config.js # Start all servicespm2 list # Monitor running servicespm2 logs your-service-bc # View service logspm2 restart your-service-bc # Restart serviceEnsure environment variables in
ecosystem.config.jsmatch your.envandconfig.module.tsexactly.
Step 10: Configure API Gateway (Production)
Section titled “Step 10: Configure API Gateway (Production)”For production deployment, register your service in the API Gateway (Kong or equivalent).
10.1 Add Service:
- Name:
your-service-name - Protocol:
http - Host:
localhost(or service hostname) - Port: Your HTTP port (e.g.,
4003) - Path:
/{prefix}/{version}(e.g.,/reporting-bc/v1)
10.2 Create Route:
- Paths:
["/reporting-bc"] - Methods:
["GET", "POST", "PUT", "DELETE", "PATCH"] - Strip path:
false
10.3 Apply Plugins (as needed):
- Rate limiting
- CORS
- JWT authentication
- Request/response logging
Verification Checklist
Section titled “Verification Checklist”After completing all steps, verify your setup:
Basic Checks
Section titled “Basic Checks”- Service starts without errors:
npm run start:dev:your-service - HTTP endpoint accessible:
http://localhost:{HTTP_PORT}/{prefix}/{version} - Health check works:
http://localhost:{HTTP_PORT}/health - Swagger docs load:
http://localhost:{HTTP_PORT}/{prefix}/{version}/api-docs - Microservice listens on TCP port (check console logs)
Integration Checks
Section titled “Integration Checks”- Service appears in docs gateway:
http://localhost:9999/api-docs - Can inject microservice client in other services
- Environment variables load correctly (no validation errors)
- Database connections work (if applicable)
- Redis session management works (if using auth)
Testing
Section titled “Testing”# Run unit testsnpm run test:your-service
# Run e2e testsnpm run test:your-service:e2eSummary
Section titled “Summary”Creating a new microservice involves 10 key steps:
- Generate app:
nest g app <name>-bc - Create bootstrap configuration in
main.ts - Add environment variables to
libs/config/src/config.module.ts - Add runtime config to
.env - Register service in
libs/common/src/enum/app-microservice.enum.ts - Register client in
libs/common/src/common.module.ts - Add docs to
apps/docs-gateway/src/main.ts - Verify
nest-cli.jsonconfiguration - Add npm scripts and entity paths
- Configure API Gateway (production only)
Continue Reading
Section titled “Continue Reading”For inter-service communication patterns, EventsController setup, MicroserviceClientService usage, message pattern naming, and troubleshooting: