Operadores: acesso e disponibilidade¶
A autorização é vinculada ao número de WhatsApp na whitelist efetiva. O webhook intercepta mensagens desses números antes do fluxo de clientes: elas viram comandos operacionais ou a resposta fixa de ajuda, sem criar atendimento de cliente nem invocar o LLM.
Comandos reais¶
parse_whitelist_command(), em src/core/application/whitelist_command.py, aceita maiúsculas/minúsculas, espaços externos, barra inicial opcional e acento em “disponível”. O comando deve ocupar a mensagem inteira.
| Mensagem | Efeito | Resposta esperada |
|---|---|---|
disponivel |
Registra disponibilidade para hoje, gera acesso e consulta total pendente | Confirma disponibilidade, quantidade aguardando se houver e link |
entrar |
Também marca disponível hoje e gera novo acesso | Mesmo fluxo de acesso e disponibilidade |
indisponivel |
Remove registro da disponibilidade | Confirma pausa das notificações |
| Outro texto de operador | Nenhuma ação de conversa | Lista os três comandos atuais |
Comandos antigos como encerrar <telefone> e /assumir <telefone> não executam ações. Assumir e finalizar são feitos no painel. indisponivel não revoga automaticamente um cookie já emitido: disponibilidade para receber avisos e autenticação do navegador têm ciclos próprios. Use Sair para invalidar a sessão do navegador.
Whitelist e disponibilidade¶
effective_whitelist() em src/core/application/admin_tools.py resolve a configuração operacional antes do fallback WHITELIST_PHONE_NUMBERS. available_whitelisted_operators() sempre cruza essa lista com o mapa operator_availability persistido por OperationalConfigRepository.
A disponibilidade é válida somente na data local configurada em BUSINESS_HOURS_TZ, com idade não negativa e no máximo HANDOFF_OPERATOR_AVAILABILITY_TTL_HOURS (default 24). À meia-noite ela vence mesmo que ainda não tenham passado 24 horas. Dias e horários comerciais não bloqueiam notificações: enviar disponivel é a manifestação explícita de disponibilidade naquele dia.
O mapa é atualizado com comparação de updated_at e até 20 tentativas em contenção. O código evita sobrescrever a disponibilidade registrada simultaneamente por outro operador. Erro persistente gera Could not update operator availability under contention.
Login sem senha¶
- O operador envia
entrarao WhatsApp do agente. issue_login_link()gera token aleatório de 32 bytes, armazena somente SHA-256 e monta<OPERATOR_UI_BASE_URL>/acesso/<TOKEN>.- O link expira em 10 minutos ou à meia-noite local, o que chegar primeiro.
- O GET apenas mostra a confirmação. O POST consome o grant atomicamente, para que previews automáticos não gastem o acesso.
exchange_login_link()emite um novo token de sessão e um token CSRF. A sessão expira na próxima meia-noite local.
Configure a base já terminando em /atendimento, por exemplo https://atendimento.example.invalid/atendimento. Informar somente a raiz gera um caminho /acesso/... diferente da rota implementada.
O cookie gogenetic_operator_session tem HttpOnly, SameSite=Lax e caminho /atendimento; é Secure em produção, e também em desenvolvimento acessado por HTTPS. A whitelist é reavaliada no login e nas requisições autenticadas, de modo que remover um número impede o uso posterior do acesso.
DynamoOperatorAuthRepository persiste grants e sessões com TTL e confere expiração no consumo/leitura. A autorização não depende da remoção física imediata pelo mecanismo TTL do DynamoDB. Ler uma sessão de autenticação já expirada também solicita sua remoção.
As mutações exigem csrf_token comparado com hmac.compare_digest. As respostas protegidas usam Cache-Control: no-store, Pragma: no-cache, Referrer-Policy: no-referrer, X-Frame-Options: DENY e X-Content-Type-Options: nosniff. Não envie links de acesso, cookies ou HTML contendo token CSRF a terceiros.
Configuração relacionada¶
| Variável | Uso |
|---|---|
WHITELIST_PHONE_NUMBERS |
Números autorizados, separados por vírgula; pode ter override operacional |
OPERATOR_UI_BASE_URL |
Base pública completa do painel para compor acesso |
BUSINESS_HOURS_TZ |
Data local e expiração diária |
HANDOFF_OPERATOR_AVAILABILITY_TTL_HOURS |
Limite adicional de idade da disponibilidade |
HANDOFF_NOTIFIER_ENABLED, HANDOFF_NOTIFIER_TYPE |
Escolha e ativação do notificador |
WHATSAPP_CLOUD_ENABLED e credenciais Meta |
Envio de respostas e acessos reais |
DEV_UI_ENABLED |
Exposição das ferramentas de desenvolvimento; também influencia o cookie local |
Tipos, defaults e diferenças SAM estão na referência de variáveis.
Falhas e manutenção¶
| Sintoma | Verificação |
|---|---|
| “Este acesso expirou ou já foi utilizado” | Gerar outro com entrar; não reutilizar o POST antigo |
| “Este número não está mais autorizado” | Conferir whitelist operacional e ambiente do link |
| Disponível ontem, sem avisos hoje | Enviar disponivel novamente; conferir fuso operacional |
| Link não é gerado | Conferir OPERATOR_UI_BASE_URL e repository de autenticação |
| Login funciona, envio dá 403 | Recarregar sessão e formulário; conferir CSRF |
| Login em HTTP de produção não persiste | Usar o endpoint HTTPS, pois o cookie é Secure |
Testes: tests/unit/application/test_whitelist_command.py, test_operator_auth.py, test_operator_availability.py; tests/unit/integrations/test_operator_auth_repository.py; e os cenários test_whitelist_entrar_issues_single_use_access_link e test_legacy_whitelist_commands_return_help_without_mutating_session em tests/unit/lambdas/test_webhook_handler.py.