> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/contributor/contributor-pt/guias-para-colaboradores/well-known-components/logic-components.md).

# Logic Components

{% hint style="info" %}
Esta seção está sendo desenvolvida atualmente. Volte em breve para uma documentação completa sobre componentes de lógica.
{% endhint %}

Os componentes de lógica são partes de software que contêm a **lógica de negócios** da sua aplicação. Eles são organizados semanticamente por domínio ou funcionalidade e servem como a camada de orquestração entre controladores e adaptadores.

## Objetivo

Componentes de lógica:

* Implementam regras de negócio e lógica de domínio
* Orquestram operações entre vários adaptadores
* Encapsulam fluxos de trabalho complexos
* Permanecem independentes de preocupações da camada de transporte (HTTP, WebSocket)
* Podem ser totalmente testados com unit tests sem dependências de I/O

## Localização

Os componentes de lógica DEVEM ser colocados no `src/logic` ou `src/components` diretório, organizado por domínio:

```
src/
└── logic/
    ├── users/
    ├── content/
    ├── permissions/
    └── notifications/
```

## Características

### 1. Consumo de Adaptadores

Os componentes de lógica são os principais consumidores de adaptadores. Eles usam adaptadores para interagir com recursos externos enquanto se concentram nas regras de negócio.

```tsx
export function createUserLogic(
  components: Pick<AppComponents, 'database' | 'cache' | 'logs'>
): IUserLogic {
  const { database, cache, logs } = components
  const logger = logs.getLogger('user-logic')

  async function getUserProfile(userId: string): Promise<UserProfile> {
    // Verificar primeiro o cache
    const cached = await cache.get(`user:${userId}`)
    if (cached) {
      return cached
    }

    // Obter do banco de dados
    const user = await database.query('SELECT * FROM users WHERE id = $1', [userId])
    
    // Aplicar lógica de negócios
    const profile = transformUserToProfile(user)
    
    // Armazenar o resultado em cache
    await cache.set(`user:${userId}`, profile, { ttl: 3600 })
    
    return profile
  }

  return {
    getUserProfile
  }
}
```

### 2. Regras de Negócio

Os componentes de lógica aplicam regras de negócio e validação:

```tsx
async function createUser(userData: CreateUserInput): Promise<User> {
  // Regra de negócio: o nome de usuário deve ser único
  const existing = await database.query(
    'SELECT id FROM users WHERE username = $1',
    [userData.username]
  )
  
  if (existing.rows.length > 0) {
    throw new UserAlreadyExistsError(userData.username)
  }

  // Regra de negócio: validar os dados do usuário
  if (!isValidEmail(userData.email)) {
    throw new InvalidEmailError(userData.email)
  }

  // Criar o usuário
  const user = await database.query(
    'INSERT INTO users (username, email) VALUES ($1, $2) RETURNING *',
    [userData.username, userData.email]
  )

  logger.info('Usuário criado', { userId: user.id })
  
  return user
}
```

### 3. Orquestração de Fluxo de Trabalho

Os componentes de lógica coordenam operações complexas em várias etapas:

```tsx
async function publishContent(
  userId: string,
  content: ContentInput
): Promise<PublishedContent> {
  // Etapa 1: Validar permissões
  const canPublish = await permissions.canUserPublish(userId)
  if (!canPublish) {
    throw new UnauthorizedError('O usuário não pode publicar conteúdo')
  }

  // Etapa 2: Processar conteúdo
  const processed = await processContent(content)

  // Etapa 3: Armazenar conteúdo
  const stored = await storage.save(processed)

  // Etapa 4: Atualizar índices
  await searchIndex.index(stored)

  // Etapa 5: Notificar assinantes
  await notifications.notifySubscribers(userId, stored)

  logger.info('Conteúdo publicado', { contentId: stored.id, userId })

  return stored
}
```

## Melhores práticas

### 1. Responsabilidade Única

Cada componente de lógica deve se concentrar em um único domínio ou contexto delimitado:

```tsx
// Bom: focado no domínio do usuário
createUserLogic()
createContentLogic()
createPermissionsLogic()

// Evitar: responsabilidades misturadas
createUserAndContentLogic()
```

### 2. Injeção de Dependências

Sempre injete dependências por meio do parâmetro components:

```tsx
export function createOrderLogic(
  components: Pick<AppComponents, 'database' | 'payments' | 'inventory' | 'logs'>
): IOrderLogic {
  // Usar dependências injetadas
}
```

### 3. Tratamento de Erros

Lance erros de domínio significativos que os controladores possam capturar e tratar:

```tsx
// Definir erros específicos do domínio
export class InsufficientInventoryError extends Error {
  constructor(public readonly productId: string, public readonly requested: number) {
    super(`Estoque insuficiente para o produto ${productId}. Solicitado: ${requested}`)
    this.name = 'InsufficientInventoryError'
  }
}
```

### 4. Lógica de Negócio Pura

Mantenha os componentes de lógica livres de preocupações da camada de transporte:

```tsx
// Bom: lógica de negócio pura
async function calculateOrderTotal(items: OrderItem[]): Promise<number> {
  return items.reduce((total, item) => total + item.price * item.quantity, 0)
}

// Evitar: preocupações da camada HTTP/transporte
async function calculateOrderTotal(req: Request, res: Response): Promise<void> {
  // Não faça isso em componentes de lógica
}
```

## Testando Componentes de Lógica

Os componentes de lógica devem ser amplamente testados com unit tests. Veja a [Serviços de teste (WKC)](/contributor/contributor-pt/guias-para-colaboradores/testing-standards/testing-services-wkc.md) documentação para detalhes.

```tsx
describe('ao criar um usuário', () => {
  let userLogic: IUserLogic
  let mockDatabase: jest.Mocked<IDatabase>

  beforeEach(() => {
    mockDatabase = createMockDatabase()
    userLogic = createUserLogic({ database: mockDatabase, logs: mockLogs })
  })

  describe('e o nome de usuário já existe', () => {
    beforeEach(() => {
      mockDatabase.query.mockResolvedValueOnce({ rows: [{ id: '123' }] })
    })

    it('deve lançar UserAlreadyExistsError', async () => {
      await expect(
        userLogic.createUser({ username: 'existing', email: 'test@test.com' })
      ).rejects.toThrow(UserAlreadyExistsError)
    })
  })
})
```

## Em Breve

Esta seção será expandida com:

* Exemplos detalhados de componentes de lógica orientados por domínio
* Padrões para lidar com fluxos de trabalho complexos
* Diretrizes para organizar lógica de domínio em grande escala
* Integração com sistemas de eventos
* Estratégias de cache
* Padrões de gerenciamento de transações


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/contributor/contributor-pt/guias-para-colaboradores/well-known-components/logic-components.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
