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ónPermisoQué es un registro
cleaning-taskscleaning-tasks:readUna línea del plan: qué hay que limpiar, dónde, con qué frecuencia, si necesita una fotografía.
cleaning-task-recordscleaning-task-records:readUna tarea hecha de verdad: cuándo y por quién.
cleaning-task-picturescleaning-task-pictures:readLa 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é.

CampoTipoSignificado
indexinteger, obligatorioLa posición de la tarea en el plan, según la ordena la aplicación.
namestring, obligatorioQué hay que limpiar, en las palabras del restaurante.
descriptionstring | nullInstrucciones más largas, cuando alguien las escribió.
areaIdstring | nullLa zona a la que pertenece. null en un restaurante que no se divide en zonas.
recurrenceinteger, obligatorioCada cuánto vuelve la tarea, como un entero a secas.
requirePhotoProofboolean | nulltrue cuando la tarea exige una fotografía. null significa que la aplicación nunca lo fijó.
isDeletedboolean, obligatorioEl 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.

CampoTipoSignificado
timestampstring, obligatorioCuándo se hizo la tarea, en milisegundos desde la época Unix como cadena.
cleaningTaskIdstring, obligatorioEl registro de cleaning-tasks que satisface.
userIdstring | nullEl 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.

CampoTipoSignificado
timestampstring, obligatorioCuándo se tomó la fotografía, en milisegundos desde la época Unix como cadena.
cleaningTaskRecordIdstring | nullEl registro de cleaning-task-records que demuestra. Admite null: véase más abajo.
partnumber | nullSin 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.
groupIdstring | nullAta esas fotografías entre sí. Los registros que comparten un groupId pertenecen a la misma prueba.
assetobject, obligatorioNombra 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.cleaningTaskIdcleaning-tasks.id
  • cleaning-task-pictures.cleaningTaskRecordIdcleaning-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.

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