# Facilities & people

> The site, its staff, its zones and its machines. The fixed map every temperature reading hangs off.

Source: https://developers.backresto.com/en/docs/facilities

These are the things that do not move: the restaurant itself, the people who
work in it, the zones it is divided into, and the machines that hold food at a
temperature. None of it is a check.

It still decides what the checks mean. A [temperature](https://developers.backresto.com/en/docs/temperatures) is a
number with no verdict attached until you read the thresholds off the equipment
it was taken on, and a reading belongs to a part of the building only because
the equipment says which area it stands in. Get this page wrong and every
figure downstream is wrong quietly.

| Collection | Scope | What a record is |
| --- | --- | --- |
| `restaurants` | `restaurants:read` | The site itself: name, address, closing days, settings. |
| `users` | `users:read` | A staff account that records checks. |
| `areas` | `areas:read` | A zone the site is divided into: kitchen, cold room, bar. |
| `equipment` | `equipment:read` | A fridge, a freezer, a cold-chain unit, with its thresholds. |
| `sensors` | `sensors:read` | A wireless probe, by MAC address. |
| `cooking-equipment` | `cooking-equipment:read` | An oven or other cooking unit, with its thresholds. |

All six 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.

## `restaurants`

The site your key is scoped to, as a record. One per restaurant, so this
collection is usually a single page.

| Field | Type | Meaning |
| --- | --- | --- |
| `name` | string, **required** | The site's name, as it is displayed in the app. |
| `address` | string, **required** | The postal address, as one string. |
| `closingDays` | string[], **required** | The days the site is shut. Plain strings, not constrained by the schema. |
| `exceptionalClosures` | object[] | One-off closures, each an object with `from` and `to`. |
| `detailedAddress` | object \| null | The address broken into parts, when the app holds it that way. |
| `deliveryAddress` | string \| null | Where goods are delivered, when it differs from `address`. |
| `deliveryDetailedAddress` | object \| null | The same, in parts. |
| `preferredLanguage` | string \| null | The language the restaurant works in. |
| `multiArea` | boolean \| null | Whether the site is split into more than one area. |
| `settings` | object \| null | App settings. The shape is the app's and it moves. |

```json
{
  "id": "e5a1d3c9-7b40-4a28-9df6-18c0b2e46a75",
  "collection": "restaurants",
  "deleted": false,
  "capturedAt": "1789300481002",
  "receivedAt": "1789300489517",
  "sequence": "7",
  "data": {
    "name": "Le Comptoir de Nanterre",
    "address": "12 rue des Anciennes Mairies, 92000 Nanterre",
    "closingDays": ["sunday"],
    "preferredLanguage": "fr",
    "multiArea": true
  }
}
```

The example shows the operational half only. Alongside it the record carries
the commercial one: `subscription`, `subscriptions`, `companyName`,
`billingAddress`, `billingEmail`, `tvaNumber`, `trialEndDate`, `customerId`,
`discount`. They exist, they are in the OpenAPI document, and this page will
not talk you through them.

**Read the operational fields and leave the commercial ones alone.** They
describe the restaurant's contract with us, not its kitchen. They are not a
billing API, they change for reasons that have nothing to do with food safety,
and an integration that renders a customer's subscription state back at them is
a support ticket waiting to happen.

**`closingDays` is a list of plain strings.** The schema puts no shape on them,
so read them and show them; do not switch on them and do not assume a
particular spelling or case.

## `users`

The staff accounts that record checks. This is who a
[temperature record's](https://developers.backresto.com/en/docs/temperatures) `userId` points at.

| Field | Type | Meaning |
| --- | --- | --- |
| `firstName` | string, **required** | Given name, as entered. |
| `lastName` | string, **required** | Family name, as entered. |
| `email` | string, **required** | The account's email address. |
| `phoneNumber` | string \| null | A contact number, when one was given. |
| `modules` | string[] | Which parts of the app this person uses. Free strings. |
| `preferredNotificationTime` | string \| null | When this person asked to be reminded. |
| `isChildren` | boolean \| null | An internal flag. The schema gives it no meaning; do not build on it. |
| `isDeleted` | boolean \| null | The app's own retirement flag, and nullable here, unlike elsewhere. |

```json
{
  "id": "2774953d-8d9b-4a68-8ec4-1209edd90777",
  "collection": "users",
  "deleted": false,
  "capturedAt": "1789315002664",
  "receivedAt": "1789315010218",
  "sequence": "31",
  "data": {
    "firstName": "Amina",
    "lastName": "Berthier",
    "email": "amina.berthier@example.test",
    "phoneNumber": null,
    "modules": ["temperatures", "cleaning"],
    "isDeleted": false
  }
}
```

**This is personal data.** `email`, `phoneNumber` and the two name fields
identify a real person, and they are in this API for one reason: a food-safety
record has to say who performed the check. That is the only job they have here.

So store the `id` and resolve a display name when you need one. Do not copy
contact details into your own tables, your logs, your analytics events or a
third-party tool because they happened to be in the payload. The restaurant is
the data controller for their staff, and every copy you make is one they now
have to account for.

`isDeleted` is nullable on this collection where it is required elsewhere, so
treat a missing flag as "not retired" rather than letting it fall through as
false-ish by accident. The difference between it and the envelope's `deleted`
is [explained on the catalogue page](https://developers.backresto.com/en/docs/catalogue).

## `areas`

A zone of the restaurant. Two fields, and far more important than two fields
suggest.

| Field | Type | Meaning |
| --- | --- | --- |
| `name` | string, **required** | The zone as the restaurant names it: kitchen, cold room, bar. |
| `isDeleted` | boolean, **required** | The app's retirement flag. See [the catalogue page](https://developers.backresto.com/en/docs/catalogue). |

```json
{
  "id": "9c2b17ae-4d80-4f55-b3e1-0a6c8f4d2b19",
  "collection": "areas",
  "deleted": false,
  "capturedAt": "1789301120440",
  "receivedAt": "1789301126871",
  "sequence": "12",
  "data": {
    "name": "Chambre froide",
    "isDeleted": false
  }
}
```

**`areaId` is how everything gets grouped by zone.** Equipment, cooking
equipment, fryers and cleaning tasks all carry one, and it is the only link
between a [reading](https://developers.backresto.com/en/docs/temperatures) and a part of the building. There is no
`areaId` on the records themselves: you get there through the equipment.

`areaId` is nullable everywhere it appears. A fridge with no area is normal.
It means nobody assigned it, usually on a single-room site where `multiArea` is
false. Group those under "unassigned" rather than dropping them.

## `equipment`

Fridges, freezers and other cold-chain units. The record that decides whether a
temperature was acceptable.

| Field | Type | Meaning |
| --- | --- | --- |
| `index` | integer, **required** | The position the restaurant gave it in its own list. Display order, not an identifier. |
| `type` | string, **required** | What kind of unit it is. An unconstrained string. Read it, and do not switch on it. |
| `name` | string, **required** | The unit as the kitchen calls it. |
| `min` | number \| null | The lowest acceptable temperature. |
| `max` | number \| null | The highest acceptable temperature. |
| `areaId` | string \| null | The area it stands in. |
| `equipmentSensorId` | string \| null | The sensor fitted to it, when there is one. |
| `state` | string \| null | The unit's current state, as an unconstrained string. |
| `outOfRangeCount` | number \| null | A count of out-of-range readings that the app maintains. |
| `isDeleted` | boolean, **required** | The app's retirement flag. |

```json
{
  "id": "84ce5c13-3237-40d4-901a-cbba59a6406f",
  "collection": "equipment",
  "deleted": false,
  "capturedAt": "1789302455901",
  "receivedAt": "1789302461330",
  "sequence": "58",
  "data": {
    "index": 2,
    "type": "freezer",
    "name": "Congélateur bas",
    "min": -22,
    "max": -18,
    "areaId": "9c2b17ae-4d80-4f55-b3e1-0a6c8f4d2b19",
    "equipmentSensorId": "b31f7d64-0e29-42ca-9a57-51d3c8e07f28",
    "state": "ok",
    "outOfRangeCount": 0,
    "isDeleted": false
  }
}
```

**`min` and `max` are the only verdict you get.** A
[temperature record](https://developers.backresto.com/en/docs/temperatures) carries a value, a time and the
equipment it was taken on. Nothing in it says whether it was fine. -14.4 °C
is a crisis in a fridge and a normal Tuesday in a freezer, and this record is
what tells the two apart. Every compliance figure you build joins here.

They are also nullable. When `min` or `max` is absent you have no threshold,
and the honest answer for that reading is "unknown", not "in range". Say so in
your interface rather than defaulting to green.

**Thresholds are the current ones, not the ones that applied.** The snapshot
gives you today's `min` and `max`; a reading from March was judged against
whatever was set in March, and the restaurant can change them at any time. If
you re-evaluate old readings against today's numbers (which is all this API
lets you do), label the result as your recalculation, not as what the kitchen
saw.

**`type` and `state` are unconstrained strings.** Both are single free-text
fields in the schema with no list behind them. Display them, group on them if
you must, and never let an unrecognised value fall through a switch into
silence.

**`outOfRangeCount` is the app's number, not yours.** The schema does not say
what window it covers, and you cannot rebuild it from the snapshots here.
Treat it as a signal from the app, and if you need a count you can defend,
compute your own from the readings and thresholds and label it as yours.

`equipmentSensorId` points from the equipment to its sensor. The sensor record
points back the other way. Both sides are nullable, and neither is guaranteed
to be filled in just because the other is.

## `sensors`

The wireless probes. Two fields, both optional.

| Field | Type | Meaning |
| --- | --- | --- |
| `macAddress` | string \| null | The probe's hardware address, how you tell one physical device from another. |
| `sensorEquipmentId` | string \| null | The equipment this sensor watches. |

```json
{
  "id": "b31f7d64-0e29-42ca-9a57-51d3c8e07f28",
  "collection": "sensors",
  "deleted": false,
  "capturedAt": "1789302501764",
  "receivedAt": "1789302509002",
  "sequence": "61",
  "data": {
    "macAddress": "F4:12:9D:3A:77:0B",
    "sensorEquipmentId": "84ce5c13-3237-40d4-901a-cbba59a6406f"
  }
}
```

Note the two field names, which are mirror images and easy to transpose:
equipment carries `equipmentSensorId`, a sensor carries `sensorEquipmentId`.
Read the wrong one and you get `undefined` with no error.

There is no name here, no battery level and no last-seen time. What a sensor
reported is on [`temperature-readings`](https://developers.backresto.com/en/docs/temperatures), and those are keyed
by `equipmentId` rather than by the sensor, so a probe that has gone quiet
looks exactly like one that had nothing to report.

## `cooking-equipment`

Ovens, holding cabinets and the rest of the hot side. Same idea as `equipment`,
with the cold-chain machinery stripped out.

| Field | Type | Meaning |
| --- | --- | --- |
| `index` | integer, **required** | Display order in the restaurant's own list. |
| `type` | string, **required** | What kind of unit it is. Unconstrained string. |
| `name` | string, **required** | The unit as the kitchen calls it. |
| `min` | number \| null | The lowest acceptable temperature. |
| `max` | number \| null | The highest acceptable temperature. |
| `areaId` | string \| null | The area it stands in. |
| `isDeleted` | boolean, **required** | The app's retirement flag. |

```json
{
  "id": "3d90f4c8-62b7-4e13-8a05-ff71d6b9c204",
  "collection": "cooking-equipment",
  "deleted": false,
  "capturedAt": "1789303880115",
  "receivedAt": "1789303887640",
  "sequence": "64",
  "data": {
    "index": 1,
    "type": "oven",
    "name": "Four à sole",
    "min": 63,
    "max": 260,
    "areaId": "9c2b17ae-4d80-4f55-b3e1-0a6c8f4d2b19",
    "isDeleted": false
  }
}
```

No `state`, no `outOfRangeCount`, no sensor: cooking units are read by a
person, so there is nothing watching them between checks. Their readings are
[`cooking-temperature-records`](https://developers.backresto.com/en/docs/temperatures), which point here with
`cookingEquipmentId`, a different field name from the cold-chain one, and the
usual place a client silently reads nothing.

## Reading the map

Everything on this page is small, slow-moving and needed before any other
collection makes sense.

- **Load it first and hold it.** Walk `areas`, `equipment`,
  `cooking-equipment` and `sensors` before you walk any record collection, and
  resolve names and thresholds from your own copy rather than per record.
- **Refresh it anyway.** Equipment gets renamed, thresholds get corrected, a
  fridge moves to another area. A copy taken once and never walked again drifts
  without ever failing.
- **Keep ids, not copies, especially for people.** Store `userId` and resolve
  a name at render time. See the personal-data note above.
- **Both delete flags, everywhere.** The envelope's `deleted` and `data`'s
  `isDeleted` are different things, and
  [the catalogue page](https://developers.backresto.com/en/docs/catalogue) explains which is which.
