# Équipements et personnes

> Le site, son personnel, ses zones et ses machines : la carte fixe à laquelle se rattache chaque relevé de température.

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

Voici les choses qui ne bougent pas : le restaurant lui-même, les personnes qui
y travaillent, les zones dans lesquelles il est découpé, et les machines qui
maintiennent les denrées à une température. Rien de tout cela n'est un
contrôle.

Cela décide pourtant de ce que veulent dire les contrôles. Une
[température](https://developers.backresto.com/fr/docs/temperatures) est un nombre sans verdict attaché tant que
vous n'avez pas lu les seuils sur l'équipement où elle a été prise, et un
relevé n'appartient à une partie du bâtiment que parce que l'équipement dit
dans quelle zone il se trouve. Ratez cette page et tous les chiffres en aval
sont faux en silence.

| Collection | Scope | Ce qu'est un enregistrement |
| --- | --- | --- |
| `restaurants` | `restaurants:read` | Le site lui-même : nom, adresse, jours de fermeture, paramètres. |
| `users` | `users:read` | Un compte du personnel qui enregistre des contrôles. |
| `areas` | `areas:read` | Une zone dans laquelle le site est découpé : cuisine, chambre froide, bar. |
| `equipment` | `equipment:read` | Un réfrigérateur, un congélateur, un équipement de la chaîne du froid, avec ses seuils. |
| `sensors` | `sensors:read` | Une sonde sans fil, par adresse MAC. |
| `cooking-equipment` | `cooking-equipment:read` | Un four ou un autre équipement de cuisson, avec ses seuils. |

Toutes les six partagent l'[enveloppe de snapshot](https://developers.backresto.com/fr/docs/collections) : `id`,
`deleted`, `capturedAt`, `receivedAt`, `sequence` et le reste entourent le
`data` décrit ci-dessous.

## `restaurants`

Le site auquel votre clé est limitée, sous forme d'enregistrement. Un par
restaurant : cette collection tient donc en général sur une seule page.

| Champ | Type | Signification |
| --- | --- | --- |
| `name` | string, **obligatoire** | Le nom du site, tel qu'il est affiché dans l'application. |
| `address` | string, **obligatoire** | L'adresse postale, en une seule chaîne de caractères. |
| `closingDays` | string[], **obligatoire** | Les jours où le site est fermé. Des chaînes simples, que le schéma ne contraint pas. |
| `exceptionalClosures` | object[] | Les fermetures ponctuelles, chacune un objet avec `from` et `to`. |
| `detailedAddress` | object \| null | L'adresse découpée en parties, quand l'application la détient ainsi. |
| `deliveryAddress` | string \| null | Où les marchandises sont livrées, quand cela diffère d'`address`. |
| `deliveryDetailedAddress` | object \| null | La même, en parties. |
| `preferredLanguage` | string \| null | La langue dans laquelle le restaurant travaille. |
| `multiArea` | boolean \| null | Si le site est découpé en plus d'une zone. |
| `settings` | object \| null | Les paramètres de l'application. La forme appartient à l'application et elle bouge. |

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

L'exemple ne montre que la moitié opérationnelle. À côté, l'enregistrement
porte la moitié commerciale : `subscription`, `subscriptions`, `companyName`,
`billingAddress`, `billingEmail`, `tvaNumber`, `trialEndDate`, `customerId`,
`discount`. Ils existent, ils sont dans le document OpenAPI, et cette page ne
vous les expliquera pas.

**Lisez les champs opérationnels et laissez les champs commerciaux
tranquilles.** Ils décrivent le contrat du restaurant avec nous, pas sa
cuisine. Ce n'est pas une API de facturation, ils changent pour des raisons qui
n'ont rien à voir avec la sécurité alimentaire, et une intégration qui renvoie
à un client l'état de son abonnement est un ticket de support en devenir.

**`closingDays` est une liste de chaînes simples.** Le schéma ne leur impose
aucune forme : lisez-les et affichez-les ; n'aiguillez pas dessus et ne
supposez ni orthographe ni casse particulière.

## `users`

Les comptes du personnel qui enregistrent les contrôles. C'est vers eux que
pointe le `userId` d'un [enregistrement de température](https://developers.backresto.com/fr/docs/temperatures).

| Champ | Type | Signification |
| --- | --- | --- |
| `firstName` | string, **obligatoire** | Le prénom, tel qu'il a été saisi. |
| `lastName` | string, **obligatoire** | Le nom de famille, tel qu'il a été saisi. |
| `email` | string, **obligatoire** | L'adresse e-mail du compte. |
| `phoneNumber` | string \| null | Un numéro de contact, quand il a été donné. |
| `modules` | string[] | Les parties de l'application que cette personne utilise. Des chaînes libres. |
| `preferredNotificationTime` | string \| null | Quand cette personne a demandé à être rappelée. |
| `isChildren` | boolean \| null | Un indicateur interne. Le schéma ne lui donne aucun sens ; ne construisez rien dessus. |
| `isDeleted` | boolean \| null | L'indicateur de retrait propre à l'application. Il peut être `null` ici, contrairement à ailleurs. |

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

**Ce sont des données personnelles.** `email`, `phoneNumber` et les deux champs
de nom identifient une personne réelle, et ils sont dans cette API pour une
seule raison : un enregistrement de sécurité alimentaire doit dire qui a
effectué le contrôle. C'est leur unique rôle ici.

Stockez donc l'`id` et résolvez un nom d'affichage quand vous en avez besoin.
Ne recopiez pas les coordonnées dans vos propres tables, vos journaux, vos
événements d'analyse ou un outil tiers sous prétexte qu'elles se trouvaient
dans le payload. Le restaurant est le responsable de traitement pour son
personnel, et chaque copie que vous faites est une copie dont il doit désormais
rendre compte.

`isDeleted` peut être `null` sur cette collection alors qu'il est obligatoire
ailleurs : traitez un indicateur absent comme "non retiré" plutôt que de le
laisser glisser vers un `false` par accident. La différence entre lui et le
`deleted` de l'enveloppe est
[expliquée sur la page du catalogue](https://developers.backresto.com/fr/docs/catalogue).

## `areas`

Une zone du restaurant. Deux champs, et bien plus importante que deux champs ne
le laissent croire.

| Champ | Type | Signification |
| --- | --- | --- |
| `name` | string, **obligatoire** | La zone telle que le restaurant la nomme : cuisine, chambre froide, bar. |
| `isDeleted` | boolean, **obligatoire** | L'indicateur de retrait de l'application. Voyez [la page du catalogue](https://developers.backresto.com/fr/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` est ce qui permet de tout grouper par zone.** Les équipements, les
équipements de cuisson, les friteuses et les tâches de nettoyage en portent
tous un, et c'est le seul lien entre un [relevé](https://developers.backresto.com/fr/docs/temperatures) et une
partie du bâtiment. Il n'y a pas d'`areaId` sur les enregistrements eux-mêmes :
vous y arrivez par l'équipement.

`areaId` peut être `null` partout où il apparaît. Un réfrigérateur sans zone
est normal : cela veut dire que personne ne la lui a attribuée, en général sur
un site d'une seule pièce où `multiArea` est faux. Groupez ceux-là sous
"non attribué" plutôt que de les jeter.

## `equipment`

Réfrigérateurs, congélateurs et autres équipements de la chaîne du froid.
L'enregistrement qui décide si une température était acceptable.

| Champ | Type | Signification |
| --- | --- | --- |
| `index` | integer, **obligatoire** | La position que le restaurant lui a donnée dans sa propre liste. Un ordre d'affichage, pas un identifiant. |
| `type` | string, **obligatoire** | Le genre d'équipement dont il s'agit. Une chaîne non contrainte. Lisez-la, n'aiguillez pas dessus. |
| `name` | string, **obligatoire** | Le nom que la cuisine lui donne. |
| `min` | number \| null | La température la plus basse acceptable. |
| `max` | number \| null | La température la plus haute acceptable. |
| `areaId` | string \| null | La zone où il se trouve. |
| `equipmentSensorId` | string \| null | La sonde qui y est installée, quand il y en a une. |
| `state` | string \| null | L'état actuel de l'équipement, sous forme de chaîne non contrainte. |
| `outOfRangeCount` | number \| null | Un décompte des relevés hors plage que l'application tient à jour. |
| `isDeleted` | boolean, **obligatoire** | L'indicateur de retrait de l'application. |

```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` et `max` sont le seul verdict que vous obtiendrez.** Un
[enregistrement de température](https://developers.backresto.com/fr/docs/temperatures) porte une valeur, une heure
et l'équipement sur lequel elle a été prise. Rien n'y dit si c'était bon.
-14,4 °C est une crise dans un réfrigérateur et un mardi ordinaire dans un
congélateur, et c'est cet enregistrement qui fait la différence entre les deux.
Tous les chiffres de conformité que vous construisez passent par cette
jointure.

Ils peuvent aussi être `null`. Quand `min` ou `max` est absent, vous n'avez pas
de seuil, et la réponse honnête pour ce relevé est "inconnu", pas "dans la
plage". Dites-le dans votre interface plutôt que de basculer par défaut sur le
vert.

**Les seuils sont ceux d'aujourd'hui, pas ceux qui s'appliquaient.**
Le snapshot vous donne les `min` et `max` du jour ; un relevé de mars a été
jugé sur ce qui était réglé en mars, et le restaurant peut les changer à tout
moment. Si vous réévaluez d'anciens relevés avec les chiffres d'aujourd'hui
(ce qui est tout ce que cette API permet), présentez le résultat comme votre
recalcul, pas comme ce que la cuisine a vu.

**`type` et `state` sont des chaînes non contraintes.** Ce sont dans le schéma
deux simples champs de texte libre, sans aucune liste derrière. Affichez-les,
groupez dessus s'il le faut, et ne laissez jamais une valeur non reconnue
traverser un aiguillage pour tomber dans le silence.

**`outOfRangeCount` est le chiffre de l'application, pas le vôtre.** Le schéma
ne dit pas quelle fenêtre il couvre, et vous ne pouvez pas le reconstruire à
partir des snapshots disponibles ici. Traitez-le comme un signal venu de
l'application, et si vous avez besoin d'un décompte défendable, calculez le
vôtre à partir des relevés et des seuils, et présentez-le comme le vôtre.

`equipmentSensorId` pointe de l'équipement vers sa sonde. L'enregistrement de
la sonde pointe dans l'autre sens. Les deux côtés peuvent être `null`, et rien
ne garantit que l'un soit renseigné parce que l'autre l'est.

## `sensors`

Les sondes sans fil. Deux champs, tous les deux facultatifs.

| Champ | Type | Signification |
| --- | --- | --- |
| `macAddress` | string \| null | L'adresse matérielle de la sonde : c'est ainsi que vous distinguez un appareil physique d'un autre. |
| `sensorEquipmentId` | string \| null | L'équipement que cette sonde surveille. |

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

Notez les deux noms de champ, qui sont l'image l'un de l'autre et faciles à
intervertir : l'équipement porte `equipmentSensorId`, la sonde porte
`sensorEquipmentId`. Lisez le mauvais et vous obtenez `undefined`, sans erreur.

Il n'y a pas de nom ici, pas de niveau de batterie et pas de date de dernière
vue. Ce qu'une sonde a remonté est sur
[`temperature-readings`](https://developers.backresto.com/fr/docs/temperatures), et ces relevés sont indexés sur
`equipmentId` plutôt que sur la sonde, si bien qu'une sonde devenue muette
ressemble exactement à une sonde qui n'avait rien à remonter.

## `cooking-equipment`

Fours, armoires de maintien et le reste du côté chaud. Même idée
qu'`equipment`, la mécanique de la chaîne du froid en moins.

| Champ | Type | Signification |
| --- | --- | --- |
| `index` | integer, **obligatoire** | L'ordre d'affichage dans la liste du restaurant. |
| `type` | string, **obligatoire** | Le genre d'équipement dont il s'agit. Chaîne non contrainte. |
| `name` | string, **obligatoire** | Le nom que la cuisine lui donne. |
| `min` | number \| null | La température la plus basse acceptable. |
| `max` | number \| null | La température la plus haute acceptable. |
| `areaId` | string \| null | La zone où il se trouve. |
| `isDeleted` | boolean, **obligatoire** | L'indicateur de retrait de l'application. |

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

Pas de `state`, pas d'`outOfRangeCount`, pas de sonde : les équipements de
cuisson sont lus par une personne, rien ne les surveille donc entre deux
contrôles. Leurs relevés sont les
[`cooking-temperature-records`](https://developers.backresto.com/fr/docs/temperatures), qui pointent ici avec
`cookingEquipmentId`, un nom de champ différent de celui de la chaîne du
froid, et l'endroit habituel où un client ne lit rien en silence.

## Lire la carte

Tout ce qui est sur cette page est petit, lent à bouger et nécessaire avant
qu'aucune autre collection n'ait de sens.

- **Chargez-la en premier et gardez-la.** Parcourez `areas`, `equipment`,
  `cooking-equipment` et `sensors` avant de parcourir la moindre collection
  d'enregistrements, et résolvez les noms et les seuils depuis votre propre
  copie plutôt qu'enregistrement par enregistrement.
- **Actualisez-la quand même.** Les équipements sont renommés, les seuils sont
  corrigés, un réfrigérateur passe dans une autre zone. Une copie prise une
  fois et jamais reparcourue dérive sans jamais tomber en panne.
- **Gardez les identifiants, pas les copies, surtout pour les personnes.**
  Stockez le `userId` et résolvez un nom au moment de l'affichage. Voyez la
  note sur les données personnelles ci-dessus.
- **Les deux indicateurs de suppression, partout.** Le `deleted` de l'enveloppe
  et l'`isDeleted` de `data` sont deux choses différentes, et
  [la page du catalogue](https://developers.backresto.com/fr/docs/catalogue) explique lequel est lequel.
