Migraciones de datos one-shot (antes scripts CLI en functions/scripts/backfill-*.js). Todas son idempotentes: re-ejecutarlas no causa daño — comparan estado actual vs deseado antes de escribir. Cada acción soporta dry-run para preview sin escribir.
searchTokens en órdenes Popula searchTokens en órdenes existentes

Habilita la búsqueda indexada de OrdenesService.searchOrders en órdenes creadas antes de que el trigger onOrdenWriteSearchTokens fuera desplegado. Las órdenes nuevas obtienen tokens automáticamente; este backfill cubre las legacy. Skip a órdenes con eliminado: true.

Normalizar grupos en equipos PoC Trim + dedup case/acento-insensitive en grupos[]

Limpia el array grupos de cada equipo PoC no eliminado: recorta espacios, colapsa whitespace interno y deduplica entradas que solo difieren en mayúsculas o tildes ("Operaciones" vs "operaciones"). Equivalente a la normalización que ya aplican las páginas de escritura — este backfill cubre los documentos creados antes de ese cambio. Skip a equipos con deleted: true.

Enlazar órdenes/POC por cliente_id Agrega cliente_id estable a docs legacy enlazados por nombre

Órdenes y equipos POC legacy referencian al cliente por nombre (frágil ante renames/typos). Esto les agrega cliente_id haciendo match normalizado del nombre contra los clientes activos. Aditivo: no toca el nombre. Idempotente. Reporta ambiguos (nombre que mapea a 2+ clientes — resolver con dedup) y huérfanos (nombre sin cliente). Usa Dry-run para revisar antes.

IP asignado por cliente Deriva clientes.ip desde los equipos PoC existentes

Calcula el IP asignado de cada cliente a partir del ip de sus equipos PoC (el más frecuente si hay varios) y lo escribe en clientes/<id>.ip solo cuando el cliente aún no tiene IP. Aditivo e idempotente: nunca sobrescribe un IP existente. Reporta ambiguos (clientes con 2+ IPs distintos — se escribe el modo, revisar) y huérfanos (sin IP derivable; recepción debe buscarlo). Recomendado: ejecutar antes Enlazar por cliente_id para máxima cobertura de equipos legacy. Usa Dry-run para revisar antes.

Marcar contratos históricos (seriales) Corte del flujo de seriales: saca los contratos viejos

Marca como seriales_estado: "legacy" todo contrato que hoy esté en activo o aprobado y que aún no tenga estado de seriales. Los saca del nuevo flujo: la lista deja de mostrarlos como "Seriales pendientes", el recordatorio diario los ignora y no se reenvían a activaciones. Solo los contratos generados de aquí en adelante entran al flujo. Idempotente: salta los que ya tienen estado de seriales o no están en activo/aprobado. Usa Dry-run para ver el conteo antes de escribir.

Enlazar modelo del catálogo en equipos PoC Agrega modelo_id + modelo_label a equipos con modelo en texto libre

El modelo del PoC pasó de texto libre a un desplegable ligado al catálogo modelos. Los equipos viejos guardaban el nombre como texto y el desplegable dejó de pre-seleccionarlos (solo hace match exacto del label marca modelo). Esto les agrega modelo_id + modelo_label haciendo match normalizado (sin acentos/mayúsculas) del texto contra el catálogo — probando el label completo y luego el modelo/nombre solo, e incluyendo modelos inactivos. Aditivo: no borra el texto viejo. Idempotente: salta los que ya tienen modelo. Reporta ambiguos (texto que mapea a 2+ modelos) y huérfanos (texto sin modelo en el catálogo — crear/renombrar). Usa Dry-run para ver los números y la muestra de huérfanos antes de escribir.

Carga inicial del pool de equipos por serial Siembra equipos_pool desde contratos, PoC y órdenes vivas

Puebla el pool de equipos serializados (inventario/equipos.html) desde las tres fuentes existentes, con precedencia contrato > PoC > orden: seriales de contratos activos/aprobados → asignado/en cliente; equipos PoC con serial → en PoC (si ya existe por contrato solo enlaza el device); equipos de órdenes vivas (< 1 año, no entregadas) → en taller. Todo entra sin verificar (se confirma después desde la página del pool). Idempotente: los serial+modelo ya presentes se saltan. Reporta colisiones (mismo serial en 2+ modelos — failsafe con doc sufijado) y sospechosos (mismo serial con grafía distinta entre fuentes). El stock físico de bodega NO sale de aquí: se captura con la "toma física" en la página del pool. Usa Dry-run primero.

Vincular contrato en equipos PoC Agrega contrato_doc_id + contrato_id cruzando el serial contra el pool

Los equipos PoC históricos conocen al cliente pero no al contrato. El pool de equipos (equipos_pool) sí sabe a qué contrato pertenece cada serial (sembrado desde los contratos), así que este backfill cruza por serial normalizado y estampa el vínculo en el device. Solo devices activos (los inactivos ya no están en servicio y su serial puede pertenecer hoy al contrato de otro cliente). Conservador — nunca adivina: se salta los ya vinculados, reporta ambiguos (serial que mapea a 2+ contratos) y sospechosos (el cliente del pool no coincide con el del PoC) sin escribirlos. Los batches nuevos ya nacen vinculados desde PoC · Nuevo batch. Aditivo e idempotente. Usa Dry-run para revisar números y muestras antes de escribir.