> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Arquitetura do Reporter

> Como o Reporter roda: um binário cujo RUN_MODE seleciona a superfície da API, a superfície do worker, ou ambas, a fila entre elas, e os armazenamentos que compartilham.

O Reporter é entregue como um binário. `RUN_MODE` seleciona quais superfícies esse binário serve: `api`, `worker`, ou `all`. A API e o worker são dois papéis do mesmo programa, não dois produtos. Eles compartilham um build, uma versão, e um release.

Você escolhe uma topologia no momento do deploy, definindo uma variável de ambiente.

## Duas superfícies, um binário

***

| Superfície | `RUN_MODE` | Serve |
| - | - | - |
| API | `api` | Toda operação REST na porta `4005`, além de `/health` e `/version`. Um listener de health em `HEALTH_PORT` carrega `/health`, `/readyz` e `/metrics`. |
| Worker | `worker` | Nenhuma superfície REST. Consome a fila de relatórios. Um listener de health em `HEALTH_PORT`, que o worker exige, carrega `/health`, `/readyz` e `/metrics`. |
| Ambas | `all` | Ambas as superfícies em um único processo. |

```bash theme={null}
# API surface
RUN_MODE=api
SERVER_ADDRESS=:4005
HEALTH_PORT=8099

# Worker surface
RUN_MODE=worker
HEALTH_PORT=8099
```

Execute `all` quando um processo é suficiente, o que é a escolha usual para desenvolvimento local e deployments pequenos. Divida os papéis em dois deployables quando a geração de relatórios precisar escalar por conta própria. Renderizar um PDF grande custa muito mais do que aceitar a requisição que o pediu. Deployments separados permitem dimensionar cada lado para a própria carga.

## O caminho que um relatório percorre

***

**1. A API aceita a requisição**

Um `POST` para `/v1/reports` nomeia um template e os filtros dele. O Reporter obtém um lock de idempotência primeiro. A chave do lock é o header `X-Idempotency` quando você envia um, e um hash do corpo da requisição quando você não envia. O Reporter rejeita uma duplicata que ainda está em andamento. Uma duplicata de uma requisição concluída repete o relatório original e marca a resposta como uma repetição.

**2. A API valida e persiste**

O Reporter carrega o mapa de campos e o formato de saída do template. Em seguida, ele verifica os campos de filtro contra o schema de cada fonte de dados, e grava o relatório com status `Processing`.

**3. A API enfileira o trabalho**

Ela publica uma mensagem de comando na fila interna do RabbitMQ e responde `201 Created` com o relatório `Processing`. Quem chamou não precisa fazer mais nada. A renderização ainda não começou.

**4. O worker renderiza**

O worker consome o comando. Ele pula o comando se o relatório já chegou a um status terminal. Ele carrega o template do armazenamento de objetos e extrai os dados de cada fonte de dados. Ele renderiza o documento e o converte para PDF quando o formato exige. Ele envia o artefato.

**5. O worker consolida o estado**

Ele grava `Finished`, `Partial`, ou `Error`, ou `Draft` para uma remessa regulatória, e emite o evento correspondente. A operação de download entrega o artefato de um relatório `Finished` ou `Final`, e de um `Draft` sem campo obrigatório em branco.

## A fila entre elas

***

A API e o worker se comunicam por uma fila do RabbitMQ que carrega comandos de relatório em uma direção, com uma dead-letter queue atrás dela. Essa fila funciona como infraestrutura interna entre as duas superfícies do mesmo binário. Ela não é um ponto de integração, não carrega nenhum contrato sobre o qual você deveria construir, e a exchange, a fila, e a routing key dela são todas configuradas pelo operador.

Eventos de negócio são um canal separado. O Reporter os publica na própria exchange deles, que o operador configura e que o valor de referência do deployment nomeia como `reporter.events`. Toda emissão acontece depois do commit no banco de dados e nunca falha o trabalho que a produziu. Eventos de alto valor passam por um outbox durável em vez de uma publicação direta, então uma indisponibilidade do broker os atrasa em vez de perdê-los.

## Extração de dados

***

O worker acessa os seus bancos de dados pelo motor de extração embarcado dele, sem consultas escritas à mão e sem salto de rede para um serviço separado.

O motor limita cada extração de uma fonte de dados. Os padrões permitem 20 tabelas por fonte de dados e 50 campos por tabela. Falhas não encerram a execução. Um relatório cujas seções têm sucesso parcial renderiza a partir do que tem. Ele se consolida como `Partial` e registra quais seções falharam.

## Armazenamentos e artefatos

***

| Dependência | Papel |
| - | - |
| MongoDB | Templates, relatórios, prazos, instituições, inscrições regulatórias, e o outbox de eventos. |
| RabbitMQ | A fila interna de relatórios e a exchange de eventos de negócio. |
| Redis ou Valkey | Locks de idempotência, o cache de schema, e os sinais de ciclo de vida do tenant. |
| Armazenamento de objetos compatível com S3 | Arquivos de template e artefatos renderizados, em um único bucket. |

O armazenamento de objetos é compatível com S3: o Reporter fala o protocolo S3 e qualquer serviço que o responda funciona como destino. As fontes de template chegam sob o prefixo `templates/`, e os artefatos renderizados sob `reports/`, indexados pelo identificador do template e do relatório com o formato de saída como extensão. O Reporter não aplica nenhuma expiração própria, então a retenção é uma política de ciclo de vida que você define no bucket.

## Reporter e Midaz

***

O Midaz é uma **fonte de dados** para o Reporter, não uma dependência em tempo de execução. Você registra um banco de dados Midaz da mesma forma que qualquer outro banco de dados PostgreSQL. Templates o endereçam pelo `configName` que o operador escolheu.

Duas consequências decorrem disso. O Reporter inicia e serve templates, prazos, e métricas sem nenhuma fonte de dados configurada, então uma indisponibilidade do Midaz nunca impede o Reporter de rodar. E o mesmo deployment pode gerar relatórios sobre o Midaz, sobre os seus próprios bancos de dados, e sobre ambos em um único template.

Aponte o Reporter para uma read replica onde uma existir. O caminho de extração apenas lê, mas a carga de consultas de um relatório pesado é real, e uma replica mantém essa carga fora do caminho de escrita do ledger.

> [!NOTE]
>
> Veja [Conectando o Reporter ao Midaz](https://docs.lerian.studio/pt/products/reporter/connecting-reporter-to-midaz.md) para as variáveis, a convenção do `configName`, e como confirmar que a fonte está visível.

## Saúde e readiness

***

Os probes alcançam `/health` e `/readyz` sem um token. A porta da API responde `/health` com um 200 constante e serve `/version` com a proveniência do build. O `/readyz` fica no listener de health, que reporta as dependências que o processo realmente usa. Ele responde 503 até que as verificações de inicialização passem pela primeira vez, para que um orquestrador segure o tráfego de um pod que não conseguiu alcançá-las.

Leia a [referência de saúde e readiness](https://docs.lerian.studio/pt/reference/health-and-readiness.md) para o contrato de probe compartilhado entre os produtos Lerian.

## Próximos passos

***

> [card] [Conceitos essenciais](https://docs.lerian.studio/pt/products/reporter/reporter-core-concepts.md)
>
> Templates, fontes de dados, relatórios, prazos, e os estados de relatório.

> [card] [Variáveis de ambiente](https://docs.lerian.studio/pt/products/reporter/reporter-environment-variables.md)
>
> Toda configuração que molda um deployment do Reporter.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.