Standort & Personen
Der Standort, sein Personal, seine Zonen und seine Geräte — die feste Karte, an der jede Temperaturmessung hängt.
Das sind die Dinge, die sich nicht bewegen: das Restaurant selbst, die Menschen, die darin arbeiten, die Zonen, in die es aufgeteilt ist, und die Geräte, die Lebensmittel auf Temperatur halten. Nichts davon ist eine Kontrolle.
Es entscheidet trotzdem, was die Kontrollen bedeuten. Eine Temperatur ist eine Zahl ohne Urteil, solange Sie nicht die Schwellen von dem Gerät lesen, an dem sie gemessen wurde, und eine Messung gehört nur deshalb zu einem Teil des Gebäudes, weil das Gerät sagt, in welchem Bereich es steht. Liegen Sie bei dieser Seite falsch, ist jede Kennzahl danach still und leise falsch.
| Collection | Berechtigung | Was ein Datensatz ist |
|---|---|---|
restaurants | restaurants:read | Der Standort selbst: Name, Adresse, Schließtage, Einstellungen. |
users | users:read | Ein Mitarbeiterkonto, das Kontrollen erfasst. |
areas | areas:read | Eine Zone, in die der Standort aufgeteilt ist — Küche, Kühlraum, Bar. |
equipment | equipment:read | Ein Kühlschrank, ein Gefriergerät, eine Kühlketten-Einheit, mit ihren Schwellen. |
sensors | sensors:read | Ein Funkfühler, über seine MAC-Adresse. |
cooking-equipment | cooking-equipment:read | Ein Ofen oder ein anderes Gargerät, mit seinen Schwellen. |
Alle sechs teilen sich den Snapshot-Umschlag: id,
deleted, capturedAt, receivedAt, sequence und der Rest stehen neben dem
data, das unten beschrieben ist.
restaurants
Der Standort, auf den Ihr Schlüssel begrenzt ist, als Datensatz. Einer pro Restaurant, diese Collection ist also meist eine einzige Seite.
| Feld | Typ | Bedeutung |
|---|---|---|
name | string, Pflicht | Der Name des Standorts, so wie er in der App angezeigt wird. |
address | string, Pflicht | Die Postanschrift, als eine Zeichenkette. |
closingDays | string[], Pflicht | Die Tage, an denen der Standort geschlossen ist. Schlichte Zeichenketten, vom Schema nicht eingeschränkt. |
exceptionalClosures | object[] | Einmalige Schließungen, jede ein Objekt mit from und to. |
detailedAddress | object | null | Die Adresse in ihre Teile zerlegt, wenn die App sie so hält. |
deliveryAddress | string | null | Wohin Waren geliefert werden, wenn es von address abweicht. |
deliveryDetailedAddress | object | null | Dasselbe, in Teilen. |
preferredLanguage | string | null | Die Sprache, in der das Restaurant arbeitet. |
multiArea | boolean | null | Ob der Standort in mehr als einen Bereich aufgeteilt ist. |
settings | object | null | App-Einstellungen. Die Struktur gehört der App, und sie bewegt sich. |
{
"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
}
}
Das Beispiel zeigt nur die betriebliche Hälfte. Daneben trägt der Datensatz die
kaufmännische: subscription, subscriptions, companyName, billingAddress,
billingEmail, tvaNumber, trialEndDate, customerId, discount. Es gibt
sie, sie stehen im OpenAPI-Dokument, und diese Seite führt Sie nicht durch sie
hindurch.
Lesen Sie die betrieblichen Felder und lassen Sie die kaufmännischen in Ruhe. Sie beschreiben den Vertrag des Restaurants mit uns, nicht seine Küche. Sie sind keine Abrechnungs-API, sie ändern sich aus Gründen, die nichts mit Lebensmittelsicherheit zu tun haben, und eine Integration, die einem Kunden seinen Abonnementstatus zurückspiegelt, ist ein Support-Ticket, das nur auf seinen Termin wartet.
closingDays ist eine Liste schlichter Zeichenketten. Das Schema gibt ihnen
keine Form, lesen Sie sie also und zeigen Sie sie; verzweigen Sie nicht darauf
und nehmen Sie keine bestimmte Schreibweise und keine bestimmte Groß- und
Kleinschreibung an.
users
Die Mitarbeiterkonten, die Kontrollen erfassen. Auf sie zeigt das userId eines
Temperaturdatensatzes.
| Feld | Typ | Bedeutung |
|---|---|---|
firstName | string, Pflicht | Vorname, so wie eingetragen. |
lastName | string, Pflicht | Nachname, so wie eingetragen. |
email | string, Pflicht | Die E-Mail-Adresse des Kontos. |
phoneNumber | string | null | Eine Rufnummer, sofern eine angegeben wurde. |
modules | string[] | Welche Teile der App diese Person nutzt. Freie Zeichenketten. |
preferredNotificationTime | string | null | Wann diese Person erinnert werden möchte. |
isChildren | boolean | null | Ein internes Kennzeichen. Das Schema gibt ihm keine Bedeutung; bauen Sie nicht darauf. |
isDeleted | boolean | null | Das eigene Kennzeichen der App für ausgemusterte Einträge — und hier darf es null sein, anders als sonst. |
{
"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
}
}
Das sind personenbezogene Daten. email, phoneNumber und die beiden
Namensfelder benennen eine echte Person, und sie stehen aus einem einzigen Grund
in dieser API: Ein Datensatz zur Lebensmittelsicherheit muss sagen, wer die
Kontrolle durchgeführt hat. Das ist ihre einzige Aufgabe hier.
Speichern Sie also das id und lösen Sie einen Anzeigenamen auf, wenn Sie einen
brauchen. Kopieren Sie Kontaktdaten nicht in Ihre eigenen Tabellen, Ihre
Protokolle, Ihre Analytics-Ereignisse oder ein Werkzeug eines Dritten, nur weil
sie zufällig in der Antwort standen. Das Restaurant ist für sein Personal der
Verantwortliche im Sinne des Datenschutzes, und jede Kopie, die Sie anlegen, ist
eine, für die es nun geradestehen muss.
isDeleted darf in dieser Collection null sein, wo es sonst Pflicht ist;
behandeln Sie ein fehlendes Kennzeichen also als „nicht ausgemustert“, statt es
versehentlich als falsch-artig durchfallen zu lassen. Der Unterschied zum
deleted des Umschlags ist
auf der Katalogseite erklärt.
areas
Eine Zone des Restaurants. Zwei Felder, und weit wichtiger, als zwei Felder vermuten lassen.
| Feld | Typ | Bedeutung |
|---|---|---|
name | string, Pflicht | Die Zone, so wie das Restaurant sie nennt — Küche, Kühlraum, Bar. |
isDeleted | boolean, Pflicht | Das Kennzeichen der App für ausgemusterte Einträge. Siehe die Katalogseite. |
{
"id": "9c2b17ae-4d80-4f55-b3e1-0a6c8f4d2b19",
"collection": "areas",
"deleted": false,
"capturedAt": "1789301120440",
"receivedAt": "1789301126871",
"sequence": "12",
"data": {
"name": "Chambre froide",
"isDeleted": false
}
}
Über areaId wird alles nach Zone gruppiert. Geräte, Gargeräte, Fritteusen
und Reinigungsaufgaben tragen alle eines, und es ist die einzige Verbindung
zwischen einer Messung und einem Teil des Gebäudes. Auf
den Datensätzen selbst gibt es kein areaId: Sie kommen über das Gerät dorthin.
areaId darf überall, wo es auftaucht, null sein. Ein Kühlschrank ohne
Bereich ist normal — es heißt, dass ihn niemand zugeordnet hat, meist an einem
Standort mit einem einzigen Raum, wo multiArea falsch ist. Fassen Sie solche
unter „nicht zugeordnet“ zusammen, statt sie wegzulassen.
equipment
Kühlschränke, Gefriergeräte und andere Einheiten der Kühlkette. Der Datensatz, der entscheidet, ob eine Temperatur zulässig war.
| Feld | Typ | Bedeutung |
|---|---|---|
index | integer, Pflicht | Die Position, die das Restaurant ihm in seiner eigenen Liste gegeben hat. Anzeigereihenfolge, keine Kennung. |
type | string, Pflicht | Um welche Art Einheit es sich handelt. Eine nicht eingeschränkte Zeichenkette — lesen Sie sie, verzweigen Sie nicht darauf. |
name | string, Pflicht | Die Einheit, so wie die Küche sie nennt. |
min | number | null | Die niedrigste zulässige Temperatur. |
max | number | null | Die höchste zulässige Temperatur. |
areaId | string | null | Der Bereich, in dem sie steht. |
equipmentSensorId | string | null | Der Sensor, der daran angebracht ist, sofern es einen gibt. |
state | string | null | Der aktuelle Zustand der Einheit, als nicht eingeschränkte Zeichenkette. |
outOfRangeCount | number | null | Eine Anzahl von Messungen außerhalb des Bereichs, die die App führt. |
isDeleted | boolean, Pflicht | Das Kennzeichen der App für ausgemusterte Einträge. |
{
"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 und max sind das einzige Urteil, das Sie bekommen. Ein
Temperaturdatensatz trägt einen Wert, eine Zeit und das
Gerät, an dem gemessen wurde — nichts, was sagt, ob es in Ordnung war. -14,4 °C
sind in einem Kühlschrank eine Krise und in einem Gefriergerät ein normaler
Dienstag, und dieser Datensatz ist es, der beides unterscheidet. Jede
Compliance-Kennzahl, die Sie bauen, verbindet sich hier.
Sie dürfen auch null sein. Fehlt min oder max, haben Sie keine Schwelle,
und die ehrliche Antwort für diese Messung lautet „unbekannt“, nicht „im
Bereich“. Sagen Sie das in Ihrer Oberfläche, statt auf Grün zurückzufallen.
Die Schwellen sind die heutigen, nicht die, die damals galten. Der Snapshot
gibt Ihnen das min und max von heute; eine Messung vom März wurde an dem
gemessen, was im März eingestellt war, und das Restaurant kann sie jederzeit
ändern. Wenn Sie alte Messungen gegen die heutigen Zahlen neu bewerten — mehr
lässt diese API nicht zu —, kennzeichnen Sie das Ergebnis als Ihre
Neuberechnung, nicht als das, was die Küche gesehen hat.
type und state sind nicht eingeschränkte Zeichenketten. Beide sind im
Schema einzelne Freitextfelder ohne Liste dahinter. Zeigen Sie sie an,
gruppieren Sie darauf, wenn es sein muss, und lassen Sie einen unbekannten Wert
nie durch eine Verzweigung ins Schweigen fallen.
outOfRangeCount ist die Zahl der App, nicht Ihre. Das Schema sagt nicht,
welchen Zeitraum sie abdeckt, und Sie können sie aus den Snapshots hier nicht
nachbauen. Behandeln Sie sie als Hinweis aus der App, und wenn Sie eine Zahl
brauchen, die Sie vertreten können, berechnen Sie Ihre eigene aus den Messungen
und den Schwellen und kennzeichnen Sie sie als Ihre.
equipmentSensorId zeigt vom Gerät auf seinen Sensor. Der Sensordatensatz zeigt
in die andere Richtung zurück. Beide Seiten dürfen null sein, und keine ist
garantiert gefüllt, nur weil die andere es ist.
sensors
Die Funkfühler. Zwei Felder, beide optional.
| Feld | Typ | Bedeutung |
|---|---|---|
macAddress | string | null | Die Hardware-Adresse des Fühlers — so unterscheiden Sie ein physisches Gerät vom anderen. |
sensorEquipmentId | string | null | Das Gerät, das dieser Sensor überwacht. |
{
"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"
}
}
Achten Sie auf die beiden Feldnamen, die Spiegelbilder sind und sich leicht
vertauschen lassen: Ein Gerät trägt equipmentSensorId, ein Sensor trägt
sensorEquipmentId. Lesen Sie das falsche, bekommen Sie undefined ohne
Fehler.
Hier gibt es keinen Namen, keinen Batteriestand und keinen Zeitpunkt der letzten
Meldung. Was ein Sensor gemeldet hat, steht in
temperature-readings, und die sind über equipmentId
geschlüsselt statt über den Sensor — ein Fühler, der verstummt ist, sieht also
genau so aus wie einer, der nichts zu melden hatte.
cooking-equipment
Öfen, Warmhalteschränke und der Rest der heißen Seite. Derselbe Gedanke wie bei
equipment, ohne die Technik der Kühlkette.
| Feld | Typ | Bedeutung |
|---|---|---|
index | integer, Pflicht | Anzeigereihenfolge in der eigenen Liste des Restaurants. |
type | string, Pflicht | Um welche Art Einheit es sich handelt. Nicht eingeschränkte Zeichenkette. |
name | string, Pflicht | Die Einheit, so wie die Küche sie nennt. |
min | number | null | Die niedrigste zulässige Temperatur. |
max | number | null | Die höchste zulässige Temperatur. |
areaId | string | null | Der Bereich, in dem sie steht. |
isDeleted | boolean, Pflicht | Das Kennzeichen der App für ausgemusterte Einträge. |
{
"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
}
}
Kein state, kein outOfRangeCount, kein Sensor: Gargeräte werden von einer
Person abgelesen, zwischen den Kontrollen beobachtet sie also nichts. Ihre
Messungen sind cooking-temperature-records, die mit
cookingEquipmentId hierher zeigen — ein anderer Feldname als der der
Kühlkette, und die übliche Stelle, an der ein Client stillschweigend nichts
liest.
Die Karte lesen
Alles auf dieser Seite ist klein, ändert sich langsam und wird gebraucht, bevor irgendeine andere Collection Sinn ergibt.
- Laden Sie es zuerst und halten Sie es. Durchlaufen Sie
areas,equipment,cooking-equipmentundsensors, bevor Sie irgendeine Datensatz-Collection durchlaufen, und lösen Sie Namen und Schwellen aus Ihrer eigenen Kopie auf, statt pro Datensatz. - Frischen Sie es trotzdem auf. Geräte werden umbenannt, Schwellen werden korrigiert, ein Kühlschrank zieht in einen anderen Bereich. Eine Kopie, die einmal genommen und nie wieder durchlaufen wird, läuft auseinander, ohne je zu scheitern.
- Halten Sie Kennungen, keine Kopien — besonders bei Personen. Speichern Sie
userIdund lösen Sie einen Namen beim Anzeigen auf. Siehe die Anmerkung zu personenbezogenen Daten oben. - Beide Löschkennzeichen, überall. Das
deleteddes Umschlags und dasisDeletedindatasind verschiedene Dinge, und die Katalogseite erklärt, welches welches ist.