# Instalaciones y personas

> El local, su personal, sus zonas y sus máquinas: el mapa fijo del que cuelga toda lectura de temperatura.

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

Estas son las cosas que no se mueven: el restaurante en sí, las personas que
trabajan en él, las zonas en que se divide y las máquinas que mantienen los
alimentos a una temperatura. Nada de esto es un control.

Aun así decide qué significan los controles. Una
[temperatura](https://developers.backresto.com/es/docs/temperatures) es un número sin ningún veredicto adjunto
hasta que lee los umbrales del equipo en que se tomó, y una lectura pertenece a
una parte del edificio solo porque el equipo dice en qué zona está. Equivóquese
en esta página y todas las cifras que vengan después estarán mal en silencio.

| Colección | Scope | Qué es un registro |
| --- | --- | --- |
| `restaurants` | `restaurants:read` | El local en sí: nombre, dirección, días de cierre, ajustes. |
| `users` | `users:read` | Una cuenta de personal que registra controles. |
| `areas` | `areas:read` | Una zona en que se divide el local: cocina, cámara frigorífica, barra. |
| `equipment` | `equipment:read` | Una nevera, un congelador, un equipo de cadena de frío, con sus umbrales. |
| `sensors` | `sensors:read` | Una sonda inalámbrica, por dirección MAC. |
| `cooking-equipment` | `cooking-equipment:read` | Un horno u otro equipo de cocción, con sus umbrales. |

Las seis comparten el [sobre de snapshot](https://developers.backresto.com/es/docs/collections): `id`,
`deleted`, `capturedAt`, `receivedAt`, `sequence` y los demás campos acompañan
al `data` que se describe más abajo.

## `restaurants`

El local al que está acotada su clave, como registro. Uno por restaurante, así
que esta colección suele ser una sola página.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `name` | string, **obligatorio** | El nombre del local, tal como se muestra en la aplicación. |
| `address` | string, **obligatorio** | La dirección postal, como una única cadena. |
| `closingDays` | string[], **obligatorio** | Los días que el local está cerrado. Cadenas a secas, sin restricción del esquema. |
| `exceptionalClosures` | object[] | Cierres puntuales, cada uno un objeto con `from` y `to`. |
| `detailedAddress` | object \| null | La dirección desglosada en partes, cuando la aplicación la guarda así. |
| `deliveryAddress` | string \| null | Dónde se entregan las mercancías, cuando difiere de `address`. |
| `deliveryDetailedAddress` | object \| null | Lo mismo, por partes. |
| `preferredLanguage` | string \| null | El idioma en que trabaja el restaurante. |
| `multiArea` | boolean \| null | Si el local está dividido en más de una zona. |
| `settings` | object \| null | Ajustes de la aplicación. La forma es la de la aplicación y se mueve. |

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

El ejemplo muestra solo la mitad operativa. Junto a ella el registro lleva la
comercial: `subscription`, `subscriptions`, `companyName`, `billingAddress`,
`billingEmail`, `tvaNumber`, `trialEndDate`, `customerId`, `discount`. Existen,
están en el documento OpenAPI, y esta página no va a explicárselos.

**Lea los campos operativos y deje en paz los comerciales.** Describen el
contrato del restaurante con nosotros, no su cocina. No son una API de
facturación, cambian por motivos que nada tienen que ver con la seguridad
alimentaria, y una integración que le muestre a un cliente el estado de su
suscripción es un ticket de soporte en potencia.

**`closingDays` es una lista de cadenas a secas.** El esquema no les impone
ninguna forma, así que léalas y muéstrelas; no haga un switch sobre ellas y no
dé por hecha una grafía ni unas mayúsculas concretas.

## `users`

Las cuentas del personal que registra los controles. Esto es a quien apunta el
`userId` de un [registro de temperatura](https://developers.backresto.com/es/docs/temperatures).

| Campo | Tipo | Significado |
| --- | --- | --- |
| `firstName` | string, **obligatorio** | Nombre de pila, tal como se introdujo. |
| `lastName` | string, **obligatorio** | Apellidos, tal como se introdujeron. |
| `email` | string, **obligatorio** | La dirección de correo electrónico de la cuenta. |
| `phoneNumber` | string \| null | Un teléfono de contacto, cuando se dio uno. |
| `modules` | string[] | Qué partes de la aplicación usa esta persona. Cadenas libres. |
| `preferredNotificationTime` | string \| null | Cuándo pidió esta persona que se le recuerde. |
| `isChildren` | boolean \| null | Una marca interna. El esquema no le da ningún significado; no construya sobre ella. |
| `isDeleted` | boolean \| null | La marca de retirada propia de la aplicación, y aquí admite `null`, a diferencia del resto. |

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

**Esto son datos personales.** `email`, `phoneNumber` y los dos campos de nombre
identifican a una persona real, y están en esta API por un solo motivo: un
registro de seguridad alimentaria tiene que decir quién hizo el control. Esa es
la única función que cumplen aquí.

Así que guarde el `id` y resuelva un nombre para mostrar cuando lo necesite. No
copie datos de contacto a sus propias tablas, sus logs, sus eventos de analítica
o una herramienta de terceros porque resulte que venían en el payload. El
restaurante es el responsable del tratamiento de los datos de su personal, y
cada copia que usted haga es una copia de la que ahora tiene que responder.

`isDeleted` admite `null` en esta colección donde en las demás es obligatorio,
así que trate una marca ausente como «no retirado» en lugar de dejar que se
cuele como un valor falsy sin querer. La diferencia entre esa marca y el
`deleted` del sobre está
[explicada en la página del catálogo](https://developers.backresto.com/es/docs/catalogue).

## `areas`

Una zona del restaurante. Dos campos, y mucho más importante de lo que dos
campos sugieren.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `name` | string, **obligatorio** | La zona tal como la nombra el restaurante: cocina, cámara frigorífica, barra. |
| `isDeleted` | boolean, **obligatorio** | La marca de retirada de la aplicación. Véase [la página del catálogo](https://developers.backresto.com/es/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` es la manera en que todo se agrupa por zonas.** Los equipos, los
equipos de cocción, las freidoras y las tareas de limpieza llevan uno, y es el
único vínculo entre una [lectura](https://developers.backresto.com/es/docs/temperatures) y una parte del edificio.
No hay ningún `areaId` en los registros en sí: se llega hasta él a través del
equipo.

`areaId` admite `null` en todos los sitios en que aparece. Una nevera sin zona
es normal: significa que nadie se la asignó, normalmente en un local de una sola
sala donde `multiArea` es false. Agrupe esas bajo «sin asignar» en lugar de
descartarlas.

## `equipment`

Neveras, congeladores y otros equipos de cadena de frío. El registro que decide
si una temperatura era aceptable.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `index` | integer, **obligatorio** | La posición que le dio el restaurante en su propia lista. Orden de presentación, no un identificador. |
| `type` | string, **obligatorio** | De qué tipo de equipo se trata. Una cadena sin restricciones: léala, no haga un switch sobre ella. |
| `name` | string, **obligatorio** | El equipo tal como lo llama la cocina. |
| `min` | number \| null | La temperatura aceptable más baja. |
| `max` | number \| null | La temperatura aceptable más alta. |
| `areaId` | string \| null | La zona en que está. |
| `equipmentSensorId` | string \| null | El sensor instalado en él, cuando hay uno. |
| `state` | string \| null | El estado actual del equipo, como cadena sin restricciones. |
| `outOfRangeCount` | number \| null | Un recuento de lecturas fuera de rango que mantiene la aplicación. |
| `isDeleted` | boolean, **obligatorio** | La marca de retirada de la aplicación. |

```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` y `max` son el único veredicto que va a obtener.** Un
[registro de temperatura](https://developers.backresto.com/es/docs/temperatures) lleva un valor, una hora y el
equipo en que se tomó; nada que diga si estaba bien. -14,4 °C es una crisis en
una nevera y un martes cualquiera en un congelador, y este registro es lo que
distingue una cosa de la otra. Toda cifra de cumplimiento que construya cruza
por aquí.

También admiten `null`. Cuando falta `min` o `max` no tiene umbral, y la
respuesta honesta para esa lectura es «desconocido», no «en rango». Dígalo así
en su interfaz en lugar de poner verde por defecto.

**Los umbrales son los actuales, no los que se aplicaron.** El snapshot le da
el `min` y el `max` de hoy; una lectura de marzo se juzgó contra lo que
estuviera fijado en marzo, y el restaurante puede cambiarlos en cualquier
momento. Si vuelve a evaluar lecturas antiguas con las cifras de hoy (que es
todo lo que le permite esta API), etiquete el resultado como recálculo suyo, no
como lo que vio la cocina.

**`type` y `state` son cadenas sin restricciones.** Los dos son campos de texto
libre en el esquema, sin ninguna lista detrás. Muéstrelos, agrupe por ellos si
no le queda más remedio, y nunca deje que un valor desconocido se cuele por un
switch hasta el silencio.

**`outOfRangeCount` es la cifra de la aplicación, no la suya.** El esquema no
dice qué ventana cubre, y no puede reconstruirla a partir de los snapshots de
aquí. Trátela como una señal de la aplicación y, si necesita un recuento que
pueda defender, calcule el suyo a partir de las lecturas y los umbrales y
etiquételo como suyo.

`equipmentSensorId` apunta del equipo a su sensor. El registro del sensor apunta
en sentido contrario. Los dos lados admiten `null`, y que uno esté relleno no
garantiza que el otro lo esté.

## `sensors`

Las sondas inalámbricas. Dos campos, los dos opcionales.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `macAddress` | string \| null | La dirección de hardware de la sonda: cómo distinguir un dispositivo físico de otro. |
| `sensorEquipmentId` | string \| null | El equipo que vigila este sensor. |

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

Fíjese en los dos nombres de campo, que son imágenes especulares y fáciles de
intercambiar: un equipo lleva `equipmentSensorId`, un sensor lleva
`sensorEquipmentId`. Lea el que no es y obtiene `undefined` sin ningún error.

Aquí no hay nombre, ni nivel de batería, ni hora del último contacto. Lo que
informó un sensor está en [`temperature-readings`](https://developers.backresto.com/es/docs/temperatures), y esas
lecturas se indexan por `equipmentId` y no por el sensor: así que una sonda que
se ha quedado muda tiene exactamente el mismo aspecto que una que no tenía nada
que comunicar.

## `cooking-equipment`

Hornos, armarios de mantenimiento y el resto del lado caliente. La misma idea
que `equipment`, sin la maquinaria de la cadena de frío.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `index` | integer, **obligatorio** | Orden de presentación en la lista del propio restaurante. |
| `type` | string, **obligatorio** | De qué tipo de equipo se trata. Cadena sin restricciones. |
| `name` | string, **obligatorio** | El equipo tal como lo llama la cocina. |
| `min` | number \| null | La temperatura aceptable más baja. |
| `max` | number \| null | La temperatura aceptable más alta. |
| `areaId` | string \| null | La zona en que está. |
| `isDeleted` | boolean, **obligatorio** | La marca de retirada de la aplicación. |

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

Ni `state`, ni `outOfRangeCount`, ni sensor: los equipos de cocción los lee una
persona, así que no hay nada vigilándolos entre control y control. Sus lecturas
son [`cooking-temperature-records`](https://developers.backresto.com/es/docs/temperatures), que apuntan aquí con
`cookingEquipmentId`: un nombre de campo distinto del de la cadena de frío, y el
sitio habitual donde un cliente se queda sin leer nada y sin enterarse.

## Leer el mapa

Todo lo de esta página es pequeño, cambia despacio y hace falta antes de que
ninguna otra colección tenga sentido.

- **Cárguelo primero y consérvelo.** Recorra `areas`, `equipment`,
  `cooking-equipment` y `sensors` antes de recorrer ninguna colección de
  registros, y resuelva nombres y umbrales desde su propia copia en lugar de
  registro a registro.
- **Refrésquelo de todos modos.** Los equipos se renombran, los umbrales se
  corrigen, una nevera se muda a otra zona. Una copia tomada una vez y nunca
  vuelta a recorrer se desvía sin llegar a fallar nunca.
- **Guarde ids, no copias, sobre todo con las personas.** Guarde el `userId` y
  resuelva un nombre en el momento de mostrarlo. Véase la nota sobre datos
  personales de más arriba.
- **Las dos marcas de borrado, en todas partes.** El `deleted` del sobre y el
  `isDeleted` de `data` son cosas distintas, y
  [la página del catálogo](https://developers.backresto.com/es/docs/catalogue) explica cuál es cuál.
