# Catálogo

> Fornecedores, produtos e preparações da casa: as listas de referência para as quais o resto do registo aponta.

Source: https://developers.backresto.com/pt/docs/catalogue

O catálogo é aquilo de que um restaurante mantém uma lista em vez de medir: quem
entrega, o que entra pela porta, e o que a cozinha faz por si. Nada aqui é um
controlo ou uma leitura. Estas são as linhas que tudo o resto nomeia, por isso
costumam ser a primeira coisa que carrega e a última que muda.

| Coleção | Scope | O que é um registo |
| --- | --- | --- |
| `suppliers` | `suppliers:read` | Uma empresa que entrega, e como chegar até ela. |
| `products` | `products:read` | Algo que o restaurante recebe e utiliza, pelo nome. |
| `preparations` | `preparations:read` | Algo que a cozinha faz, com o seu prazo de validade e os seus alergénios. |

As três partilham o [envelope de snapshot](https://developers.backresto.com/pt/docs/collections): `id`,
`deleted`, `capturedAt`, `receivedAt`, `sequence` e os restantes ficam ao lado
do `data` descrito abaixo.

## `suppliers`

Um registo por fornecedor que o restaurante tenha introduzido, tenha ou não
chegado alguma coisa deles ultimamente.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `name` | string, **obrigatório** | O fornecedor tal como o restaurante lhe chama. Texto livre, não um registo comercial. |
| `isDeleted` | boolean, **obrigatório** | A marca de retirada da própria aplicação. Não é o `deleted` do envelope. Veja abaixo. |
| `contactMethods` | object[] | Como chegar até eles. Cada entrada é `{ "type": string, "value": string }`. |
| `accountNumber` | string \| null | A conta do restaurante junto deste fornecedor, quando foi introduzida. |

```json
{
  "id": "1f3c2a76-5b94-4b0e-9c1a-6d8f0a2e7b31",
  "collection": "suppliers",
  "deleted": false,
  "capturedAt": "1789431600214",
  "receivedAt": "1789431604771",
  "sequence": "412",
  "data": {
    "name": "Metro Nanterre",
    "isDeleted": false,
    "contactMethods": [
      { "type": "phone", "value": "+33 1 41 20 30 40" },
      { "type": "email", "value": "commandes@example.test" }
    ],
    "accountNumber": "FR-884213"
  }
}
```

**`contactMethods[].type` não é uma enumeração.** O esquema diz string e fica-se
por aí, e os valores acima são uma ilustração e não uma lista. Trate-o num
`switch` com um caso por omissão, e mostre o `value` seja qual for a grafia do
`type`.

Uma [entrega](https://developers.backresto.com/pt/docs/deliveries) aponta para o seu fornecedor através de
`supplierDeliveriesId`, o `id` de um registo desta coleção. O nome, o número de
conta e o número de telefone vivem todos aqui.

## `products`

O que o restaurante recebe e utiliza. O registo é tão magro como parece.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `name` | string, **obrigatório** | O produto tal como o restaurante lhe chamou. |
| `isDeleted` | boolean, **obrigatório** | A marca de retirada da aplicação. Veja abaixo. |

```json
{
  "id": "6b0d4ea2-91c7-4f3d-a0be-2c5f7d1e8a44",
  "collection": "products",
  "deleted": false,
  "capturedAt": "1789431980551",
  "receivedAt": "1789432001903",
  "sequence": "413",
  "data": {
    "name": "Beurre doux 250 g",
    "isDeleted": false
  }
}
```

É este o registo todo: sem referência, sem categoria, sem unidade, sem
fornecedor. Se o seu modelo precisar de alguma dessas coisas, é a si que cabe
mantê-las, indexadas pelo `id` do envelope.

**Mais nada aponta para um produto por identificador.** Uma entrega regista o
que foi medido em `temperatureRecords[].product`, texto livre escrito durante o
controlo. Veja [entregas](https://developers.backresto.com/pt/docs/deliveries). Fazer corresponder isso a esta
lista é trabalho de comparação de texto do seu lado, e «Beurre doux 250 g» não
é «beurre doux». Faça-o se for preciso, mas não apresente o resultado como uma
junção.

## `preparations`

Algo feito na casa em vez de recebido: um molho, um caldo, uma terrina.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `name` | string, **obrigatório** | A preparação tal como a cozinha lhe chama. |
| `lifespan` | number, **obrigatório** | Quanto tempo se conserva. Um número e mais nada. |
| `allergens` | string[] | O que contém. Cadeias livres, não um conjunto fechado. |
| `isDeleted` | boolean, **obrigatório** | A marca de retirada da aplicação. Veja abaixo. |

```json
{
  "id": "c47e8b13-0a52-4d96-8f1b-73ae2905cd6f",
  "collection": "preparations",
  "deleted": false,
  "capturedAt": "1789455120087",
  "receivedAt": "1789455133642",
  "sequence": "418",
  "data": {
    "name": "Sauce béarnaise",
    "lifespan": 3,
    "allergens": ["oeuf", "lait"],
    "isDeleted": false
  }
}
```

**`lifespan` não traz unidade nenhuma.** O esquema dá-lhe um número e nada com
que o interpretar. Não escreva «3 dias» só porque três parece dias. Confirme o
que a aplicação quer dizer com isso para o restaurante que está a ler, e
identifique-o com clareza se não conseguir.

**`allergens` é uma lista de cadeias de caracteres, não uma lista
regulamentar.** As entradas vêm da aplicação na língua do restaurante. Não as
mapeie para os catorze alergénios nomeados sem verificar o que as cadeias dizem
de facto, e não trate uma lista vazia como um controlo de alergénios feito e
limpo: também significa que ninguém a preencheu.

## `isDeleted` não é `deleted`

Todas as coleções desta página trazem os dois, significam coisas diferentes, e
quem filtre por um deles fica com uma lista errada.

- **`deleted`, no envelope**, é o tombstone da cópia sombra. `true` significa
  que o registo foi apagado na aplicação e que o `data` desapareceu. É assim
  que fica a saber que alguma coisa desapareceu: [a página do
  envelope](https://developers.backresto.com/pt/docs/collections) tem as regras.
- **`isDeleted`, dentro do `data`**, é a marca de soft delete da própria
  aplicação sobre a linha. O registo continua lá, continua a ter o seu nome, e
  continua a chegar com `deleted: false`. O restaurante retirou-o: deixou de o
  oferecer nos seletores, e guardou-o para que os registos antigos continuem a
  resolver-se.

Por isso, filtre pelos dois. Respeite só o `deleted` e a sua lista de
fornecedores enche-se de fornecedores que o restaurante abandonou há dois anos.
Respeite só o `isDeleted` e fica com linhas que foram apagadas de vez, porque
um tombstone não tem `data` de onde ler a marca.

Ainda assim, guarde as linhas retiradas em vez de as deitar fora. Uma entrega de
março passado ainda aponta para um fornecedor que hoje está a `isDeleted: true`, e
resolver esse id num nome é a razão inteira por que tem esta lista.

## Ler o catálogo

Estas três são pequenas, mudam devagar e são precisas para quase tudo o resto, o
que faz delas a parte barata de uma sincronização e a parte fácil de errar sem
dar por isso.

- **Percorra-as primeiro, guarde-as, atualize-as com regularidade.** O catálogo
  inteiro de um restaurante são meia dúzia de páginas com `limit=100`. Guarde-o
  no seu próprio armazenamento, indexado pelo `id` do envelope, e resolva os
  nomes a partir daí em vez de ir buscar um por registo.
- **Os nomes mudam, os identificadores não.** `name` é texto livre que o
  restaurante edita durante o serviço. Guarde o `id` como a sua chave e trate o
  nome como uma etiqueta que vai atualizando, nunca como algo pelo qual unir.
- **A ausência também é ambígua aqui.** Um fornecedor que não apareça pode nunca
  ter sido introduzido, ou pode ainda não ter chegado até nós. Veja
  [a nota de aviso](https://developers.backresto.com/pt/docs/collections) antes de comunicar uma contagem.
