> ## 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.

# Incorporando o Fetcher Engine

> Importe o módulo Go do Fetcher Engine, forneça as portas de que ele precisa e construa-o com engine.New — com um exemplo autocontido que roda sem nenhuma infraestrutura.

Incorporar o [Fetcher Engine](/pt/fetcher/fetcher-engine-overview) leva três passos: **importe, forneça as portas de que ele precisa, construa com `engine.New`.** Nenhuma infraestrutura vem junto com a importação. Você liga apenas as partes que a sua aplicação hospedeira realmente usa.

## 1. Instalar

***

```bash theme={null}
go get github.com/LerianStudio/fetcher/pkg/engine
```

<Note>
  O Engine é um módulo Go distinto dos serviços do Fetcher (`github.com/LerianStudio/fetcher/v2`). Ele carrega zero dependências de terceiros e tem sua própria linha de versões, com tags prefixadas pelo caminho (`pkg/engine/vX.Y.Z`). A importação não traz nenhuma dependência dos serviços para o grafo do seu módulo.
</Note>

## 2. Fornecer as portas

***

O Engine depende apenas de interfaces fornecidas pelo hospedeiro. Uma porta é sempre obrigatória. Uma segunda é obrigatória apenas quando a persistência criptografada está ligada. As demais são opcionais, e o Engine degrada de forma controlada sem elas.

| Porta                    | Obrigatória?                                | Sem ela                                                                                                                                       |
| ------------------------ | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `ConnectorRegistry`      | **Sempre**                                  | `engine.New` falha e nenhum Engine existe                                                                                                     |
| `CredentialProtector`    | Apenas com `WithEncryptedPersistence(true)` | A construção falha quando a persistência criptografada está ligada; as credenciais chegam ao armazenamento sem proteção quando está desligada |
| `ConnectionStore`        | Opcional                                    | Toda operação exceto `Limits()` falha                                                                                                         |
| `ResultSink`             | Opcional                                    | O modo store fica indisponível e a extração roda em modo direct                                                                               |
| `SchemaCache`            | Opcional                                    | A descoberta de esquema sempre consulta a fonte de dados ao vivo                                                                              |
| `ExecutionStore`         | Opcional                                    | Sem rastreamento durável do estado de execução                                                                                                |
| `ActiveExecutionChecker` | Opcional                                    | Sem bloqueio por conflito em atualizações e exclusões de conexão                                                                              |
| `Observability`          | Opcional                                    | Os ganchos de tracing viram no-ops                                                                                                            |

A [referência de portas](/pt/fetcher/fetcher-engine-ports) documenta cada contrato e cada degradação por completo. Leia-a antes de decidir quais portas pular — "opcional" não quer dizer "inofensivo".

Para testes e primeiras execuções, o harness **`pkg/engine/memory`** fornece implementações em memória das portas de armazenamento: o registro de conectores, o connection store, o cache de esquemas, o result sink e o execution store. Você não precisa de MongoDB, Redis, RabbitMQ nem object storage para exercitar o Engine. O harness não traz um `CredentialProtector`, então um teste que ligue a persistência criptografada precisa fornecer um.

## 3. Construir, planejar, executar

***

Este exemplo é autocontido. Ele usa o harness em memória, então roda com zero infraestrutura.

```go theme={null}
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/LerianStudio/fetcher/pkg/engine"
	"github.com/LerianStudio/fetcher/pkg/engine/memory"
)

func main() {
	ctx := context.Background()

	// Provide ports. In production these are your real adapters (see pkg/enginecompat);
	// here the in-memory harness stands in so the example runs with zero infrastructure.
	store := memory.NewConnectionStore()
	registry := memory.NewConnectorRegistry()

	// Construct the Engine. WithConnectorRegistry is the only required option.
	eng, err := engine.New(
		engine.WithConnectorRegistry(registry),
		engine.WithConnectionStore(store),
	)
	if err != nil {
		log.Fatal(err)
	}

	// Every operation is scoped to a tenant — the sole isolation dimension.
	tenant, err := engine.NewTenantContext("tenant-123")
	if err != nil {
		log.Fatal(err)
	}

	// Register a connector for the datasource type, then persist a connection.
	conn := memory.NewTemplateConnector(memory.ConnectorBehavior{
		Schema: engine.SchemaSnapshot{
			ConfigName: "pg-main",
			Tables:     []engine.TableSnapshot{{Name: "public.users", Fields: []string{"id", "email"}}},
		},
		Rows: map[string][]map[string]any{
			"public.users": {{"id": 1, "email": "a@example.com"}},
		},
	})
	registry.Register("postgres", memory.NewConnectorFactory(conn))

	if _, err = eng.CreateConnection(ctx, tenant, engine.NewConnectionInput(engine.ConnectionInputParams{
		ConfigName: "pg-main",
		Type:       "postgres",
		Host:       "localhost",
		Port:       5432,
	})); err != nil {
		log.Fatal(err)
	}

	// Plan validates the request against the live schema and enforces limits.
	plan, err := eng.PlanExtraction(ctx, tenant, engine.ExtractionRequest{
		MappedFields: map[string]engine.FieldSelection{
			"pg-main": {"public.users": {"id", "email"}},
		},
	})
	if err != nil {
		log.Fatal(err)
	}

	// Execute. With no ResultSink wired, the Engine runs in Direct mode and returns
	// inline JSON bytes plus a SHA-256 integrity digest.
	result, err := eng.ExecuteExtraction(ctx, plan)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("rows=%d bytes=%d\n", result.Direct.RowCount, len(result.Direct.Data))
}
```

### O que o exemplo mostra

* **Uma única opção obrigatória.** `WithConnectorRegistry` é a única porta que `engine.New` exige. O armazenamento de conexões aqui é uma conveniência, mas pule-o e toda operação falha.
* **Validação no momento da construção.** `engine.New` rejeita uma porta passada como nil tipado, e não apenas um nil literal. Um hospedeiro mal configurado falha na construção, em vez de quebrar no primeiro uso.
* **Escopo de tenant em toda chamada.** `NewTenantContext` monta a única dimensão de isolamento que o Engine conhece. Ela carrega um ID de tenant e um ID de requisição opcional — sem organização e sem produto.
* **Planejar, depois executar.** `PlanExtraction` valida a requisição contra o esquema ao vivo e aplica os limites. `ExecuteExtraction` lê o plano.
* **Modo por composição.** O exemplo não liga nenhum `ResultSink`, então o Engine escolhe o modo direct e retorna os bytes inline com um digest SHA-256. Adicione um sink e o mesmo código retorna uma referência de storage. Veja [Modo Direct e modo Store](/pt/fetcher/fetcher-engine-overview#modo-direct-e-modo-store).

## Indo para produção

***

Troque o harness em memória pelos adaptadores reais. Os próprios serviços do Fetcher são a implementação de referência, e o código deles é público. Eles fazem a ponte entre as portas do Engine e a infraestrutura real, em `pkg/enginecompat`:

| Pacote de adaptador                 | Faz a ponte de                                                                                       |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `pkg/enginecompat/connectioncompat` | Armazenamento de conexões, acesso a conexões, contexto de tenant e o verificador de execuções ativas |
| `pkg/enginecompat/schemacompat`     | Cache de esquema, conector de esquema e construção de snapshots                                      |
| `pkg/enginecompat/datasource`       | Os drivers de fonte de dados por trás do contrato de conector                                        |
| `pkg/enginecompat/tablenorm`        | Normalização de nomes qualificados de tabela                                                         |

Veja como os serviços os ligam:

* **CRUD de conexões** — `components/manager/internal/bootstrap/connection_engine.go`
* **Descoberta e cache de esquema** — `components/manager/internal/bootstrap/schema_engine.go`
* **Planejar e executar a extração** — `components/worker/internal/bootstrap/extraction_engine.go`

Duas regras valem do harness até a produção:

1. **Os seus adaptadores são donos do escopo de tenant.** O Engine passa um contexto de tenant em toda chamada de porta e impõe a fronteira na própria borda. Um armazenamento que ignora o ID de tenant vaza dados entre tenants, e o Engine não consegue pegar isso por você.
2. **Os seus adaptadores são donos dos segredos.** O Engine chama `Protect` e `Reveal` e registra apenas a versão de chave retornada como metadado. Derivação, rotação e armazenamento de chaves ficam no seu hospedeiro.

## Próximos passos

***

<CardGroup cols={2}>
  <Card title="Referência de portas" icon="plug" href="/pt/fetcher/fetcher-engine-ports">
    Cada porta, seu contrato e o comportamento que você tem sem ela.
  </Card>

  <Card title="Visão geral do Engine" icon="cube" href="/pt/fetcher/fetcher-engine-overview">
    O modelo de três camadas, a fronteira de importação e os dois modos de resultado.
  </Card>
</CardGroup>
