Limpieza
El plan de limpieza, las tareas realmente hechas y las fotografías que lo demuestran: tres colecciones y qué no prueba un registro ausente.
La limpieza en la aplicación es un plan y su prueba. El restaurante anota qué hay que limpiar, dónde y con qué frecuencia; el personal va marcando las tareas a medida que las hace; algunas de esas tareas exigen una fotografía. Tres colecciones, una por capa, y el cruce entre ellas es donde está casi todo el trabajo.
| Colección | Permiso | Qué es un registro |
|---|---|---|
cleaning-tasks | cleaning-tasks:read | Una línea del plan: qué hay que limpiar, dónde, con qué frecuencia, si necesita una fotografía. |
cleaning-task-records | cleaning-task-records:read | Una tarea hecha de verdad: cuándo y por quién. |
cleaning-task-pictures | cleaning-task-pictures:read | La fotografía que lo demuestra. Lleva un archivo. |
Las tres 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.
cleaning-tasks
El plan en sí. Cambian poco —un restaurante escribe su plan una vez y lo edita cuando cambia la cocina—, así que esta es la colección que menos veces recorrerá y la que más tiempo puede conservar en caché.
| Campo | Tipo | Significado |
|---|---|---|
index | integer, obligatorio | La posición de la tarea en el plan, según la ordena la aplicación. |
name | string, obligatorio | Qué hay que limpiar, en las palabras del restaurante. |
description | string | null | Instrucciones más largas, cuando alguien las escribió. |
areaId | string | null | La zona a la que pertenece. null en un restaurante que no se divide en zonas. |
recurrence | integer, obligatorio | Cada cuánto vuelve la tarea, como un entero a secas. |
requirePhotoProof | boolean | null | true cuando la tarea exige una fotografía. null significa que la aplicación nunca lo fijó. |
isDeleted | boolean, obligatorio | El borrado lógico propio de la aplicación. Lea la nota de abajo. |
{
"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 no lleva unidad. Es un entero y el registro no dice qué cuenta.
Muéstrelo como lo muestra la aplicación en lugar de escribir «cada 1 días» a
partir de una suposición.
isDeleted no es el deleted del sobre. Una tarea que el restaurante quitó
de su plan vuelve con isDeleted: true y deleted: false: sigue siendo un
registro vivo, que describe una línea que ya no se aplica. Filtre por los dos y
conserve las borradas: los registros antiguos siguen apuntando a ellas.
cleaning-task-records
Una tarea hecha. Pequeño a propósito: qué tarea, cuándo, quién.
| Campo | Tipo | Significado |
|---|---|---|
timestamp | string, obligatorio | Cuándo se hizo la tarea, en milisegundos desde la época Unix como cadena. |
cleaningTaskId | string, obligatorio | El registro de cleaning-tasks que satisface. |
userId | string | null | El miembro del personal que la hizo, cuando la aplicación registró uno. |
{
"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 es obligatorio, así que todo registro tiene una tarea. Lo
contrario no se cumple: una tarea puede estar en el plan sin ningún registro
durante semanas, y ese es el estado normal de una tarea semanal un martes.
cleaning-task-pictures
La fotografía. Lleva un archivo, lo que la convierte en la única colección de esta página que no puede consumir solo desde el endpoint de registros.
| Campo | Tipo | Significado |
|---|---|---|
timestamp | string, obligatorio | Cuándo se tomó la fotografía, en milisegundos desde la época Unix como cadena. |
cleaningTaskRecordId | string | null | El registro de cleaning-task-records que demuestra. Admite null: véase más abajo. |
part | number | null | Sin documentar, y un decimal en lugar de un contador. Arrástrelo tal cual en lugar de interpretarlo: la misma advertencia que en las etiquetas de trazabilidad. |
groupId | string | null | Ata esas fotografías entre sí. Los registros que comparten un groupId pertenecen a la misma prueba. |
asset | object, obligatorio | Nombra el archivo: objectKey y status siempre, más contentType, byteLength y sha256 una vez subido. |
{
"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…"
}
}
}
Los bytes son una segunda llamada, contra el propio id del registro:
GET /v1/restaurants/{restaurantId}/collections/cleaning-task-pictures/records/{recordId}/assets
Responde con una lista de URL firmadas, cada una válida durante quince
minutos y con su propia autorización, de modo que la descarga no necesita
cabecera. Descargue los bytes ahora, guarde los bytes en lugar del enlace y
vuelva a llamar al endpoint cuando necesite una URL nueva. Las reglas —qué
aparece, para qué sirve sha256, por qué conviene leer contentType— están en
la página de colecciones, y aquí son las mismas.
asset.status le dice si hay bytes que descargar. Es pending o
uploaded. Un archivo pending es una fotografía que el dispositivo ha
anunciado y todavía no ha terminado de enviar: el registro es real, el archivo
no, y el endpoint de archivos adjuntos responde sin él. Lea el estado antes de
tomar una lista de archivos vacía por una fotografía que nunca se hizo.
cleaningTaskRecordId admite null. Una fotografía puede existir sin
apuntar a ningún registro, así que un cruce que dé por hecho que siempre está
pierde fotografías por el camino. Cuéntelas aparte en lugar de descartarlas en
silencio.
Cruzar las tres
La forma que casi seguro quiere es una fila por tarea hecha, con su línea del plan y sus fotografías:
cleaning-task-records.cleaningTaskId→cleaning-tasks.idcleaning-task-pictures.cleaningTaskRecordId→cleaning-task-records.id
Tres recorridos, unidos por su parte. No hay ningún endpoint que lo haga por usted, y no hay filtro por tarea ni por fecha: recorre cada colección entera y concilia, como describe la página del sobre.
Ordene por capturedAt, no por receivedAt: una tableta en una cámara
frigorífica sube los datos cuando encuentra cobertura, y una fotografía tomada a
las 09:00 puede llegar a las 14:00, después del registro al que pertenece o
antes que él.
Qué no significa un registro ausente
Una línea del plan sin registro que le corresponda no prueba que la tarea se
omitiera. Puede haberse hecho en un dispositivo que todavía no ha subido nada,
o antes de que se activara la captura para ese restaurante. Lo mismo vale para
una tarea marcada con requirePhotoProof: true y sin ninguna fotografía: la
fotografía puede estar a mitad de subida, y un archivo cuya subida no ha
terminado está ausente, no roto.
Así que no saque de esta API una tasa de cumplimentación de la limpieza y la llame cumplimiento. Lo que puede decir con honestidad es qué llegó y cuándo: consulte la nota sobre exhaustividad antes de poner una cifra delante de nadie.