Pular para conteúdo

Atendimento humano

O atendimento humano começa quando uma sessão entra em HANDOFF_PENDING. O histórico continua sendo recebido pelo WhatsApp e persistido no DynamoDB; a equipe assume, responde e encerra a conversa em /atendimento. A sessão é a fonte de verdade. A atualização comercial no CRM é uma projeção assíncrona e pode continuar pendente após o encerramento no painel.

Componentes e responsabilidades

Componente Localização Responsabilidade
Entrada e comandos src/webhook_handler/app.py Distingue operador de cliente, autentica webhook e persiste mensagens recebidas durante atendimento humano
Handoff src/core/application/process_message_use_case.py Define motivo, estado e resumo operacional; solicita notificação
Disponibilidade src/core/application/operator_availability.py Calcula operadores autorizados disponíveis e fila global
Notificação src/core/integrations/handoff/whatsapp.py Avisa todos os operadores disponíveis na whitelist
Serviço de conversa src/core/application/human_conversation.py assume_conversation, send_human_message, finalize_conversation
Autenticação src/core/application/operator_auth.py Link de uso único, sessão diária e logout
Painel HTTP src/emulator/app.py e src/emulator/templates/operator*.html Login, lista, histórico, ações e pendências do CRM

Fluxo operacional

sequenceDiagram
    participant C as Cliente
    participant W as Webhook / Orchestrator
    participant D as DynamoDB
    participant O as Operador
    participant P as Painel /atendimento
    W->>D: Sessão HANDOFF_PENDING e resumo
    W-->>O: WhatsApp para operadores disponíveis
    O->>W: entrar
    W->>D: Disponibilidade hoje e hash do acesso
    W-->>O: Link de uso único
    O->>P: Abrir link e confirmar acesso
    P->>D: Consumir grant e criar sessão diária
    C->>W: Nova mensagem
    W->>D: Persistir inbound na sessão humana
    O->>P: Assumir / enviar
    P->>D: HANDOFF_PENDING para HUMAN; adquirir lock
    P-->>C: Resposta manual pelo WhatsApp
    P->>D: Registrar outbound e liberar lock
    O->>P: Finalizar
    P->>D: CLOSED e intenção de sincronização CRM

Estados e mensagens recebidas

Estado Comportamento
HANDOFF_PENDING Cliente aguarda equipe. Inbound vai ao histórico sem chamar agente. O webhook pode enviar o aviso fixo de espera; seu recibo impede duplicação do histórico e permite repetir um aviso que falhou.
HUMAN Conversa em atendimento. Inbound fica no histórico; o agente não responde. O painel permite colaboração entre operadores autenticados.
CLOSED Atendimento encerrado; deixa a fila. Um inbound posterior segue a abertura de nova conversa do fluxo normal.

Se a finalização ganhar a corrida contra a gravação de uma mensagem recebida, o webhook reavalia a sessão e trata o inbound como nova conversa. Essa proteção é coberta por test_finalize_winning_inbound_append_race_reroutes_as_new_conversation, em tests/unit/lambdas/test_webhook_handler.py.

Fila, área e colaboração

pending_queue() ordena todas as sessões HANDOFF_PENDING por created_at, da mais antiga para a mais nova. A posição é global, não por segmento. Na interface, pendentes aparecem antes das sessões HUMAN; estas são ordenadas pela atividade mais recente.

O segmento aparece como área (AGRO, ANIMAL, HUMANO, PESQUISA ou GERAL). As áreas organizam a visualização, mas não autorizam acesso nem restringem notificações. assigned_to registra quem assumiu primeiro e é informativo: outro operador autenticado pode responder e finalizar. Um lock de envio de 90 segundos impede dois envios simultâneos na mesma conversa.

Divergência documental

Existem helpers e configurações legadas de operadores por segmento. O caminho atual de notificação usa a interseção entre whitelist efetiva e disponibilidade diária, e envia para todos os elegíveis. Não use HANDOFF_OPERATOR_* como controle de acesso ou garantia de distribuição exclusiva.

Ausência de operador e renotificação

Sem operador disponível, a sessão permanece na fila. Isso não é uma falha de criação do handoff. O comando entrar informa a quantidade aguardando e dá acesso ao painel; ele não envia uma mensagem adicional por cliente já na fila.

src/handoff_renotify/app.py executa a cada hora no SAM. renotify_stale_handoffs() considera, por padrão, pendências com 24 horas desde updated_at. Primeiro notifica a equipe e persiste sua marca; só envia novo aviso ao cliente se o último inbound ainda estiver dentro da janela. Marcas separadas de equipe e cliente evitam repetir etapas já concluídas. O mesmo job encerra conversas abandonadas em TRIAGE, QUALIFYING, DATA_COLLECT e CONFIRM, com motivo timeout e etapa comercial perdido; ele não encerra automaticamente HUMAN.

Veja acesso dos operadores, contratos do painel, handoff e máquina de estados.