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

# Escrevendo uma ontologia

> A estrutura do arquivo YAML — nós, arestas, normalizadores e identificadores com nome próprio — campo a campo, com um exemplo completo que roda.

O arquivo tem três blocos: `nodes`, `edges` e, opcionalmente, `timeline`. Esta página cobre os dois primeiros, que é onde está toda a modelagem.

Antes de escrever, leia [Conceitos da ontologia](https://docs.strattum.ai/admin/ontology-concepts.md) — sobretudo a diferença entre `id_field` e `er_fields`.

***

## Um nó

```yaml theme={null}
nodes:
  - label: Cliente                 # o tipo. PascalCase, singular.
    source: clean/crm_contatos     # a tabela da clean. Sempre começa com clean/
    connector: postgres            # de qual conector veio (ícone na UI)
    connector_instance: crm_matriz # QUAL instância — dois CRMs não se misturam

    id_field: external_id          # cunha o id
    er_fields: [cpf, email]        # acha quem já existe
    normalizers: {matricula: text} # opcional — a regra de formato por campo
    identifier_columns: {}         # opcional — quando a coluna tem outro nome

    properties:                    # as colunas que viram propriedade do nó
      - external_id
      - nome
      - cpf
      - email
```

### Campo a campo

| Campo | Obrigatório | O que faz |
| - | - | - |
| `label` | sim | o tipo da entidade |
| `source` | sim | a tabela da clean |
| `id_field` | sim | a chave que cunha o id. Use a chave que o sistema já tem e que **não muda** — normalmente `external_id`. Nunca um campo que o usuário edita. |
| `er_fields` | não | os identificadores. Sem eles, o nó é local à sua fonte, e fica no caminho de ingestão mais rápido. |
| `properties` | sim | tudo que você quer ver no nó. Precisa conter o `id_field` e as colunas dos `er_fields`. |
| `indexed_fields` | não | as propriedades pelas quais se **filtra** (`cor`, `status`, `ano`). Cria índice no grafo. Não identificam nada — ver [Campos pesquisáveis](https://docs.strattum.ai/admin/ontology-searchable-fields.md). |
| `normalizers` | não | a regra de normalização por campo |
| `identifier_columns` | não | quando esta fonte chama o identificador de outra coisa |
| `connector` e `connector_instance` | recomendado | procedência; a instância é o que impede dois sistemas iguais de se fundirem |

***

## Normalizadores

A regra sai do **nome do campo**. `cpf` vira só dígitos porque se chama `cpf`.

```yaml theme={null}
er_fields: [cpf, matricula_imovel, placa]
normalizers:
  matricula_imovel: text    # "M-123456", " m-123456 " → "m-123456"
```

| Nome | O que faz | Exemplo |
| - | - | - |
| `cpf`, `cnpj` | só dígitos | `111.222.333-44` → `11122233344` |
| `email` | minúscula, tira o `+alias` | `Ana+x@X.COM` → `ana@x.com` |
| `phone` | E.164 | `(11) 99999-9999` → `+5511999999999` |
| `digits` | só dígitos, qualquer campo | `RG 12.345.678-9` → `123456789` |
| `alnum` | letras e dígitos, minúscula | `M-123.456` → `m123456` |
| `upper` e `title` | caixa alta, capitalizado | `ana souza` → `Ana Souza` |
| `text` | **o padrão** — trim e minúscula | ` M-123456` → `m-123456` |
| `verbatim` | só trim | preserva a caixa |

> [!WARNING]
>
> O padrão `text` **mantém a pontuação**. Uma coluna chamada `documento` guardando CPF cai no padrão, e `111.222.333-44` vira uma entidade diferente de `11122233344`.
>
> Declare a regra: `normalizers: {documento: cpf}`. O worker avisa no log quando detecta isso, mas é melhor declarar de cara.

***

## Quando a coluna tem outro nome

Uma fonte estrangeira chama o CPF de `ID_BRAZIL`. Sem dizer nada, ela chaveia como `id_brazil` e **nunca encontra** quem chama de `cpf`:

```yaml theme={null}
- label: Cliente
  source: clean/erp_estrangeiro
  id_field: external_id
  er_fields: [cpf]                       # o NOME é o que faz convergir
  identifier_columns: {cpf: ID_BRAZIL}   # a COLUNA é local desta fonte
  properties: [external_id, full_name, ID_BRAZIL]
```

A chave é o nome do identificador; o valor é a coluna desta fonte. O normalizador continua seguindo o **nome** — `ID_BRAZIL` é tratado como CPF porque é um CPF.

***

## Várias fontes, um label

É o caso normal: o mesmo conceito visto por vários sistemas. Repita o label, mude o `source`.

```yaml theme={null}
- label: Cliente
  source: clean/crm
  id_field: external_id
  er_fields: [cpf, email]        # o CRM tem e-mail
  properties: [external_id, nome, cpf, email]

- label: Cliente
  source: clean/erp
  id_field: external_id          # outra chave, outro namespace — tudo bem
  er_fields: [cpf, telefone]     # lista DIFERENTE — basta compartilhar o cpf
  properties: [external_id, nome, cpf, telefone]

- label: Cliente
  source: clean/rh
  id_field: external_id
  er_fields: [cpf, matricula]
  properties: [external_id, nome, cpf, matricula]
```

As listas **não precisam ser iguais**. Precisam formar uma **cadeia**: folha de pagamento e mailing podem não ter nada em comum, desde que o ERP conheça os dois.

O que é recusado é o conjunto **desconexo** — duas ilhas sem caminho entre si não são uma entidade, são duas.

***

## Uma aresta

```yaml theme={null}
edges:
  - type: POSSUI_VEICULO        # VERBO, maiúsculas com underscore
    source: clean/detran        # a tabela que tem AS DUAS colunas
    from:
      label: Cliente
      match_field: cpf
      source_column: cpf_proprietario
    to:
      label: Carro
      match_field: placa
      source_column: placa
```

### Por vários campos

Quando metade das linhas tem um identificador e a outra metade tem outro:

```yaml theme={null}
    from:
      label: Cliente
      match_field:   [cpf, email]
      source_column: [titular_cpf, titular_email]
```

Tenta na ordem; vence o primeiro que **realmente resolve**.

### `join_key` em vez de `match_field`

Quando a coluna aponta direto para o `id_field` do outro lado:

```yaml theme={null}
    to:
      label: Contrato
      join_key: id
```

***

## Exemplo completo que roda

Uma pessoa vista por três sistemas, com o carro dela:

```yaml theme={null}
version: "1"

nodes:
  - label: Cliente
    source: clean/sim_crm
    connector: postgres
    connector_instance: sim_crm
    id_field: external_id
    er_fields: [cpf, email]
    properties: [external_id, nome, cpf, email]

  - label: Cliente
    source: clean/sim_rh
    connector: postgres
    connector_instance: sim_rh
    id_field: external_id
    er_fields: [cpf, matricula]
    normalizers: {matricula: text}
    properties: [external_id, nome, cpf, matricula]

  - label: Carro
    source: clean/sim_detran
    connector: postgres
    connector_instance: sim_detran
    id_field: external_id
    er_fields: [placa, chassi, renavam]
    properties: [external_id, placa, chassi, renavam, modelo, cpf_proprietario]

  - label: Carro
    source: clean/sim_seguradora
    connector: postgres
    connector_instance: sim_seguradora
    id_field: external_id
    er_fields: [placa]              # a seguradora só tem a placa — e basta
    properties: [external_id, placa, cor, ano]

edges:
  - type: POSSUI_VEICULO
    source: clean/sim_detran
    from: {label: Cliente, match_field: cpf,   source_column: cpf_proprietario}
    to:   {label: Carro,   match_field: placa, source_column: placa}
```

Resultado: o CPF em três formatos vira **uma** pessoa; a placa em duas caixas vira **um** carro, com o chassi do DETRAN e a cor da seguradora no mesmo nó.

***

## Aplicando

```bash theme={null}
POST /v1/ontology            # salva uma versão nova (não ativa)
POST /v1/ontology/validate   # confere sem salvar
POST /v1/ontology/apply      # ativa  { "id": 12, "reset": false }
```

> [!WARNING]
>
> `reset: true` **apaga o grafo inteiro** antes de aplicar. Não é o caminho normal.

Para o dado que já existe ficar achável pelos identificadores novos, é preciso um re-scan: `POST /v1/memory/full-refresh`.

O procedimento completo, com os estados de versão e como reverter, está em [Gerenciar a ontologia](https://docs.strattum.ai/admin/manage-ontology.md).

***

## O que não vai aqui

**Nada de visualização.** Não existe `display_field`, e `display_tier` e `display_color` estão depreciados — aceitos e ignorados. O rótulo do nó é derivado (um campo de nome, senão o primeiro `er_field`, senão o `id_field`) e a cor sai do label. Duas pessoas lendo a mesma ontologia podem querer coisas diferentes na tela; isso não é do negócio.

**Nada de transformação.** Limpar, converter, juntar colunas — camada clean, em dbt. Se você precisa de um campo composto, crie a coluna lá e declare ela aqui.

> **[Campos pesquisáveis](https://docs.strattum.ai/admin/ontology-searchable-fields.md)**
>
> Por que você não acha uma coisa, e o que declarar para achar.

> **[Padrões e armadilhas](https://docs.strattum.ai/admin/ontology-patterns.md)**
>
> A regra de ouro, os erros que já aconteceram e o checklist antes do apply.


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