Skip to content

Code Style Guide

Padrões obrigatórios herdados do contrasync-nest-api. Em caso de conflito, esta página complementa, não substitui, o Code Style do nest-api.


1. Princípios Invioláveis

1.1 Nunca Comentários no Código

Sem comentários inline, JSDoc ou banners. Se o código precisa de explicação, refatore.

1.2 Nunca any

Use Record<string, unknown>, generics <T>, ou unknown com type guard.

1.3 Importações Absolutas via Path Aliases

typescript
// ❌ PROIBIDO
import { Logger } from '../../common/logger'

// ✅ CORRETO
import { Logger } from '@common/logger'

Aliases disponíveis (configurados em tsconfig.json e vitest.config.ts):

  • @/*src/*
  • @common/*src/common/*
  • @domain/*src/domain/*
  • @helpers/*src/helpers/*
  • @services/*src/services/*
  • @handlers/*src/handlers/*
  • @adapters/*src/adapters/*
  • @infra/*infra/*

1.4 Tipos, Interfaces e Constantes em domain/

Toda interface, type e const/enum reutilizável fica em src/domain/, nunca declarada dentro de handler, service ou adapter:

src/domain/
├── constants/  → BOT_COMMANDS, OFF_HOURS_MESSAGE, BOT_HOURS_OPEN/CLOSE
├── enums/      → BotState
└── interfaces/ → IncomingMessage, OutgoingTextMessage, SentMessageReceipt

1.5 Sem try/catch Manual

Erros são tratados de forma centralizada em src/common/error-boundary.ts. Handlers e services apenas lançam BotError, ValidationError ou UnauthorizedError: a fronteira HTTP converte em response.

typescript
// ❌ PROIBIDO
async handle(event) {
  try {
    return await this.process(event)
  } catch (e) {
    return { statusCode: 500, body: '...' }
  }
}

// ✅ CORRETO
async handle(event) {
  return this.process(event)
}

1.6 Sem return Type Anotado

O TypeScript infere o tipo de retorno. Tipos explícitos só em interfaces/contracts:

typescript
// ❌ PROIBIDO
sendText(message: OutgoingTextMessage): Promise<SentMessageReceipt> { ... }

// ✅ CORRETO
sendText(message: OutgoingTextMessage) { ... }

Exceção: quando o contrato externo (ex.: interface explícita) exige.

1.7 Logger com warn Antes de throw

Sempre logar com nível warn (ou error) antes de propagar uma exceção, com contexto suficiente para investigação posterior.


2. Nomenclatura

TipoConvençãoExemplo
ClassesPascalCaseZapiClient, BotRouterService
MétodoscamelCasereplyOffHours(), sendText()
VariáveiscamelCaseincoming, payload
ConstantesUPPER_SNAKEOFF_HOURS_MESSAGE, BOT_HOURS_OPEN
Arquivoskebab-caseinbound-webhook.handler.ts, business-hours.ts
Specskebab-case + .spec.tszapi.mapper.spec.ts
InterfacesPascalCaseIncomingMessage, ZapiWebhookPayload
EnumsPascalCaseBotState

3. Estrutura de Arquivos por Tipo

CamadaSufixoLocalização
Handler.handler.tssrc/handlers/
Service.service.tssrc/services/
Adapter (HTTP client).client.tssrc/adapters/<vendor>/
Mapper.mapper.tssrc/adapters/<vendor>/
Types externos.types.tssrc/adapters/<vendor>/
Helper purokebab-casesrc/helpers/
Interface.interface.tssrc/domain/interfaces/
Enum.enum.tssrc/domain/enums/
Constante.const.tssrc/domain/constants/
Spec (teste).spec.tsco-locado com o arquivo testado

4. Regras de ESLint (herdadas)

  • Proibido: for, for...in, for...of (usar .map(), .filter(), .reduce(), .forEach())
  • Proibido: comentários inline e TODO/FIXME/HACK
  • Proibido: imports relativos profundos (usar @/)
  • Limite: 4 níveis de aninhamento, 4 callbacks aninhados
  • Aviso: funções > 80 linhas, > 5 parâmetros, complexidade > 15

5. Regras Específicas do Lambda

RegraRazão
Bootstrap fora do handlerInicialização (ZapiClient, services) acontece no module-level para reaproveitar contexto entre invocations
Sem console.* diretoSempre via Logger do @common/logger para garantir JSON estruturado
process.env apenas em handler.ts ou infra/Services recebem config via construtor (DI manual)
axios.create() por clientNunca usar axios global facilita mock em testes
IncomingMessage é imutávelMapper devolve uma vez; downstream só lê

Documento atualizado em Maio 2026