# Catalogo

> Fornitori, prodotti e preparazioni interne: gli elenchi di riferimento che tutto il resto del registro indica.

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

Il catalogo è ciò di cui un ristorante tiene un elenco anziché misurarlo: chi
consegna, cosa entra dalla porta, e cosa la cucina prepara da sé. Qui niente è
un controllo o una lettura. Sono le righe che tutto il resto nomina, quindi di
solito sono la prima cosa che carica e l'ultima che cambia.

| Collezione | Scope | Che cos'è un record |
| --- | --- | --- |
| `suppliers` | `suppliers:read` | Un'azienda che consegna, e come raggiungerla. |
| `products` | `products:read` | Qualcosa che il ristorante riceve e utilizza, per nome. |
| `preparations` | `preparations:read` | Qualcosa che la cucina prepara, con la sua durata di conservazione e i suoi allergeni. |

Tutte e tre condividono l'[involucro di snapshot](https://developers.backresto.com/it/docs/collections): `id`,
`deleted`, `capturedAt`, `receivedAt`, `sequence` e gli altri stanno accanto al
`data` descritto qui sotto.

## `suppliers`

Un record per ogni fornitore che il ristorante ha inserito, che da lui sia
arrivato qualcosa di recente o no.

| Campo | Tipo | Significato |
| --- | --- | --- |
| `name` | string, **obbligatorio** | Il fornitore come lo nomina il ristorante. Testo libero, non un registro delle imprese. |
| `isDeleted` | boolean, **obbligatorio** | L'indicatore di dismissione proprio dell'app. Non è il `deleted` dell'involucro. Veda qui sotto. |
| `contactMethods` | object[] | Come raggiungerlo. Ogni voce è `{ "type": string, "value": string }`. |
| `accountNumber` | string \| null | Il conto del ristorante presso questo fornitore, quando ne è stato inserito uno. |

```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` non è un enum.** Lo schema dice stringa e si ferma lì,
e i valori qui sopra sono un'illustrazione anziché un elenco. Ci faccia uno
switch con un ramo predefinito, e mostri il `value` comunque sia scritto il
`type`.

Una [consegna](https://developers.backresto.com/it/docs/deliveries) punta al suo fornitore tramite
`supplierDeliveriesId`, l'`id` di un record di questa collezione. Il nome, il
numero di conto e il numero di telefono stanno tutti qui.

## `products`

Cosa il ristorante riceve e utilizza. Il record è scarno quanto sembra.

| Campo | Tipo | Significato |
| --- | --- | --- |
| `name` | string, **obbligatorio** | Il prodotto come lo ha nominato il ristorante. |
| `isDeleted` | boolean, **obbligatorio** | L'indicatore di dismissione dell'app. Veda qui sotto. |

```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
  }
}
```

Il record è tutto qui: nessun riferimento, nessuna categoria, nessuna unità,
nessun fornitore. Se il suo modello ha bisogno di qualcuna di queste cose, sta a
lei tenerla, con chiave l'`id` dell'involucro.

**Nient'altro punta a un prodotto tramite id.** Una consegna registra cosa è
stato misurato come `temperatureRecords[].product`, testo libero digitato
durante il controllo. Veda [consegne](https://developers.backresto.com/it/docs/deliveries). Far corrispondere
quello a questo elenco è lavoro sulle stringhe dalla sua parte, e
«Beurre doux 250 g» non è «beurre doux». Lo faccia se deve, ma non presenti il
risultato come una join.

## `preparations`

Qualcosa fatto in casa anziché ricevuto: una salsa, un fondo, una terrina.

| Campo | Tipo | Significato |
| --- | --- | --- |
| `name` | string, **obbligatorio** | La preparazione come la nomina la cucina. |
| `lifespan` | number, **obbligatorio** | Quanto si conserva. Un numero e basta. |
| `allergens` | string[] | Cosa contiene. Stringhe libere, non un insieme chiuso. |
| `isDeleted` | boolean, **obbligatorio** | L'indicatore di dismissione dell'app. Veda qui sotto. |

```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` non porta alcuna unità.** Lo schema le dà un numero e nulla con cui
interpretarlo. Non stampi «3 giorni» solo perché quel tre sembra un numero di
giorni. Verifichi cosa intenda l'app per il ristorante che sta leggendo, e lo
etichetti in modo esplicito se non ci riesce.

**`allergens` è un elenco di stringhe, non un elenco normativo.** Le voci
arrivano dall'app nella lingua del ristorante. Non le mappi sui quattordici
allergeni nominati senza controllare cosa dicano davvero le stringhe, e non
tratti un array vuoto come un controllo degli allergeni superato: significa
anche che nessuno l'ha compilato.

## `isDeleted` non è `deleted`

Ogni collezione di questa pagina porta entrambi, significano cose diverse, e chi
consuma i dati filtrando su uno solo dei due ottiene un elenco sbagliato.

- **`deleted`, sull'involucro**, è il tombstone della copia shadow. `true`
  significa che il record è stato cancellato nell'app e che `data` non c'è più.
  È così che viene a sapere che qualcosa è sparito. Le regole sono nella
  [pagina sull'involucro](https://developers.backresto.com/it/docs/collections).
- **`isDeleted`, dentro `data`**, è l'indicatore di soft delete dell'app sulla
  riga. Il record è ancora lì, ha ancora il suo nome, e arriva
  ancora con `deleted: false`. Il ristorante l'ha dismesso: ha smesso di
  proporlo nei selettori, e l'ha tenuto perché i vecchi record si risolvano
  ancora.

Quindi filtri su entrambi. Rispetti solo `deleted` e il suo elenco di fornitori
si riempie di fornitori che il ristorante ha abbandonato due anni fa. Rispetti
solo `isDeleted` e si tiene righe che sono state cancellate del tutto, perché un
tombstone non ha alcun `data` da cui leggere l'indicatore.

Conservi però le righe dismesse anziché scartarle. Una consegna dello scorso
marzo punta ancora a un fornitore che oggi è `isDeleted: true`, e risolvere
quell'id in un nome è l'intera ragione per cui tiene questo elenco.

## Leggere il catalogo

Queste tre sono piccole, cambiano lentamente e servono a quasi tutto il resto,
il che ne fa la parte economica di una sincronizzazione e la parte facile da
sbagliare in modo sottile.

- **Le percorra per prime, le tenga, le aggiorni a intervalli regolari.**
  L'intero catalogo di un ristorante è una manciata di pagine a `limit=100`. Lo
  tenga nel suo archivio con chiave l'`id` dell'involucro, e risolva i nomi da
  lì anziché recuperarli per ogni record.
- **I nomi cambiano, gli id no.** `name` è testo libero che il ristorante
  modifica durante il servizio. Memorizzi l'`id` come sua chiave e tratti il
  nome come un'etichetta da aggiornare, mai come qualcosa su cui fare una join.
- **Anche qui l'assenza è ambigua.** Un fornitore che non compare può non essere
  mai stato inserito, oppure può non essere ancora arrivato a noi. Veda
  [l'avvertenza](https://developers.backresto.com/it/docs/collections) prima di comunicare un conteggio.
