> 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-do-contribuidor/componentes-bem-conhecidos/logic-components.md).

# Componentes de Lógica

{% hint style="info" %}
Esta seção está atualmente em desenvolvimento. Volte em breve para documentação abrangente sobre logic components.
{% endhint %}

Logic components são pedaços de software que contêm o **business logic** da sua aplicação. Eles são organizados semanticamente por domínio ou funcionalidade e servem como a camada de orquestração entre controllers e adapters.

## Propósito

Logic components:

* Implementam regras de negócio e domain logic
* Orquestram operações entre múltiplos adapters
* Encapsulam fluxos de trabalho complexos
* Permaneçam independentes de preocupações da camada de transporte (HTTP, WebSocket)
* Podem ser testados unitariamente de forma completa sem dependências de I/O

## Localização

Logic components DEVERIAM ser colocados sob o `src/logic` ou `src/components` diretório, organizados por domínio:

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

## Características

### 1. Consumo de Adapters

Logic components são os consumidores primários de adapters. Eles usam adapters 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 cache primeiro
    const cached = await cache.get(`user:${userId}`)
    if (cached) {
      return cached
    }

    // Buscar do database
    const user = await database.query('SELECT * FROM users WHERE id = $1', [userId])
    
    // Aplicar business logic
    const profile = transformUserToProfile(user)
    
    // Cachear o resultado
    await cache.set(`user:${userId}`, profile, { ttl: 3600 })
    
    return profile
  }

  return {
    getUserProfile
  }
}
```

### 2. Regras de Negócio

Logic components aplicam regras de negócio e validação:

```tsx
async function createUser(userData: CreateUserInput): Promise<User> {
  // Regra de negócio: o username 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 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('User created', { userId: user.id })
  
  return user
}
```

### 3. Orquestração de Workflow

Logic components coordenam operações complexas em múltiplas etapas:

```tsx
async function publishContent(
  userId: string,
  content: ContentInput
): Promise<PublishedContent> {
  // Passo 1: Validar permissions
  const canPublish = await permissions.canUserPublish(userId)
  if (!canPublish) {
    throw new UnauthorizedError('User cannot publish content')
  }

  // Passo 2: Processar content
  const processed = await processContent(content)

  // Passo 3: Armazenar content
  const stored = await storage.save(processed)

  // Passo 4: Atualizar indexes
  await searchIndex.index(stored)

  // Passo 5: Notificar subscribers
  await notifications.notifySubscribers(userId, stored)

  logger.info('Content published', { contentId: stored.id, userId })

  return stored
}
```

## Boas Práticas

### 1. Responsabilidade Única

Cada logic component deve focar em um domínio ou contexto limitado:

```tsx
// Bom: Focado no domínio do user
createUserLogic()
createContentLogic()
createPermissionsLogic()

// Evitar: Responsabilidades mistas
createUserAndContentLogic()
```

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

Sempre injete dependências através do parâmetro components:

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

### 3. Tratamento de Erros

Lance erros de domínio significativos que controllers 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(`Insufficient inventory for product ${productId}. Requested: ${requested}`)
    this.name = 'InsufficientInventoryError'
  }
}
```

### 4. Business Logic Pura

Mantenha logic components livres de preocupações da camada de transporte:

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

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

## Testando Logic Components

Logic components devem ser exaustivamente testados unitariamente. Veja a [Testing Services (WKC)](/contributor/contributor-pt/guias-do-contribuidor/testing-standards/testing-services-wkc.md) documentation para detalhes.

```tsx
describe('when creating a user', () => {
  let userLogic: IUserLogic
  let mockDatabase: jest.Mocked<IDatabase>

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

  describe('and the username already exists', () => {
    beforeEach(() => {
      mockDatabase.query.mockResolvedValueOnce({ rows: [{ id: '123' }] })
    })

    it('should throw 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 domain-driven logic components
* Padrões para lidar com workflows complexos
* Diretrizes para organizar large domain logic
* Integração com event systems
* Estratégias de caching
* 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/contributor/contributor-pt/guias-do-contribuidor/componentes-bem-conhecidos/logic-components.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
