Pular para conteúdo

Painel de atendimento

O painel FastAPI em src/emulator/app.py utiliza HTML renderizado por Jinja2 e atualizações parciais. Ele tem autenticação própria por WhatsApp e permanece disponível quando DEV_UI_ENABLED=false. A dashboard de desenvolvimento é outra superfície: ela é bloqueada por essa flag.

Uso pelo operador

Após entrar pelo WhatsApp, abra /atendimento. A lista reúne todos os pendentes e atendimentos em andamento, com área, nome, responsável, resumo e horário. Ao selecionar uma conversa, o painel carrega o histórico daquela sessão, o resumo operacional e o motivo do handoff.

Assumir muda HANDOFF_PENDING para HUMAN. Enviar também assume uma pendência automaticamente. Finalizar fecha o atendimento, remove-o da lista e, quando CRM está habilitado, informa que a sincronização está pendente. O serviço aceita finalizar tanto HUMAN quanto HANDOFF_PENDING, embora a interface apresente a ação de finalização para conversas HUMAN.

assigned_to é informativo, não bloqueia colaboração. A lista não consulta histórico por linha: usa duas consultas por estado; somente a conversa selecionada carrega mensagens. O nome vem de cadastral_data.nome, de recognized_name ou, como fallback, do telefone.

Contratos HTTP

Os POSTs recebem application/x-www-form-urlencoded; não são endpoints de JSON. Requisições autenticadas enviam o cookie gogenetic_operator_session. Tokens dos exemplos são fictícios.

Método / endpoint Entrada Sucesso Erros relevantes
GET /atendimento/acesso/{token} Token no path 200 HTML de confirmação; não consome o token A validade é conferida no POST
POST /atendimento/acesso token 303 para /atendimento, com cookie 400 expirado/consumido; 403 removido da whitelist
GET /atendimento telefone, erro, aviso opcionais 200 HTML; sem sessão mostra tela de acesso Falhas de armazenamento podem impedir carregamento
GET /atendimento/lista telefone opcional Fragmento HTML da fila 401 e HX-Redirect: /atendimento
GET /atendimento/mensagens telefone obrigatório HTML e headers X-Conversation-State, X-Window-Open 401 sem acesso; 404 conversa fora da fila
POST /atendimento/assumir telefone, csrf_token 303 para conversa 401 sessão; 403 CSRF; erro de domínio redireciona com erro
POST /atendimento/enviar telefone, content, csrf_token 303 após envio Mesma autenticação; janela, conteúdo e concorrência viram aviso no redirecionamento
POST /atendimento/finalizar telefone, csrf_token 303 com aviso de encerramento Mudança concorrente ou envio em andamento
POST /atendimento/sair csrf_token Revoga sessão, apaga cookie e redireciona 401/403
GET /atendimento/crm Cookie HTML com PENDING, BLOCKED, UNCERTAIN 401; não oferece mutação de CRM

Exemplo de corpo de envio, para inspecionar no navegador em homologação:

POST /atendimento/enviar
Content-Type: application/x-www-form-urlencoded
Cookie: gogenetic_operator_session=<TOKEN_DE_SESSAO>

telefone=%2B5500000000000&content=Mensagem+ficticia+de+homologacao&csrf_token=<CSRF>

Sucesso retorna 303 e Location: /atendimento?telefone=.... O conteúdo da conversa não é devolvido como Message JSON. Campos obrigatórios ausentes recebem a validação padrão FastAPI, geralmente HTTP 422.

Envio, janela e falhas parciais

send_human_message() limpa espaços externos, rejeita texto vazio e limita o conteúdo a 4.096 caracteres. Exige um inbound há menos de 24 horas; exatamente 24 horas já está fora da janela. O serviço consulta até 200 mensagens do telefone para essa validação; a tela usa o histórico da sessão selecionada. Essa diferença deve ser considerada ao investigar casos de sessão antiga.

Depois de assumir, adquire lock condicional de 90 segundos, envia pelo adapter WhatsApp, registra outbound com operator_phone, agent=None e provider_message_id, e libera o lock em finally. Finalizar durante um envio com lock válido é bloqueado.

Se WhatsApp falhar, o atendimento permanece HUMAN e não há registro outbound de sucesso. Se WhatsApp tiver sucesso mas a persistência do histórico falhar, o resultado é transcript_persisted=false; a tela avisa “Não reenvie”. O cliente já recebeu a mensagem. Use human_message_transcript_persist_failed e o ID do provider para investigar sem duplicar envio. Falha ao liberar lock também não transforma um envio entregue em erro repetível; o lease expira.

Auditoria e CRM

As ações geram eventos operator.assume, operator.send e operator.finalize; o evento de envio inclui IDs, sem copiar seu conteúdo. operator_audit_write_failed indica falha secundária de auditoria.

/atendimento/crm preserva a visibilidade de problemas inclusive de sessões já encerradas. PENDING é trabalho a processar; BLOCKED exige intervenção; UNCERTAIN exige conferir se o negócio já foi criado antes de qualquer repetição. Veja troubleshooting e integração CRM.

Testes e alteração

Execute python -m pytest tests/unit/application/test_human_conversation.py tests/unit/application/test_operator_auth.py tests/unit/lambdas/test_emulator.py -q. Os testes cobrem colaboração, acesso de uso único, cookie seguro, CSRF, janela fechada, concorrência de envio e finalização, e entrega com falha de histórico. Ao alterar formulários, preserve nomes e tokens; ao alterar envio, preserve a distinção entre falha antes e depois da entrega externa.