# Raffreddamento e processi alimentari

> Raffreddamento, congelamento, riscaldamento e trasporto: quattro collezioni che registrano una transizione di temperatura, e che aspetto ha quella rimasta incompiuta.

Source: https://developers.backresto.com/it/docs/food-processes

Un piatto caldo che si raffredda lentamente passa ore nell'intervallo in cui i
batteri si moltiplicano, quindi la regola è abbassarne la temperatura in fretta
e poterlo dimostrare. Quattro collezioni registrano questo tipo di transizione.
Tre sono una transizione nel tempo (giù, ancora più giù, di nuovo su) e la
quarta è la stessa idea nello spazio.

| Collezione | Scope | Che cos'è un record |
| --- | --- | --- |
| `cooling` | `cooling:read` | Un prodotto caldo portato alla temperatura di conservazione a freddo. |
| `freezing` | `freezing:read` | Un prodotto portato fino al congelamento. |
| `reheating` | `reheating:read` | Un prodotto freddo riportato alla temperatura di servizio. |
| `transport` | `transport:read` | Un prodotto spostato da un luogo a un altro, con la temperatura a ciascuna estremità. |

Tutte e quattro 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.

## `cooling`

Un ciclo: un prodotto, quando è iniziato e quanto era caldo, quando è terminato
e quanto era freddo.

| Campo | Tipo | Significato |
| --- | --- | --- |
| `timestamp` | string, **obbligatorio** | La marca temporale del record stesso, millisecondi dall'epoch come stringa. Non l'orologio del ciclo: quello sono le due date qui sotto. |
| `product` | string, **obbligatorio** | Cosa è stato raffreddato, come testo. |
| `beginDate` | string, **obbligatorio** | Quando è iniziato il ciclo, millisecondi dall'epoch come stringa. |
| `beginTemperature` | number, **obbligatorio** | La temperatura di partenza. |
| `endDate` | string \| null | Quando è terminato. `null` finché non lo è. |
| `endTemperature` | number \| null | La temperatura di arrivo. `null` insieme a `endDate`. |
| `reminderId` | string \| null | Il promemoria che l'app ha associato al ciclo, quando ce n'era uno. |
| `userId` | string \| null | Il [membro del personale](https://developers.backresto.com/it/docs/facilities) che l'ha registrato, quando l'app ne ha registrato uno. |

```json
{
  "id": "0e5d1a7c-9f24-4b13-8d60-c1a7f0b25e94",
  "collection": "cooling",
  "deleted": false,
  "capturedAt": "1789779612441",
  "receivedAt": "1789779910228",
  "sequence": "1",
  "data": {
    "timestamp": "1789772400000",
    "product": "Blanquette de veau",
    "beginDate": "1789772400000",
    "beginTemperature": 63.5,
    "endDate": "1789779600000",
    "endTemperature": 8.2,
    "userId": "2774953d-8d9b-4a68-8ec4-1209edd90777"
  }
}
```

**`product` è un nome, non un riferimento.** Su questi record non esiste alcun
`productId`, quindi non può unirli a `products` senza confrontare stringhe, e
le stringhe vengono digitate durante il servizio, nella lingua del ristorante.

**`reminderId` è opaco.** Nessuna collezione di questa API lo risolve. Se le
serve per raggruppare i record, se lo porti dietro; non si aspetti di poterlo
consultare.

## `freezing`

La stessa forma, per un prodotto portato al congelamento anziché alla
temperatura del frigorifero. Campo per campo, è `cooling`.

| Campo | Tipo | Significato |
| --- | --- | --- |
| `timestamp` | string, **obbligatorio** | La marca temporale del record stesso. |
| `product` | string, **obbligatorio** | Cosa è stato congelato. |
| `beginDate` | string, **obbligatorio** | Quando è iniziata l'operazione. |
| `beginTemperature` | number, **obbligatorio** | La temperatura di partenza. |
| `endDate` | string \| null | Quando è terminata, oppure `null`. |
| `endTemperature` | number \| null | La temperatura di arrivo, oppure `null`. |
| `reminderId` | string \| null | Come sopra. |
| `userId` | string \| null | Chi l'ha registrata. |

Niente nel record dice quale delle tre sia: lo dice la collezione da cui
proviene, e il campo `collection` dell'involucro lo ripete. Una pipeline che
unisce tutte e tre in un'unica tabella deve conservare quella colonna.

## `reheating`

Un prodotto freddo riportato su. Di nuovo la stessa forma, letta nell'altra
direzione: `beginTemperature` è quella bassa ed `endTemperature` quella alta.

| Campo | Tipo | Significato |
| --- | --- | --- |
| `timestamp` | string, **obbligatorio** | La marca temporale del record stesso. |
| `product` | string, **obbligatorio** | Cosa è stato riscaldato. |
| `beginDate` | string, **obbligatorio** | Quando è stato messo dentro. |
| `beginTemperature` | number, **obbligatorio** | La temperatura di partenza. |
| `endDate` | string \| null | Quando è stato tirato fuori, oppure `null`. |
| `endTemperature` | number \| null | La temperatura raggiunta, oppure `null`. |
| `reminderId` | string \| null | Come sopra. |
| `userId` | string \| null | Chi l'ha registrato. |

Un'operazione senza fine si presenta così:

```json
{
  "id": "b4c8e21d-3a76-4f58-9c02-77ad5e1b8f30",
  "collection": "reheating",
  "deleted": false,
  "capturedAt": "1789783221907",
  "receivedAt": "1789783402115",
  "sequence": "2",
  "data": {
    "timestamp": "1789783200000",
    "product": "Gratin dauphinois",
    "beginDate": "1789783200000",
    "beginTemperature": 4.1,
    "endDate": null,
    "endTemperature": null,
    "userId": "2774953d-8d9b-4a68-8ec4-1209edd90777"
  }
}
```

## `transport`

La stessa transizione, nello spazio anziché nel tempo: da dove il prodotto è
partito e dove è arrivato, con una temperatura a ciascuna estremità.

| Campo | Tipo | Significato |
| --- | --- | --- |
| `timestamp` | string, **obbligatorio** | La marca temporale del record stesso. |
| `product` | string, **obbligatorio** | Cosa è stato trasportato, come testo. |
| `departureLocation` | string, **obbligatorio** | Da dove è partito, come testo. |
| `departureTime` | string, **obbligatorio** | Quando è partito, millisecondi dall'epoch come stringa. |
| `departureTemperature` | number, **obbligatorio** | La temperatura alla partenza. |
| `arrivalLocation` | string \| null | Dove è arrivato. `null` finché non è arrivato. |
| `arrivalTime` | string \| null | Quando è arrivato, oppure `null`. |
| `arrivalTemperature` | number \| null | La temperatura all'arrivo, oppure `null`. |
| `reminderId` | string \| null | Come sopra. |
| `userId` | string \| null | Chi l'ha registrato. |

```json
{
  "id": "f31b6a08-5c47-4de9-b1a5-6e0c9d247b82",
  "collection": "transport",
  "deleted": false,
  "capturedAt": "1789786944610",
  "receivedAt": "1789787101883",
  "sequence": "3",
  "data": {
    "timestamp": "1789785000000",
    "product": "Plats préparés, service traiteur",
    "departureLocation": "Cuisine centrale",
    "departureTime": "1789785000000",
    "departureTemperature": 3.4,
    "arrivalLocation": "Salle Montparnasse",
    "arrivalTime": "1789786800000",
    "arrivalTemperature": 5.9,
    "userId": "2774953d-8d9b-4a68-8ec4-1209edd90777"
  }
}
```

I due luoghi sono testo libero, non sono [aree](https://developers.backresto.com/it/docs/facilities) e non sono
indirizzi. Sono quello che la persona ha digitato, e il lato dell'arrivo è
opzionale esattamente quanto la temperatura di arrivo: un record può portare
una partenza e nient'altro.

## Lavorare con questi dati

**Una fine assente è due cose diverse.** `endDate` ed `endTemperature` (e
`arrivalTime`, `arrivalTemperature` e `arrivalLocation` su `transport`)
ammettono null, e il record non le dice perché. Può trattarsi di
un'operazione ancora in corso mentre la legge, oppure di una che nessuno ha
mai chiuso. Le due sono identiche a vedersi.

La cosa conta nel momento in cui calcola una durata. Le date sono stringhe,
quindi `endDate - beginDate` sottrae senza problemi su un record chiuso e, su
uno aperto, converte `null` in zero e le restituisce un numero negativo molto
grande anziché un errore. Non viene sollevata alcuna eccezione; semplicemente
la sua media è sbagliata. Filtri prima sui record chiusi, conti quelli aperti a
parte, e decida lei dopo quanto tempo un record aperto smette di essere in corso
e comincia a essere abbandonato: niente in questa API prende quella decisione
al posto suo.

**Calcoli su `beginDate` ed `endDate`, non su `timestamp`.** Le date sono
l'orologio dell'operazione. `timestamp` è quello del record, e non è la cosa di
cui è fatta una durata.

**Faccia i report su `capturedAt`, sincronizzi su `receivedAt`.** Un tablet in
una cella frigorifera carica i dati quando trova segnale, quindi un ciclo
iniziato alle 09:00 può arrivare alle 14:00.
[La pagina sull'involucro](https://developers.backresto.com/it/docs/collections) racconta tutta la storia.

**L'assenza non prova nulla.** Un prodotto senza alcun record di raffreddamento
può non essere mai stato raffreddato, oppure può trovarsi su un dispositivo che
non ha ancora caricato i dati. Non trasformi un conteggio di questi record in
un dato di conformità. Veda [l'avvertenza](https://developers.backresto.com/it/docs/support).
