# Pulizie

> Il piano di pulizia, i compiti effettivamente svolti e le fotografie che lo dimostrano: tre collezioni, e cosa non prova un record mancante.

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

La pulizia nell'app è un piano e la sua prova. Il ristorante mette per iscritto
cosa deve essere pulito, dove e con quale frequenza; il personale spunta i
compiti man mano che li svolge; alcuni di quei compiti richiedono una
fotografia. Tre collezioni, una per livello, e la join fra loro è dove sta la
maggior parte del lavoro.

| Collezione | Scope | Che cos'è un record |
| --- | --- | --- |
| `cleaning-tasks` | `cleaning-tasks:read` | Una riga del piano: cosa deve essere pulito, dove, ogni quanto, se serve una fotografia. |
| `cleaning-task-records` | `cleaning-task-records:read` | Un compito effettivamente svolto: quando, e da chi. |
| `cleaning-task-pictures` | `cleaning-task-pictures:read` | La fotografia che lo dimostra. Porta con sé un file. |

Tutte e tre condividono l'[involucro di snapshot](https://developers.backresto.com/it/docs/collections): `id`,
`deleted`, `capturedAt`, `receivedAt`, `sequence` e gli altri stanno accanto al
`data` descritto qui sotto.

## `cleaning-tasks`

Il piano stesso. Cambia di rado (un ristorante scrive il suo piano una volta e
lo modifica quando cambia la cucina), quindi è la collezione che percorrerà
meno spesso e che terrà in cache più a lungo.

| Campo | Tipo | Significato |
| --- | --- | --- |
| `index` | integer, **obbligatorio** | La posizione del compito nel piano, nell'ordine in cui li dispone l'app. |
| `name` | string, **obbligatorio** | Cosa deve essere pulito, nelle parole del ristorante. |
| `description` | string \| null | Istruzioni più estese, quando qualcuno le ha scritte. |
| `areaId` | string \| null | L'[area](https://developers.backresto.com/it/docs/facilities) a cui appartiene. `null` in un ristorante che non si suddivide in aree. |
| `recurrence` | integer, **obbligatorio** | Ogni quanto il compito si ripresenta, come semplice numero intero. |
| `requirePhotoProof` | boolean \| null | `true` quando il compito richiede una fotografia. `null` significa che l'app non l'ha mai impostato. |
| `isDeleted` | boolean, **obbligatorio** | Il soft delete proprio dell'app. Legga la nota qui sotto. |

```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` non porta alcuna unità.** È un intero e il record non dice cosa
conti. Lo presenti come lo presenta l'app, anziché visualizzare «ogni 1 giorni»
tirando a indovinare.

**`isDeleted` non è il `deleted` dell'involucro.** Un compito che il ristorante
ha rimosso dal suo piano torna con `isDeleted: true` e `deleted: false`: è
ancora un record vivo, che descrive una riga che non si applica più. Filtri su
entrambi, e conservi quelli cancellati: i vecchi record li indicano ancora.

## `cleaning-task-records`

Un compito svolto. Piccolo di proposito: quale compito, quando, chi.

| Campo | Tipo | Significato |
| --- | --- | --- |
| `timestamp` | string, **obbligatorio** | Quando il compito è stato svolto, millisecondi dall'epoch come stringa. |
| `cleaningTaskId` | string, **obbligatorio** | Il record `cleaning-tasks` a cui risponde. |
| `userId` | string \| null | Il [membro del personale](https://developers.backresto.com/it/docs/facilities) che l'ha svolto, quando l'app ne ha registrato uno. |

```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` è obbligatorio, quindi ogni record ha un compito. Il contrario
non vale: un compito può restare nel piano senza alcun record a suo carico per
settimane, ed è lo stato normale di un compito settimanale di martedì.

## `cleaning-task-pictures`

La fotografia. Porta con sé un file, il che ne fa l'unica collezione di questa
pagina che non può consumare dal solo endpoint dei record.

| Campo | Tipo | Significato |
| --- | --- | --- |
| `timestamp` | string, **obbligatorio** | Quando è stata scattata l'immagine, millisecondi dall'epoch come stringa. |
| `cleaningTaskRecordId` | string \| null | Il record `cleaning-task-records` di cui è la prova. Ammette null. Veda qui sotto. |
| `part` | number \| null | Non documentato, ed è un decimale anziché un contatore. Lo porti avanti così com'è anziché interpretarlo: la stessa avvertenza delle [etichette di tracciabilità](https://developers.backresto.com/it/docs/traceability-labels). |
| `groupId` | string \| null | Lega insieme quelle immagini. I record che condividono un `groupId` appartengono alla stessa prova. |
| `asset` | object, **obbligatorio** | Indica il file: sempre `objectKey` e `status`, più `contentType`, `byteLength` e `sha256` una volta caricato. |

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

I byte sono una seconda chiamata, sull'id del record stesso:

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

Risponde con un elenco di URL firmati, ciascuno valido per **quindici minuti**,
ciascuno con la propria autorizzazione, così il download non richiede alcun
header. Scarichi i byte adesso, conservi i byte anziché il collegamento, e
richiami l'endpoint quando le serve un URL nuovo. Le regole (cosa compare, a
cosa serve `sha256`, perché vale la pena leggere `contentType`) sono nella
[pagina sulle collezioni](https://developers.backresto.com/it/docs/collections), e qui sono le stesse.

**`asset.status` le dice se ci sono byte da scaricare.** È `pending` oppure
`uploaded`. Un asset `pending` è una fotografia che il dispositivo ha annunciato
e non ha ancora finito di inviare: il record è reale, il file no, e l'endpoint
degli asset risponde senza di esso. Legga lo stato prima di trattare un elenco
di asset vuoto come una fotografia che non è mai stata scattata.

**`cleaningTaskRecordId` ammette null.** Un'immagine può esistere senza puntare
a un record, quindi una join che dà per scontato che ci sia sempre butta via
delle fotografie. Le conti a parte anziché scartarle in silenzio.

## Unire le tre

La forma che quasi sicuramente le serve è una riga per compito svolto, con la
sua voce di piano e le sue fotografie:

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

Tre percorsi, uniti dalla sua parte. Non esiste un endpoint che lo faccia per
lei, e non esiste alcun filtro per compito o per data: percorre ogni collezione
per intero e riconcilia, come descrive
[la pagina sull'involucro](https://developers.backresto.com/it/docs/collections).

Faccia i report su `capturedAt` e sincronizzi su `receivedAt`: un tablet in una
cella frigorifera carica i dati quando trova segnale, e un'immagine scattata
alle 09:00 può arrivare alle 14:00, dopo il record a cui appartiene, oppure
prima.

## Cosa non significa un record mancante

**Una voce di piano senza un record corrispondente non è la prova che il compito
sia stato saltato.** Può essere stato svolto su un dispositivo che non ha ancora
caricato i dati, oppure svolto prima che l'acquisizione venisse attivata per
quel ristorante. Lo stesso vale per un compito contrassegnato
`requirePhotoProof: true` senza alcuna immagine a suo carico: la fotografia può
essere a metà del caricamento, e un asset che non ha finito di caricarsi è
assente anziché rotto.

Quindi non stampi un tasso di completamento delle pulizie da questa API
chiamandolo conformità. Ciò che può dire onestamente è cosa è arrivato, e
quando. Veda [la nota sulla completezza](https://developers.backresto.com/it/docs/support) prima di mettere un
numero davanti a chiunque.
