Arrefecimento e processos alimentares
Arrefecimento, congelação, reaquecimento e transporte — quatro coleções que registam uma transição de temperatura, e o aspeto de uma que não terminou.
Um prato quente que arrefece devagar passa horas na faixa em que as bactérias se multiplicam, por isso a regra é baixá-lo depressa e conseguir mostrar que assim foi. Quatro coleções registam esse tipo de transição. Três delas são uma transição no tempo — para baixo, mais para baixo, de novo para cima — e a quarta é a mesma ideia no espaço.
| Coleção | Âmbito | O que é um registo |
|---|---|---|
cooling | cooling:read | Um produto quente baixado até à temperatura de conservação em frio. |
freezing | freezing:read | Um produto baixado até à congelação. |
reheating | reheating:read | Um produto frio levado de novo até à temperatura de serviço. |
transport | transport:read | Um produto deslocado de um sítio para outro, com a temperatura em cada ponta. |
As quatro partilham o envelope de instantâneo: id,
deleted, capturedAt, receivedAt, sequence e os restantes ficam ao lado
do data descrito abaixo.
cooling
Um ciclo: um produto, quando começou e quão quente estava, quando terminou e quão frio ficou.
| Campo | Tipo | Significado |
|---|---|---|
timestamp | string, obrigatório | O carimbo do próprio registo, em milissegundos desde a época Unix, em forma de cadeia de caracteres. Não é o relógio do ciclo — esse são as duas datas abaixo. |
product | string, obrigatório | O que foi arrefecido, em texto. |
beginDate | string, obrigatório | Quando o ciclo começou, em milissegundos desde a época Unix, em forma de cadeia de caracteres. |
beginTemperature | number, obrigatório | A temperatura a que começou. |
endDate | string | null | Quando terminou. null enquanto não terminou. |
endTemperature | number | null | A temperatura a que terminou. null ao lado de endDate. |
reminderId | string | null | O lembrete que a aplicação associou ao ciclo, quando havia um. |
userId | string | null | O funcionário que o registou, quando a aplicação registou um. |
{
"id": "0e5d1a7c-9f24-4b13-8d60-c1a7f0b25e94",
"collection": "cooling",
"deleted": false,
"capturedAt": "1789779612441",
"receivedAt": "1789779910228",
"sequence": "1",
"data": {
"timestamp": "1789772400000",
"product": "Blanquette de veau",
"beginDate": "1789772400000",
"beginTemperature": 63.5,
"endDate": "1789779600000",
"endTemperature": 8.2,
"userId": "2774953d-8d9b-4a68-8ec4-1209edd90777"
}
}
product é um nome, não uma referência. Não há productId nestes
registos, por isso não os consegue unir a products sem fazer correspondência
de cadeias de caracteres — e essas cadeias são escritas durante o serviço, na
língua do restaurante.
reminderId é opaco. Nenhuma coleção desta API o resolve. Leve-o consigo
se o ajudar a agrupar registos; não conte poder consultá-lo.
freezing
O mesmo formato, para um produto baixado até à congelação em vez de até à
temperatura de frigorífico. Campo a campo, é cooling.
| Campo | Tipo | Significado |
|---|---|---|
timestamp | string, obrigatório | O carimbo do próprio registo. |
product | string, obrigatório | O que foi congelado. |
beginDate | string, obrigatório | Quando a operação começou. |
beginTemperature | number, obrigatório | A temperatura a que começou. |
endDate | string | null | Quando terminou, ou null. |
endTemperature | number | null | A temperatura a que terminou, ou null. |
reminderId | string | null | Como acima. |
userId | string | null | Quem a registou. |
Nada no registo diz qual das três operações é: isso é a coleção de onde veio, e
o campo collection do envelope repete-o. Um pipeline que junte as três numa
só tabela precisa de manter essa coluna.
reheating
Um produto frio levado de novo para cima. Outra vez o mesmo formato, lido no
sentido contrário: beginTemperature é a baixa e endTemperature a alta.
| Campo | Tipo | Significado |
|---|---|---|
timestamp | string, obrigatório | O carimbo do próprio registo. |
product | string, obrigatório | O que foi reaquecido. |
beginDate | string, obrigatório | Quando entrou. |
beginTemperature | number, obrigatório | A temperatura a que começou. |
endDate | string | null | Quando saiu, ou null. |
endTemperature | number | null | A temperatura que atingiu, ou null. |
reminderId | string | null | Como acima. |
userId | string | null | Quem a registou. |
Uma operação sem fim tem este aspeto:
{
"id": "b4c8e21d-3a76-4f58-9c02-77ad5e1b8f30",
"collection": "reheating",
"deleted": false,
"capturedAt": "1789783221907",
"receivedAt": "1789783402115",
"sequence": "2",
"data": {
"timestamp": "1789783200000",
"product": "Gratin dauphinois",
"beginDate": "1789783200000",
"beginTemperature": 4.1,
"endDate": null,
"endTemperature": null,
"userId": "2774953d-8d9b-4a68-8ec4-1209edd90777"
}
}
transport
A mesma transição, no espaço em vez de no tempo: de onde o produto partiu e onde chegou, com uma temperatura em cada ponta.
| Campo | Tipo | Significado |
|---|---|---|
timestamp | string, obrigatório | O carimbo do próprio registo. |
product | string, obrigatório | O que foi transportado, em texto. |
departureLocation | string, obrigatório | De onde partiu, em texto. |
departureTime | string, obrigatório | Quando partiu, em milissegundos desde a época Unix, em forma de cadeia de caracteres. |
departureTemperature | number, obrigatório | A temperatura à partida. |
arrivalLocation | string | null | Onde chegou. null enquanto não chegou. |
arrivalTime | string | null | Quando chegou, ou null. |
arrivalTemperature | number | null | A temperatura à chegada, ou null. |
reminderId | string | null | Como acima. |
userId | string | null | Quem o registou. |
{
"id": "f31b6a08-5c47-4de9-b1a5-6e0c9d247b82",
"collection": "transport",
"deleted": false,
"capturedAt": "1789786944610",
"receivedAt": "1789787101883",
"sequence": "3",
"data": {
"timestamp": "1789785000000",
"product": "Plats préparés — service traiteur",
"departureLocation": "Cuisine centrale",
"departureTime": "1789785000000",
"departureTemperature": 3.4,
"arrivalLocation": "Salle Montparnasse",
"arrivalTime": "1789786800000",
"arrivalTemperature": 5.9,
"userId": "2774953d-8d9b-4a68-8ec4-1209edd90777"
}
}
Os dois locais são texto livre, não são zonas nem moradas. São o que a pessoa escreveu, e a ponta da chegada é exatamente tão opcional como a temperatura de chegada: um registo pode trazer uma partida e mais nada.
Trabalhar com estes
Um fim a null são duas coisas diferentes. endDate e endTemperature —
e arrivalTime, arrivalTemperature e arrivalLocation em transport —
admitem null, e o registo não lhe diz porquê. Pode ser uma operação ainda a
decorrer no momento em que a lê, ou uma que ninguém fechou. As duas são
idênticas à vista.
Isso conta a partir do momento em que calcula uma duração. As datas são cadeias
de caracteres, por isso endDate - beginDate subtrai bem num registo fechado e,
num aberto, converte null em zero e devolve-lhe um número negativo grande em
vez de um erro. Nada é lançado; a sua média está simplesmente errada. Filtre
primeiro pelos registos fechados, conte os abertos à parte, e decida por si a
partir de que idade um registo aberto deixa de estar em curso e passa a estar
abandonado — nada nesta API faz essa decisão por si.
Calcule com beginDate e endDate, não com timestamp. As datas são o
relógio da operação. timestamp é o do próprio registo, e não é aquilo de que
se faz uma duração.
Ordene por capturedAt, não por receivedAt. Um tablet numa câmara
frigorífica carrega quando encontra sinal, por isso um ciclo começado às 09:00
pode chegar às 14:00. A página do envelope conta a
história toda.
A ausência não prova nada. Um produto sem registo de arrefecimento pode nunca ter sido arrefecido, ou pode estar num dispositivo que ainda não carregou os dados. Não transforme uma contagem destes num número de conformidade — veja a nota de aviso.