# Instalações e pessoas

> O estabelecimento, o seu pessoal, as suas zonas e as suas máquinas: o mapa fixo de que depende cada leitura de temperatura.

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

Estas são as coisas que não se mexem: o próprio restaurante, as pessoas que lá
trabalham, as zonas em que está dividido, e as máquinas que mantêm os alimentos
a uma temperatura. Nada disto é um controlo.

Ainda assim, é isto que decide o que os controlos significam. Uma
[temperatura](https://developers.backresto.com/pt/docs/temperatures) é um número sem veredito nenhum até ler os
limiares do equipamento em que foi medida, e uma leitura só pertence a uma parte
do edifício porque o equipamento diz em que zona está. Engane-se nesta página e
todos os números a jusante ficam errados em silêncio.

| Coleção | Scope | O que é um registo |
| --- | --- | --- |
| `restaurants` | `restaurants:read` | O estabelecimento em si: nome, morada, dias de encerramento, definições. |
| `users` | `users:read` | Uma conta de funcionário que regista controlos. |
| `areas` | `areas:read` | Uma zona em que o estabelecimento está dividido: cozinha, câmara frigorífica, bar. |
| `equipment` | `equipment:read` | Um frigorífico, um congelador, um equipamento de cadeia de frio, com os seus limiares. |
| `sensors` | `sensors:read` | Uma sonda sem fios, por endereço MAC. |
| `cooking-equipment` | `cooking-equipment:read` | Um forno ou outro equipamento de confeção, com os seus limiares. |

As seis partilham o [envelope de snapshot](https://developers.backresto.com/pt/docs/collections): `id`,
`deleted`, `capturedAt`, `receivedAt`, `sequence` e os restantes ficam ao lado
do `data` descrito abaixo.

## `restaurants`

O estabelecimento a que a sua chave está limitada, como um registo. Um por
restaurante, por isso esta coleção costuma ser uma única página.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `name` | string, **obrigatório** | O nome do estabelecimento, tal como aparece na aplicação. |
| `address` | string, **obrigatório** | A morada postal, numa só cadeia de caracteres. |
| `closingDays` | string[], **obrigatório** | Os dias em que o estabelecimento está fechado. Cadeias simples, não restringidas pelo esquema. |
| `exceptionalClosures` | object[] | Encerramentos pontuais, cada um um objeto com `from` e `to`. |
| `detailedAddress` | object \| null | A morada repartida em partes, quando a aplicação a guarda assim. |
| `deliveryAddress` | string \| null | Onde as mercadorias são entregues, quando difere de `address`. |
| `deliveryDetailedAddress` | object \| null | O mesmo, em partes. |
| `preferredLanguage` | string \| null | A língua em que o restaurante trabalha. |
| `multiArea` | boolean \| null | Se o estabelecimento está dividido em mais do que uma zona. |
| `settings` | object \| null | Definições da aplicação. O formato é da aplicação e vai mudando. |

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

O exemplo mostra apenas a metade operacional. Ao lado dela, o registo traz a
metade comercial: `subscription`, `subscriptions`, `companyName`,
`billingAddress`, `billingEmail`, `tvaNumber`, `trialEndDate`, `customerId`,
`discount`. Existem, estão no documento OpenAPI, e esta página não lhos vai
explicar.

**Leia os campos operacionais e deixe os comerciais em paz.** Descrevem o
contrato do restaurante connosco, não a sua cozinha. Não são uma API de
faturação, mudam por razões que nada têm a ver com segurança alimentar, e uma
integração que devolva a um cliente o estado da sua própria subscrição é um
pedido de suporte à espera de acontecer.

**`closingDays` é uma lista de cadeias de caracteres simples.** O esquema não
lhes impõe formato nenhum, por isso leia-as e mostre-as; não faça um `switch`
sobre elas e não assuma uma grafia ou uma caixa em particular.

## `users`

As contas do pessoal que regista os controlos. É para aqui que aponta o `userId`
de um [registo de temperatura](https://developers.backresto.com/pt/docs/temperatures).

| Campo | Tipo | Significado |
| --- | --- | --- |
| `firstName` | string, **obrigatório** | O nome próprio, tal como foi introduzido. |
| `lastName` | string, **obrigatório** | O apelido, tal como foi introduzido. |
| `email` | string, **obrigatório** | O endereço de email da conta. |
| `phoneNumber` | string \| null | Um número de contacto, quando foi dado. |
| `modules` | string[] | Que partes da aplicação esta pessoa utiliza. Cadeias livres. |
| `preferredNotificationTime` | string \| null | A hora a que esta pessoa pediu para ser lembrada. |
| `isChildren` | boolean \| null | Uma marca interna. O esquema não lhe dá significado nenhum; não construa nada sobre ela. |
| `isDeleted` | boolean \| null | A marca de retirada da própria aplicação. Aqui admite `null`, ao contrário do 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
  }
}
```

**Isto são dados pessoais.** `email`, `phoneNumber` e os dois campos de nome
identificam uma pessoa real, e estão nesta API por uma razão: um registo de
segurança alimentar tem de dizer quem fez o controlo. É a única função que têm
aqui.

Por isso, guarde o `id` e resolva um nome para mostrar quando precisar de um.
Não copie os dados de contacto para as suas tabelas, os seus registos de
atividade, os seus eventos de análise ou uma ferramenta de terceiros só porque
calharam de vir no payload. O restaurante é o responsável pelo tratamento dos
dados do seu pessoal, e cada cópia que faz é mais uma pela qual ele tem agora de
responder.

O `isDeleted` admite `null` nesta coleção onde é obrigatório noutras, por isso
trate uma marca ausente como «não retirado» em vez de a deixar passar por falsa
por acidente. A diferença entre ela e o `deleted` do envelope está
[explicada na página do catálogo](https://developers.backresto.com/pt/docs/catalogue).

## `areas`

Uma zona do restaurante. Dois campos, e muito mais importante do que dois campos
fazem supor.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `name` | string, **obrigatório** | A zona tal como o restaurante lhe chama: cozinha, câmara frigorífica, bar. |
| `isDeleted` | boolean, **obrigatório** | A marca de retirada da aplicação. Veja [a página do catálogo](https://developers.backresto.com/pt/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` é a forma como tudo se agrupa por zona.** Os equipamentos, os
equipamentos de confeção, as fritadeiras e as tarefas de limpeza trazem todos
um, e é a única ligação entre uma [leitura](https://developers.backresto.com/pt/docs/temperatures) e uma parte do
edifício. Não há `areaId` nos próprios registos: chega-se lá através do
equipamento.

O `areaId` admite `null` em todos os sítios onde aparece. Um frigorífico sem
zona é normal: significa que ninguém lhe atribuiu uma, normalmente num
estabelecimento de uma só sala em que `multiArea` é falso. Agrupe esses em «sem
atribuição» em vez de os deitar fora.

## `equipment`

Frigoríficos, congeladores e outros equipamentos de cadeia de frio. O registo
que decide se uma temperatura era aceitável.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `index` | integer, **obrigatório** | A posição que o restaurante lhe deu na sua própria lista. Ordem de apresentação, não um identificador. |
| `type` | string, **obrigatório** | Que tipo de equipamento é. Uma cadeia de caracteres sem restrições. Leia-a, não faça um `switch` sobre ela. |
| `name` | string, **obrigatório** | O equipamento tal como a cozinha lhe chama. |
| `min` | number \| null | A temperatura aceitável mais baixa. |
| `max` | number \| null | A temperatura aceitável mais alta. |
| `areaId` | string \| null | A zona em que está. |
| `equipmentSensorId` | string \| null | O sensor que lhe está instalado, quando há um. |
| `state` | string \| null | O estado atual do equipamento, como uma cadeia de caracteres sem restrições. |
| `outOfRangeCount` | number \| null | Uma contagem de leituras fora do intervalo que a aplicação mantém. |
| `isDeleted` | boolean, **obrigatório** | A marca de retirada da aplicação. |

```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` e `max` são o único veredito que recebe.** Um
[registo de temperatura](https://developers.backresto.com/pt/docs/temperatures) traz um valor, uma hora e o
equipamento em que foi medido, mas nada que diga se estava bem. -14,4 °C é uma
crise num frigorífico e uma terça-feira normal num congelador, e é este registo
que distingue os dois casos. Todos os números de conformidade que construir se
unem aqui.

Também admitem `null`. Quando `min` ou `max` está ausente, você não tem limiar
nenhum, e a resposta honesta para essa leitura é «desconhecido», não «dentro do
intervalo». Diga-o na sua interface em vez de assumir verde por omissão.

**Os limiares são os atuais, não os que se aplicavam.** O snapshot dá-lhe o
`min` e o `max` de hoje; uma leitura de março foi avaliada face ao que estava
definido em março, e o restaurante pode alterá-los a qualquer momento. Se
reavaliar leituras antigas face aos números de hoje (que é tudo o que esta API
lhe permite fazer), identifique o resultado como um cálculo seu, e não como o
que a cozinha viu.

**`type` e `state` são cadeias de caracteres sem restrições.** No esquema, ambos
são um único campo de texto livre sem lista nenhuma por trás. Mostre-os, agrupe
por eles se for preciso, e nunca deixe um valor não reconhecido cair num
`switch` e desaparecer em silêncio.

**`outOfRangeCount` é o número da aplicação, não o seu.** O esquema não diz que
janela é que ele cobre, e não o consegue reconstruir a partir dos snapshots
que estão aqui. Trate-o como um sinal vindo da aplicação e, se precisar de uma
contagem que consiga defender, calcule a sua a partir das leituras e dos
limiares, e identifique-a como sua.

O `equipmentSensorId` aponta do equipamento para o seu sensor. O registo do
sensor aponta no sentido contrário. Os dois lados admitem `null`, e nenhum deles
está garantidamente preenchido só porque o outro está.

## `sensors`

As sondas sem fios. Dois campos, ambos opcionais.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `macAddress` | string \| null | O endereço de hardware da sonda: como distingue um dispositivo físico de outro. |
| `sensorEquipmentId` | string \| null | O equipamento que este sensor vigia. |

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

Repare nos dois nomes de campo, que são imagens espelhadas e fáceis de trocar: o
equipamento traz `equipmentSensorId`, um sensor traz `sensorEquipmentId`. Leia o
errado e recebe `undefined` sem erro nenhum.

Aqui não há nome, não há nível de bateria e não há hora da última comunicação. O
que um sensor comunicou está em
[`temperature-readings`](https://developers.backresto.com/pt/docs/temperatures), e essas estão indexadas por
`equipmentId` e não pelo sensor. Por isso, uma sonda que se calou é
exatamente igual a uma que não tinha nada a comunicar.

## `cooking-equipment`

Fornos, armários de manutenção a quente e o resto do lado quente. A mesma ideia
de `equipment`, com a maquinaria da cadeia de frio retirada.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `index` | integer, **obrigatório** | Ordem de apresentação na lista do próprio restaurante. |
| `type` | string, **obrigatório** | Que tipo de equipamento é. Cadeia de caracteres sem restrições. |
| `name` | string, **obrigatório** | O equipamento tal como a cozinha lhe chama. |
| `min` | number \| null | A temperatura aceitável mais baixa. |
| `max` | number \| null | A temperatura aceitável mais alta. |
| `areaId` | string \| null | A zona em que está. |
| `isDeleted` | boolean, **obrigatório** | A marca de retirada da aplicação. |

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

Sem `state`, sem `outOfRangeCount`, sem sensor: os equipamentos de confeção são
lidos por uma pessoa, por isso não há nada a vigiá-los entre controlos. As suas
leituras são [`cooking-temperature-records`](https://developers.backresto.com/pt/docs/temperatures), que apontam
para aqui com `cookingEquipmentId`, um nome de campo diferente do da cadeia de
frio, e o sítio habitual onde um cliente não lê nada sem dar por isso.

## Ler o mapa

Tudo o que está nesta página é pequeno, muda devagar e é preciso antes de
qualquer outra coleção fazer sentido.

- **Carregue-o primeiro e guarde-o.** Percorra `areas`, `equipment`,
  `cooking-equipment` e `sensors` antes de percorrer qualquer coleção de
  registos, e resolva os nomes e os limiares a partir da sua própria cópia em
  vez de o fazer registo a registo.
- **Atualize-o na mesma.** Os equipamentos são renomeados, os limiares são
  corrigidos, um frigorífico muda de zona. Uma cópia tirada uma vez e nunca mais
  percorrida afasta-se da realidade sem nunca falhar.
- **Guarde identificadores, não cópias, sobretudo no caso das pessoas.**
  Guarde o `userId` e resolva um nome no momento de o mostrar. Veja a nota sobre
  dados pessoais acima.
- **Os dois campos de eliminação, em todo o lado.** O `deleted` do envelope e o
  `isDeleted` do `data` são coisas diferentes, e
  [a página do catálogo](https://developers.backresto.com/pt/docs/catalogue) explica qual é qual.
