# Cooling & food processes

> Cooling, freezing, reheating and transport. Four collections recording a temperature transition, and what an unfinished one looks like.

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

A hot dish that cools slowly spends hours in the range where bacteria
multiply, so the rule is to bring it down fast and to be able to show you
did. Four collections record that kind of transition. Three of them are a
transition in time (down, down further, back up), and the fourth is the
same idea in space.

| Collection | Scope | What a record is |
| --- | --- | --- |
| `cooling` | `cooling:read` | A hot product brought down to cold-storage temperature. |
| `freezing` | `freezing:read` | A product taken down to frozen. |
| `reheating` | `reheating:read` | A cold product brought back up to service temperature. |
| `transport` | `transport:read` | A product moved from one place to another, with the temperature at each end. |

All four share the [snapshot envelope](https://developers.backresto.com/en/docs/collections): `id`, `deleted`,
`capturedAt`, `receivedAt`, `sequence` and the rest sit beside the `data`
described below.

## `cooling`

One cycle: a product, when it started and how hot it was, when it finished and
how cold it was.

| Field | Type | Meaning |
| --- | --- | --- |
| `timestamp` | string, **required** | The record's own stamp, epoch milliseconds as a string. Not the cycle's clock. That is the two dates below. |
| `product` | string, **required** | What was cooled, as text. |
| `beginDate` | string, **required** | When the cycle started, epoch milliseconds as a string. |
| `beginTemperature` | number, **required** | The temperature it started at. |
| `endDate` | string \| null | When it finished. `null` while it has not. |
| `endTemperature` | number \| null | The temperature it finished at. `null` alongside `endDate`. |
| `reminderId` | string \| null | The reminder the app attached to the cycle, when there was one. |
| `userId` | string \| null | The [staff member](https://developers.backresto.com/en/docs/facilities) who recorded it, when the app recorded one. |

```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` is a name, not a reference.** There is no `productId` on these
records, so you cannot join them to `products` without matching strings, and
the strings are typed during service, in the language of the restaurant.

**`reminderId` is opaque.** No collection in this API resolves it. Carry it if
it helps you group records; do not expect to look it up.

## `freezing`

The same shape, for a product taken down to frozen rather than to fridge
temperature. Field for field, it is `cooling`.

| Field | Type | Meaning |
| --- | --- | --- |
| `timestamp` | string, **required** | The record's own stamp. |
| `product` | string, **required** | What was frozen. |
| `beginDate` | string, **required** | When the operation started. |
| `beginTemperature` | number, **required** | The temperature it started at. |
| `endDate` | string \| null | When it finished, or `null`. |
| `endTemperature` | number \| null | The temperature it finished at, or `null`. |
| `reminderId` | string \| null | As above. |
| `userId` | string \| null | Who recorded it. |

Nothing in the record says which of the three it is: that is the collection it
came from, and the envelope's `collection` field echoes it. A pipeline that
merges all three into one table needs to keep that column.

## `reheating`

A cold product brought back up. Same shape again, read in the other direction:
`beginTemperature` is the low one and `endTemperature` the high one.

| Field | Type | Meaning |
| --- | --- | --- |
| `timestamp` | string, **required** | The record's own stamp. |
| `product` | string, **required** | What was reheated. |
| `beginDate` | string, **required** | When it went in. |
| `beginTemperature` | number, **required** | The temperature it started at. |
| `endDate` | string \| null | When it came out, or `null`. |
| `endTemperature` | number \| null | The temperature it reached, or `null`. |
| `reminderId` | string \| null | As above. |
| `userId` | string \| null | Who recorded it. |

An operation with no end looks like this:

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

The same transition, in space rather than in time: where the product left
from and where it arrived, with a temperature at each end.

| Field | Type | Meaning |
| --- | --- | --- |
| `timestamp` | string, **required** | The record's own stamp. |
| `product` | string, **required** | What was transported, as text. |
| `departureLocation` | string, **required** | Where it left from, as text. |
| `departureTime` | string, **required** | When it left, epoch milliseconds as a string. |
| `departureTemperature` | number, **required** | The temperature on departure. |
| `arrivalLocation` | string \| null | Where it arrived. `null` while it has not. |
| `arrivalTime` | string \| null | When it arrived, or `null`. |
| `arrivalTemperature` | number \| null | The temperature on arrival, or `null`. |
| `reminderId` | string \| null | As above. |
| `userId` | string \| null | Who recorded it. |

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

The two locations are free text, not [areas](https://developers.backresto.com/en/docs/facilities) and not
addresses. They are whatever the person typed, and the arrival end is exactly
as optional as the arrival temperature: one record can carry a departure and
nothing else.

## Working with these

**A null end is two different things.** `endDate` and `endTemperature` (and
`arrivalTime`, `arrivalTemperature` and `arrivalLocation` on `transport`) are
nullable, and the record does not tell you why. It may be an operation still
running as you read it, or one nobody ever closed. Both look identical.

That matters the moment you compute a duration. The dates are strings, so
`endDate - beginDate` subtracts fine on a closed record and, on an open one,
coerces `null` to zero and hands you a large negative number instead of an
error. Nothing throws; your average is simply wrong. Filter to closed records
first, count the open ones separately, and decide for yourself at what age an
open record stops being in progress and starts being abandoned. Nothing in
this API makes that call for you.

**Compute on `beginDate` and `endDate`, not on `timestamp`.** The dates are the
operation's clock. `timestamp` is the record's own, and it is not the thing a
duration is made of.

**Report on `capturedAt`, sync on `receivedAt`.** A tablet in a cold room uploads
when it finds signal, so a cycle started at 09:00 can arrive at 14:00.
[The envelope page](https://developers.backresto.com/en/docs/collections) has the full story.

**Absence proves nothing.** A product with no cooling record may never have
been cooled, or may be sitting on a device that has not uploaded yet. Do not
turn a count of these into a compliance figure. See
[the caveat](https://developers.backresto.com/en/docs/support).
