Instalaciones y personas

El local, su personal, sus zonas y sus máquinas: el mapa fijo del que cuelga toda lectura de temperatura.

Estas son las cosas que no se mueven: el restaurante en sí, las personas que trabajan en él, las zonas en que se divide y las máquinas que mantienen los alimentos a una temperatura. Nada de esto es un control.

Aun así decide qué significan los controles. Una temperatura es un número sin ningún veredicto adjunto hasta que lee los umbrales del equipo en que se tomó, y una lectura pertenece a una parte del edificio solo porque el equipo dice en qué zona está. Equivóquese en esta página y todas las cifras que vengan después estarán mal en silencio.

ColecciónPermisoQué es un registro
restaurantsrestaurants:readEl local en sí: nombre, dirección, días de cierre, ajustes.
usersusers:readUna cuenta de personal que registra controles.
areasareas:readUna zona en que se divide el local: cocina, cámara frigorífica, barra.
equipmentequipment:readUna nevera, un congelador, un equipo de cadena de frío, con sus umbrales.
sensorssensors:readUna sonda inalámbrica, por dirección MAC.
cooking-equipmentcooking-equipment:readUn horno u otro equipo de cocción, con sus umbrales.

Las seis comparten el sobre de instantánea: id, deleted, capturedAt, receivedAt, sequence y los demás campos acompañan al data que se describe más abajo.

restaurants

El local al que está acotada su clave, como registro. Uno por restaurante, así que esta colección suele ser una sola página.

CampoTipoSignificado
namestring, obligatorioEl nombre del local, tal como se muestra en la aplicación.
addressstring, obligatorioLa dirección postal, como una única cadena.
closingDaysstring[], obligatorioLos días que el local está cerrado. Cadenas a secas, sin restricción del esquema.
exceptionalClosuresobject[]Cierres puntuales, cada uno un objeto con from y to.
detailedAddressobject | nullLa dirección desglosada en partes, cuando la aplicación la guarda así.
deliveryAddressstring | nullDónde se entregan las mercancías, cuando difiere de address.
deliveryDetailedAddressobject | nullLo mismo, por partes.
preferredLanguagestring | nullEl idioma en que trabaja el restaurante.
multiAreaboolean | nullSi el local está dividido en más de una zona.
settingsobject | nullAjustes de la aplicación. La forma es la de la aplicación y se mueve.
{
  "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
  }
}

El ejemplo muestra solo la mitad operativa. Junto a ella el registro lleva la comercial: subscription, subscriptions, companyName, billingAddress, billingEmail, tvaNumber, trialEndDate, customerId, discount. Existen, están en el documento OpenAPI, y esta página no va a explicárselos.

Lea los campos operativos y deje en paz los comerciales. Describen el contrato del restaurante con nosotros, no su cocina. No son una API de facturación, cambian por motivos que nada tienen que ver con la seguridad alimentaria, y una integración que le muestre a un cliente el estado de su suscripción es un ticket de soporte esperando a ocurrir.

closingDays es una lista de cadenas a secas. El esquema no les impone ninguna forma, así que léalas y muéstrelas; no haga un switch sobre ellas y no dé por hecha una grafía ni unas mayúsculas concretas.

users

Las cuentas del personal que registra los controles. Esto es a quien apunta el userId de un registro de temperatura.

CampoTipoSignificado
firstNamestring, obligatorioNombre de pila, tal como se introdujo.
lastNamestring, obligatorioApellidos, tal como se introdujeron.
emailstring, obligatorioLa dirección de correo electrónico de la cuenta.
phoneNumberstring | nullUn teléfono de contacto, cuando se dio uno.
modulesstring[]Qué partes de la aplicación usa esta persona. Cadenas libres.
preferredNotificationTimestring | nullCuándo pidió esta persona que se le recuerde.
isChildrenboolean | nullUna marca interna. El esquema no le da ningún significado; no construya sobre ella.
isDeletedboolean | nullLa marca de retirada propia de la aplicación, y aquí admite null, a diferencia del resto.
{
  "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
  }
}

Esto son datos personales. email, phoneNumber y los dos campos de nombre identifican a una persona real, y están en esta API por un solo motivo: un registro de seguridad alimentaria tiene que decir quién hizo el control. Esa es la única función que cumplen aquí.

Así que guarde el id y resuelva un nombre para mostrar cuando lo necesite. No copie datos de contacto a sus propias tablas, sus registros, sus eventos de analítica o una herramienta de terceros porque resulte que estaban en la carga útil. El restaurante es el responsable del tratamiento de los datos de su personal, y cada copia que usted haga es una copia de la que ahora tiene que responder.

isDeleted admite null en esta colección donde en las demás es obligatorio, así que trate una marca ausente como «no retirado» en lugar de dejar que cuele como algo parecido a false sin querer. La diferencia entre esa marca y el deleted del sobre está explicada en la página del catálogo.

areas

Una zona del restaurante. Dos campos, y mucho más importante de lo que dos campos sugieren.

CampoTipoSignificado
namestring, obligatorioLa zona tal como la nombra el restaurante: cocina, cámara frigorífica, barra.
isDeletedboolean, obligatorioLa marca de retirada de la aplicación. Véase la página del catálogo.
{
  "id": "9c2b17ae-4d80-4f55-b3e1-0a6c8f4d2b19",
  "collection": "areas",
  "deleted": false,
  "capturedAt": "1789301120440",
  "receivedAt": "1789301126871",
  "sequence": "12",
  "data": {
    "name": "Chambre froide",
    "isDeleted": false
  }
}

areaId es la manera en que todo se agrupa por zonas. Los equipos, los equipos de cocción, las freidoras y las tareas de limpieza llevan uno, y es el único vínculo entre una lectura y una parte del edificio. No hay ningún areaId en los registros en sí: se llega hasta él a través del equipo.

areaId admite null en todos los sitios en que aparece. Una nevera sin zona es normal: significa que nadie se la asignó, normalmente en un local de una sola sala donde multiArea es false. Agrupe esas bajo «sin asignar» en lugar de descartarlas.

equipment

Neveras, congeladores y otros equipos de cadena de frío. El registro que decide si una temperatura era aceptable.

CampoTipoSignificado
indexinteger, obligatorioLa posición que le dio el restaurante en su propia lista. Orden de presentación, no un identificador.
typestring, obligatorioDe qué tipo de equipo se trata. Una cadena sin restricciones: léala, no haga un switch sobre ella.
namestring, obligatorioEl equipo tal como lo llama la cocina.
minnumber | nullLa temperatura aceptable más baja.
maxnumber | nullLa temperatura aceptable más alta.
areaIdstring | nullLa zona en que está.
equipmentSensorIdstring | nullEl sensor instalado en él, cuando hay uno.
statestring | nullEl estado actual del equipo, como cadena sin restricciones.
outOfRangeCountnumber | nullUn recuento de lecturas fuera de rango que mantiene la aplicación.
isDeletedboolean, obligatorioLa marca de retirada de la aplicación.
{
  "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 y max son el único veredicto que va a obtener. Un registro de temperatura lleva un valor, una hora y el equipo en que se tomó; nada que diga si estaba bien. -14,4 °C es una crisis en una nevera y un martes cualquiera en un congelador, y este registro es lo que distingue una cosa de la otra. Toda cifra de cumplimiento que construya cruza por aquí.

También admiten null. Cuando falta min o max no tiene umbral, y la respuesta honesta para esa lectura es «desconocido», no «en rango». Dígalo así en su interfaz en lugar de poner verde por defecto.

Los umbrales son los actuales, no los que se aplicaron. La instantánea le da el min y el max de hoy; una lectura de marzo se juzgó contra lo que estuviera fijado en marzo, y el restaurante puede cambiarlos en cualquier momento. Si vuelve a evaluar lecturas antiguas con las cifras de hoy —que es todo lo que le permite esta API—, etiquete el resultado como recálculo suyo, no como lo que vio la cocina.

type y state son cadenas sin restricciones. Los dos son campos de texto libre en el esquema, sin ninguna lista detrás. Muéstrelos, agrupe por ellos si no le queda más remedio, y nunca deje que un valor desconocido se cuele por un switch hasta el silencio.

outOfRangeCount es la cifra de la aplicación, no la suya. El esquema no dice qué ventana cubre, y no puede reconstruirla a partir de las instantáneas de aquí. Trátela como una señal de la aplicación y, si necesita un recuento que pueda defender, calcule el suyo a partir de las lecturas y los umbrales y etiquételo como suyo.

equipmentSensorId apunta del equipo a su sensor. El registro del sensor apunta en sentido contrario. Los dos lados admiten null, y que uno esté relleno no garantiza que el otro lo esté.

sensors

Las sondas inalámbricas. Dos campos, los dos opcionales.

CampoTipoSignificado
macAddressstring | nullLa dirección de hardware de la sonda: cómo distinguir un dispositivo físico de otro.
sensorEquipmentIdstring | nullEl equipo que vigila este sensor.
{
  "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"
  }
}

Fíjese en los dos nombres de campo, que son imágenes especulares y fáciles de intercambiar: un equipo lleva equipmentSensorId, un sensor lleva sensorEquipmentId. Lea el que no es y obtiene undefined sin ningún error.

Aquí no hay nombre, ni nivel de batería, ni hora del último contacto. Lo que informó un sensor está en temperature-readings, y esas lecturas se indexan por equipmentId y no por el sensor: así que una sonda que se ha quedado muda tiene exactamente el mismo aspecto que una que no tenía nada que informar.

cooking-equipment

Hornos, armarios de mantenimiento y el resto del lado caliente. La misma idea que equipment, sin la maquinaria de la cadena de frío.

CampoTipoSignificado
indexinteger, obligatorioOrden de presentación en la lista del propio restaurante.
typestring, obligatorioDe qué tipo de equipo se trata. Cadena sin restricciones.
namestring, obligatorioEl equipo tal como lo llama la cocina.
minnumber | nullLa temperatura aceptable más baja.
maxnumber | nullLa temperatura aceptable más alta.
areaIdstring | nullLa zona en que está.
isDeletedboolean, obligatorioLa marca de retirada de la aplicación.
{
  "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
  }
}

Ni state, ni outOfRangeCount, ni sensor: los equipos de cocción los lee una persona, así que no hay nada vigilándolos entre control y control. Sus lecturas son cooking-temperature-records, que apuntan aquí con cookingEquipmentId: un nombre de campo distinto del de la cadena de frío, y el sitio habitual donde un cliente lee nada en silencio.

Leer el mapa

Todo lo de esta página es pequeño, cambia despacio y hace falta antes de que ninguna otra colección tenga sentido.

  • Cárguelo primero y consérvelo. Recorra areas, equipment, cooking-equipment y sensors antes de recorrer ninguna colección de registros, y resuelva nombres y umbrales desde su propia copia en lugar de registro a registro.
  • Refrésquelo de todos modos. Los equipos se renombran, los umbrales se corrigen, una nevera se muda a otra zona. Una copia tomada una vez y nunca vuelta a recorrer se desvía sin llegar a fallar nunca.
  • Guarde id, no copias, y con las personas sobre todo. Guarde el userId y resuelva un nombre en el momento de mostrarlo. Véase la nota sobre datos personales de más arriba.
  • Las dos marcas de borrado, en todas partes. El deleted del sobre y el isDeleted de data son cosas distintas, y la página del catálogo explica cuál es cuál.

Última actualización: 2026-09-20.