# Limpeza

> O plano de limpeza, as tarefas efetivamente feitas e as fotografias que o provam. Três coleções, e o que um registo em falta não prova.

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

A limpeza, na aplicação, é um plano e a sua prova. O restaurante escreve o que
tem de ser limpo, onde e com que frequência; o pessoal vai marcando as tarefas à
medida que as faz; algumas dessas tarefas exigem uma fotografia. Três coleções,
uma por camada, e a junção entre elas é onde está quase todo o trabalho.

| Coleção | Scope | O que é um registo |
| --- | --- | --- |
| `cleaning-tasks` | `cleaning-tasks:read` | Uma linha do plano: o que tem de ser limpo, onde, com que frequência, se exige uma fotografia. |
| `cleaning-task-records` | `cleaning-task-records:read` | Uma tarefa efetivamente feita: quando, e por quem. |
| `cleaning-task-pictures` | `cleaning-task-pictures:read` | A fotografia que o prova. Traz um ficheiro. |

As três 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.

## `cleaning-tasks`

O plano em si. Estes mudam raramente (um restaurante escreve o seu plano uma
vez e edita-o quando a cozinha muda), por isso é a coleção que percorre com
menos frequência e que mantém em cache durante mais tempo.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `index` | integer, **obrigatório** | A posição da tarefa no plano, tal como a aplicação a ordena. |
| `name` | string, **obrigatório** | O que tem de ser limpo, nas palavras do restaurante. |
| `description` | string \| null | Instruções mais longas, quando alguém as escreveu. |
| `areaId` | string \| null | A [zona](https://developers.backresto.com/pt/docs/facilities) a que pertence. `null` num restaurante que não se divide em zonas. |
| `recurrence` | integer, **obrigatório** | Com que frequência a tarefa volta, como um simples número inteiro. |
| `requirePhotoProof` | boolean \| null | `true` quando a tarefa exige uma fotografia. `null` significa que a aplicação nunca o definiu. |
| `isDeleted` | boolean, **obrigatório** | O soft delete da própria aplicação. Leia a nota abaixo. |

```json
{
  "id": "c9a4f7e2-1b83-4d05-a6f1-90e3b7c4d218",
  "collection": "cleaning-tasks",
  "deleted": false,
  "capturedAt": "1789601204773",
  "receivedAt": "1789601399042",
  "sequence": "1",
  "data": {
    "index": 3,
    "name": "Nettoyage de la trancheuse",
    "description": "Démonter la lame, dégraisser, désinfecter.",
    "areaId": "7d2c0b61-4e8a-49f3-9c27-5a1b8e60d3f4",
    "recurrence": 1,
    "requirePhotoProof": true,
    "isDeleted": false
  }
}
```

**`recurrence` não traz unidade nenhuma.** É um número inteiro e o registo não
diz o que é que ele conta. Mostre-o como a aplicação o mostra, em vez de
apresentar «de 1 em 1 dias» a partir de um palpite.

**`isDeleted` não é o `deleted` do envelope.** Uma tarefa que o restaurante
retirou do seu plano volta com `isDeleted: true` e `deleted: false`: continua a
ser um registo vivo, que descreve uma linha que já não se aplica. Filtre pelos
dois, e guarde as eliminadas: os registos antigos ainda apontam para elas.

## `cleaning-task-records`

Uma tarefa feita. Pequeno de propósito: que tarefa, quando, quem.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `timestamp` | string, **obrigatório** | Quando a tarefa foi feita, em milissegundos desde a época Unix, em forma de cadeia de caracteres. |
| `cleaningTaskId` | string, **obrigatório** | O registo de `cleaning-tasks` que ela cumpre. |
| `userId` | string \| null | O [funcionário](https://developers.backresto.com/pt/docs/facilities) que a fez, quando a aplicação registou um. |

```json
{
  "id": "5f8b3d16-2c90-4a77-b4e8-31d0a9c65f7b",
  "collection": "cleaning-task-records",
  "deleted": false,
  "capturedAt": "1789775012558",
  "receivedAt": "1789775204910",
  "sequence": "2",
  "data": {
    "timestamp": "1789774800000",
    "cleaningTaskId": "c9a4f7e2-1b83-4d05-a6f1-90e3b7c4d218",
    "userId": "2774953d-8d9b-4a68-8ec4-1209edd90777"
  }
}
```

`cleaningTaskId` é obrigatório, por isso todos os registos têm uma tarefa. O
contrário não se verifica: uma tarefa pode estar no plano semanas sem qualquer
registo associado, e esse é o estado normal de uma tarefa semanal numa
terça-feira.

## `cleaning-task-pictures`

A fotografia. Traz um ficheiro, o que faz dela a única coleção desta página que
não consegue consumir só a partir do endpoint dos registos.

| Campo | Tipo | Significado |
| --- | --- | --- |
| `timestamp` | string, **obrigatório** | Quando a fotografia foi tirada, em milissegundos desde a época Unix, em forma de cadeia de caracteres. |
| `cleaningTaskRecordId` | string \| null | O registo de `cleaning-task-records` que ela prova. Admite `null`. Veja abaixo. |
| `part` | number \| null | Não documentado, e um decimal em vez de um contador. Leve-o consigo em vez de o interpretar: a mesma ressalva que nas [etiquetas de rastreabilidade](https://developers.backresto.com/pt/docs/traceability-labels). |
| `groupId` | string \| null | Liga essas fotografias entre si. Os registos que partilham um `groupId` pertencem à mesma prova. |
| `asset` | object, **obrigatório** | Identifica o ficheiro: `objectKey` e `status` sempre, mais `contentType`, `byteLength` e `sha256` assim que ele estiver carregado. |

```json
{
  "id": "2d71c8a9-6e34-4b0f-8517-ac93e25d0b46",
  "collection": "cleaning-task-pictures",
  "deleted": false,
  "capturedAt": "1789775118330",
  "receivedAt": "1789775301774",
  "sequence": "3",
  "data": {
    "timestamp": "1789774860000",
    "cleaningTaskRecordId": "5f8b3d16-2c90-4a77-b4e8-31d0a9c65f7b",
    "part": 1,
    "groupId": "a03e5c88-71bd-4f92-b6d4-2e8f10c73a5b",
    "asset": {
      "objectKey": "cleaning-task-pictures/2d71c8a9/1.jpg",
      "status": "uploaded",
      "contentType": "image/jpeg",
      "byteLength": 812043,
      "sha256": "9f2a…"
    }
  }
}
```

Os bytes são uma segunda chamada, sobre o identificador do próprio registo:

```http
GET /v1/restaurants/{restaurantId}/collections/cleaning-task-pictures/records/{recordId}/assets
```

Responde com uma lista de URL assinados, cada um válido durante **quinze
minutos**, cada um a levar a sua própria autorização, por isso a transferência
não precisa de qualquer cabeçalho. Vá buscar os bytes agora, guarde os bytes e
não a ligação, e volte a chamar o endpoint quando precisar de um URL novo. As
regras (o que aparece, para que serve o `sha256`, porque vale a pena ler o
`contentType`) estão na [página das coleções](https://developers.backresto.com/pt/docs/collections), e aqui são
as mesmas.

**O `asset.status` diz-lhe se há bytes para ir buscar.** É `pending` ou
`uploaded`. Um `asset` a `pending` é uma fotografia que o dispositivo anunciou e
ainda não acabou de enviar: o registo é real, o ficheiro não é, e o endpoint dos
ficheiros responde sem ele. Leia o estado antes de tratar uma lista de ficheiros
vazia como uma fotografia que nunca foi tirada.

**`cleaningTaskRecordId` admite `null`.** Uma fotografia pode existir sem
apontar para um registo, por isso uma junção que assuma que ele está sempre lá
deixa fotografias pelo caminho. Conte-as à parte em vez de as descartar em
silêncio.

## Unir as três

O formato que quase de certeza quer é uma linha por tarefa feita, com a sua
entrada no plano e as suas fotografias:

- `cleaning-task-records.cleaningTaskId` → `cleaning-tasks.id`
- `cleaning-task-pictures.cleaningTaskRecordId` → `cleaning-task-records.id`

Três percursos, unidos do seu lado. Não há endpoint que o faça por si, e não há
filtro por tarefa nem por data: percorre cada coleção inteira e reconcilia,
como descreve [a página do envelope](https://developers.backresto.com/pt/docs/collections).

Faça os relatórios por `capturedAt` e sincronize por `receivedAt`: um tablet
numa câmara frigorífica carrega quando encontra sinal, e uma fotografia tirada
às 09:00 pode chegar às 14:00, depois do registo a que pertence, ou antes
dele.

## O que um registo em falta não significa

**Uma entrada do plano sem registo correspondente não é prova de que a tarefa
foi saltada.** Pode ter sido feita num dispositivo que ainda não carregou os
dados, ou feita antes de a captura ter sido ativada para esse restaurante. O
mesmo vale para uma tarefa marcada com `requirePhotoProof: true` e sem
fotografia associada: a fotografia pode estar a meio do carregamento, e um
ficheiro que não acabou de carregar está ausente, não avariado.

Por isso, não produza uma taxa de execução da limpeza a partir desta API e lhe
chame conformidade. O que pode dizer com honestidade é o que chegou, e quando.
Veja [a nota sobre a completude](https://developers.backresto.com/pt/docs/support) antes de pôr um número à frente
de quem quer que seja.
