npm package: @ferreirasw/yoke-common
Description: Shared utilities, types, and messaging infrastructure for Yoke microservices
Author: ferreirasw
Latest version: 0.5.0

# @ferreirasw/yoke-common

Shared utilities, types, and messaging infrastructure for Yoke microservices.

## Installation

```bash
npm install @ferreirasw/yoke-common
```

## Features

- **Enums**: Shared enums for business logic (Modality, TaxRegime, RiskProfile, Status enums, etc.)
- **Messaging**: RabbitMQ infrastructure with exchanges, routing keys, and message types
- **DTOs**: Standardized DTOs for pagination and API responses
- **Filters**: Global exception filters for consistent error handling
- **Interceptors**: Logging interceptors for request/response tracking
- **Utilities**: Common validation and formatting utilities (CPF, CNPJ, currency, etc.)

## Table of Contents

- [Enums](#enums)
- [Messaging (RabbitMQ)](#messaging-rabbitmq)
- [DTOs and Interfaces](#dtos-and-interfaces)
- [Filters and Interceptors](#filters-and-interceptors)
- [Utilities](#utilities)
- [Publishing Updates](#publishing-updates)

## Enums

All shared enums for consistent business logic across microservices.

### Usage Example

```typescript
import {
  Modality,
  TaxRegime,
  RiskProfile,
  ProductStatus,
  QuotationStatus,
} from '@ferreirasw/yoke-common';

// Use in your entities
@Entity()
export class Product {
  @Column({ type: 'enum', enum: Modality })
  modality: Modality;

  @Column({ type: 'enum', enum: TaxRegime })
  taxRegime: TaxRegime;

  @Column({ type: 'enum', enum: ProductStatus, default: ProductStatus.ACTIVE })
  status: ProductStatus;
}
```

### Available Enums

- `Modality`: PGBL, VGBL, ANY
- `TaxRegime`: PROGRESSIVE, REGRESSIVE, ANY
- `RiskProfile`: CONSERVATIVE, MODERATE, BOLD, AGGRESSIVE
- `ProductStatus`: ACTIVE, INACTIVE, SUSPENDED
- `QuotationStatus`: PENDING, COMPLETED, EXPIRED, CANCELLED
- `FundStatus`: ACTIVE, INACTIVE
- `InsurerStatus`: ACTIVE, INACTIVE, SUSPENDED
- `CoverageType`: DEATH, DISABILITY, TERM_PENSION, LIFETIME_INCOME, TEMPORARY_INCOME
- `Benchmark`: CDI, SELIC, IPCA, IBOVESPA, IBRX, IGPM
- `Action` (CASL): Manage, Create, Read, ReadAll, Update, UpdateAll, Delete, DeleteAll

## Messaging (RabbitMQ)

Centralized RabbitMQ infrastructure for event-driven communication between microservices.

### Exchanges and Routing Keys

```typescript
import { EXCHANGES, ROUTING_KEYS } from '@ferreirasw/yoke-common';

// Publish an event
await eventsService.publishEvent(
  EXCHANGES.PRODUCT,
  ROUTING_KEYS.PRODUCT_CREATED,
  { productId: '123', name: 'Product A' }
);
```

### BaseEventsService

Extend the `BaseEventsService` in your microservice:

```typescript
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { BaseEventsService, EXCHANGES } from '@ferreirasw/yoke-common';

@Injectable()
export class ProductEventsService extends BaseEventsService {
  constructor(configService: ConfigService) {
    super(configService, 'ProductEventsService');
  }

  protected async setupExchanges(channel: any): Promise<void> {
    // Assert your service's exchanges
    await channel.assertExchange(EXCHANGES.PRODUCT, 'topic', { durable: true });
    await channel.assertExchange(EXCHANGES.FUND, 'topic', { durable: true });
    await channel.assertExchange(EXCHANGES.COVERAGE, 'topic', { durable: true });
    await channel.assertExchange(EXCHANGES.INSURER, 'topic', { durable: true });
  }
}
```

Then register in your module:

```typescript
import { Module } from '@nestjs/common';
import { ProductEventsService } from './events/product-events.service';

@Module({
  providers: [ProductEventsService],
  exports: [ProductEventsService],
})
export class EventsModule {}
```

### Message Types

Type-safe message interfaces for all events:

```typescript
import {
  ProductCreatedMessage,
  EXCHANGES,
  ROUTING_KEYS,
} from '@ferreirasw/yoke-common';

const message: ProductCreatedMessage = {
  productId: product.id,
  insurerId: product.insurerId,
  name: product.name,
  description: product.description,
  modality: product.modality,
  taxRegime: product.taxRegime,
  status: product.status,
  minContribution: product.minContribution,
  maxContribution: product.maxContribution,
  entryFee: product.entryFee,
  administrationFee: product.administrationFee,
  timestamp: Date.now(),
  source: 'product-microservice',
};

await this.eventsService.publishEvent(
  EXCHANGES.PRODUCT,
  ROUTING_KEYS.PRODUCT_CREATED,
  message
);
```

## DTOs and Interfaces

### Pagination

```typescript
import {
  PaginationDto,
  PaginatedResult,
  PaginationHelper,
} from '@ferreirasw/yoke-common';

// In your controller
@Get()
async findAll(@Query() pagination: PaginationDto) {
  const [data, total] = await this.productService.findAll(pagination);

  return PaginationHelper.createResult(
    data,
    total,
    pagination.page,
    pagination.limit
  );
}

// In your service
async findAll(pagination: PaginationDto) {
  const offset = pagination.getOffset();
  const limit = pagination.getLimit();

  const [data, total] = await this.repository.findAndCount({
    skip: offset,
    take: limit,
    order: {
      [pagination.sortBy || 'createdAt']: pagination.sortOrder || 'DESC',
    },
  });

  return [data, total];
}
```

### API Responses

```typescript
import {
  ApiResponse,
  ResponseBuilder,
} from '@ferreirasw/yoke-common';

// Success response
@Post()
async create(@Body() createDto: CreateProductDto) {
  const product = await this.productService.create(createDto);
  return ResponseBuilder.success(product, 'Product created successfully');
}

// Error response (usually handled by exception filter)
throw new BadRequestException(
  ResponseBuilder.error('VALIDATION_FAILED', 'Invalid input data')
);
```

## Filters and Interceptors

### Exception Filter

```typescript
// In main.ts
import { AllExceptionsFilter } from '@ferreirasw/yoke-common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Register global exception filter
  app.useGlobalFilters(new AllExceptionsFilter());

  await app.listen(3000);
}
```

### Logging Interceptor

```typescript
// In main.ts
import { LoggingInterceptor } from '@ferreirasw/yoke-common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Register global logging interceptor
  app.useGlobalInterceptors(
    new LoggingInterceptor({
      logRequestBody: process.env.NODE_ENV === 'development',
      logResponseData: false, // Disable in production for security
    })
  );

  await app.listen(3000);
}
```

## Utilities

### Validation Utilities

```typescript
import {
  isValidCPF,
  isValidCNPJ,
  formatCPF,
  formatCNPJ,
  formatCurrency,
  calculateAge,
} from '@ferreirasw/yoke-common';

// Validate CPF
if (isValidCPF('123.456.789-09')) {
  console.log('Valid CPF');
}

// Validate CNPJ
if (isValidCNPJ('11.222.333/0001-81')) {
  console.log('Valid CNPJ');
}

// Format values
const formattedCPF = formatCPF('12345678909'); // '123.456.789-09'
const formattedCNPJ = formatCNPJ('11222333000181'); // '11.222.333/0001-81'
const formattedPrice = formatCurrency(1234.56); // 'R$ 1.234,56'

// Calculate age
const age = calculateAge(new Date('1990-01-15')); // 36 (as of 2026)
```

## Publishing Updates

### Prerequisites

1. Login to npm with ferreirasw account:

```bash
npm login
# Enter credentials for ferreirasw
npm whoami  # Should output: ferreirasw
```

### Publishing Workflow

1. **Make your changes** to the codebase

2. **Update CHANGELOG.md** with your changes

3. **Bump the version** using semantic versioning:

```bash
# For bug fixes (0.1.0 -> 0.1.1)
npm version patch

# For new features (0.1.0 -> 0.2.0)
npm version minor

# For breaking changes (0.1.0 -> 1.0.0)
npm version major
```

4. **Build and publish**:

```bash
npm run build
npm publish --access public
```

5. **Push to git with tags**:

```bash
git push origin main --tags
```

### Using in Microservices

After publishing, install in your microservices:

```bash
cd /path/to/account-microservice
npm install @ferreirasw/yoke-common@latest

cd /path/to/product-microservice
npm install @ferreirasw/yoke-common@latest

cd /path/to/quotation-microservice
npm install @ferreirasw/yoke-common@latest
```

### Updating Microservices

When a new version is published:

```bash
npm update @ferreirasw/yoke-common
```

Or install a specific version:

```bash
npm install @ferreirasw/yoke-common@0.2.0
```

## Development

### Building

```bash
npm run build
```

### Linting

```bash
npm run lint
```

### Formatting

```bash
npm run format
```

## License

MIT

## Support

For issues or questions, please create an issue in the repository.