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ÂmbitoO que é um registo
coolingcooling:readUm produto quente baixado até à temperatura de conservação em frio.
freezingfreezing:readUm produto baixado até à congelação.
reheatingreheating:readUm produto frio levado de novo até à temperatura de serviço.
transporttransport:readUm 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.

CampoTipoSignificado
timestampstring, obrigatórioO 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.
productstring, obrigatórioO que foi arrefecido, em texto.
beginDatestring, obrigatórioQuando o ciclo começou, em milissegundos desde a época Unix, em forma de cadeia de caracteres.
beginTemperaturenumber, obrigatórioA temperatura a que começou.
endDatestring | nullQuando terminou. null enquanto não terminou.
endTemperaturenumber | nullA temperatura a que terminou. null ao lado de endDate.
reminderIdstring | nullO lembrete que a aplicação associou ao ciclo, quando havia um.
userIdstring | nullO 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.

CampoTipoSignificado
timestampstring, obrigatórioO carimbo do próprio registo.
productstring, obrigatórioO que foi congelado.
beginDatestring, obrigatórioQuando a operação começou.
beginTemperaturenumber, obrigatórioA temperatura a que começou.
endDatestring | nullQuando terminou, ou null.
endTemperaturenumber | nullA temperatura a que terminou, ou null.
reminderIdstring | nullComo acima.
userIdstring | nullQuem 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.

CampoTipoSignificado
timestampstring, obrigatórioO carimbo do próprio registo.
productstring, obrigatórioO que foi reaquecido.
beginDatestring, obrigatórioQuando entrou.
beginTemperaturenumber, obrigatórioA temperatura a que começou.
endDatestring | nullQuando saiu, ou null.
endTemperaturenumber | nullA temperatura que atingiu, ou null.
reminderIdstring | nullComo acima.
userIdstring | nullQuem 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.

CampoTipoSignificado
timestampstring, obrigatórioO carimbo do próprio registo.
productstring, obrigatórioO que foi transportado, em texto.
departureLocationstring, obrigatórioDe onde partiu, em texto.
departureTimestring, obrigatórioQuando partiu, em milissegundos desde a época Unix, em forma de cadeia de caracteres.
departureTemperaturenumber, obrigatórioA temperatura à partida.
arrivalLocationstring | nullOnde chegou. null enquanto não chegou.
arrivalTimestring | nullQuando chegou, ou null.
arrivalTemperaturenumber | nullA temperatura à chegada, ou null.
reminderIdstring | nullComo acima.
userIdstring | nullQuem 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.

Última atualização em 2026-09-20.