Skip to content

Módulo 6 - Operações em Campo & Telemetria GPS (field-operations)

Módulo 6: Operações em Campo & Telemetria (field-operations)

Section titled “Módulo 6: Operações em Campo & Telemetria (field-operations)”

O módulo Field Operations gerencia a atuação presencial da equipe nos imóveis dos clientes, capturando coordenadas GPS no check-in/out e calculando a compatibilidade entre a funcionária e a residência.


📍 1. Algoritmo de Matching de Equipe (StaffMatchingService)

Section titled “📍 1. Algoritmo de Matching de Equipe (StaffMatchingService)”

Na hora de alocar uma funcionária para um cliente, o StaffMatchingService calcula um Score de Compatibilidade (0 a 100) considerando:

  1. Afinidade Prévia (40%): Histórico de limpezas bem-sucedidas no mesmo cliente.
  2. Proximidade Geográfica (40%): Distância em km entre a residência da funcionária e o imóvel.
  3. Preferência de Idioma (20%): Idioma de comunicação em comum entre a equipe e o cliente.

  • Matching de Equipe: src/features/field-operations/services/StaffMatchingService.ts
  • Hook de Operações: src/features/field-operations/hooks/useExecutionOperations.ts
  • Validação GPS & Ações de Campo: src/components/service-detail/ServiceGeoAction.tsx
    • A checagem de proximidade de 20 segundos usa um gate por epoch de foreground/visita: serializa leituras normais, invalida resultados ao pausar/trocar/desmontar e solicita um fix novo na retomada. Uma posição tardia nunca dispara auto-start no atendimento anterior.
    • Clock-in e finalização adquirem locks antes do primeiro await; a preflight mostra busy e não fecha durante a captura. Toque duplo não duplica GPS, persistência ou Activity Log, e o preparo da evidência não conclui depois do teardown.
  • Aviso de Deslocamento/Trânsito (Transporte Público): src/components/service-detail/modals/TransitDelayModal.tsx & functions/api/channels/transitNotice.ts
    • O envio usa timeout de 15 segundos e controller pertencente ao pedido/cliente visível. Fechar, desmontar ou trocar esse owner aborta a operação; respostas antigas não produzem toast, háptico nem fechamento. Presets e ações ficam congelados durante o envio, e falha devolve a mesma superfície ao estado interativo para retry em desktop, PWA, Android e iOS.
  • Upload de Fotos/Evidências: src/components/service-detail/PhotoUploadZone.tsx envia ao R2 com AbortSignal, epoch de sessão e confirmação autoritativa antes de anexar a URL ao pedido.
  • Custódia de Chaves: KeyCustodyPanel.tsx + KeyCustodyApiService.ts usam /api/field/key-custody; inventário e histórico são persistidos em D1, com auditoria por trigger, autorização administrativa e controle de versão contra transferências concorrentes. Leituras/mutações possuem teto de 12/15 segundos, cancelamento e isolamento por identidade; troca de conta limpa os dados sensíveis e uma operação ativa desabilita todas as ações conflitantes. A interface usa os primitives oficiais, cards móveis/tabela desktop e exige seleção explícita do responsável antes da retirada.
  • Supply Hub: avisos de reposição são compostos sem alterar o cache compartilhado. Auditorias de IA possuem teto de 30 segundos, resposta validada e cancelamento; loading usa conjuntos por cliente, portanto análises/notificações paralelas permanecem visualmente corretas. Single-flight inclui a identidade na chave e epochs impedem resultado, toast ou loading tardio depois de logout/impersonação; insights são apagados imediatamente na troca de conta. Cópia usa o provider nativo/web e trata indisponibilidade do clipboard com feedback recuperável.
  • Incidentes: formulário avulso e fechamento de turno usam CFSelect, CFInput, IconBadge e Button, com seleções aria-pressed, grids adaptativos e alvos de toque canônicos. A descrição é aparada antes do envio e um lock síncrono impede relatórios duplicados. A análise por IA mantém um único AbortController, é cancelada no teardown e mostra falha com opção real de retry.

Check-in, check-out e finalização calculam a próxima solicitação a partir do snapshot síncrono atual do store e publicam o estado otimista antes de rede, log ou toast. Nenhuma escrita ocorre dentro de um updater React/Zustand, portanto uma reinvocação do render não duplica D1 ou Activity Log. Eventos sequenciais no mesmo frame enxergam o resultado anterior, e uma tarefa removida antes da confirmação não produz falso sucesso de finalização em web, PWA, Android ou iOS.

Alocação individual/em série, conclusão manual e mudança administrativa de status seguem a mesma fronteira: o próximo estado é calculado fora do updater e cada tarefa aceita somente uma mutação em voo. Rejeição restaura o snapshot pertencente àquela tentativa; desmontagem ou troca de árvore invalida respostas, rollbacks e toasts tardios. Propagação recorrente e notificações verificam o lifecycle antes do feedback, evitando duplicação por toque/Strict Mode e conclusão vazando para outra sessão nas quatro plataformas.


🚇 3. Aviso de Deslocamento & Trânsito via Transporte Público (Londres TfL)

Section titled “🚇 3. Aviso de Deslocamento & Trânsito via Transporte Público (Londres TfL)”

Quando a funcionária se desloca via metrô/ônibus e prevê uma variação no horário de início, o app calcula a estimativa de trânsito em tempo real (estimateLondonPublicTransit) e despacha com 1 clique uma notificação oficial assinada pela própria funcionária no canal da tarefa (JOB) e via WhatsApp para o cliente.


📶 4. Contrato de Conectividade para Fotos de Vistoria

Section titled “📶 4. Contrato de Conectividade para Fotos de Vistoria”

Fotos não possuem fila offline: uma fila anterior guardava base64 em localStorage e conseguia enviar o arquivo depois, mas não reconciliava a URL resultante no pedido, criando risco de objeto órfão e falso sucesso. Agora a interface detecta ausência/falha de rede, informa que a foto precisa ser selecionada novamente e só chama onAdd depois da resposta válida do R2. O chat continua sendo a única funcionalidade com fila offline persistente, porque possui identidade, owner de sessão e reconciliação completas em IndexedDB.

O portal público /rate compartilha o transporte limitado das demais rotas públicas: contexto encerra em 12 segundos, envio em 15 segundos e teardown aborta a operação. Falha de rede mantém retry explícito e não vira falso “Service not found”; o lock síncrono preserva uma única avaliação em voo em web, PWA, Android e iOS.