Appearance
Regras de Caixas (Inboxes)
Caixas são os canais de atendimento no Chatwoot. Cada loja ativa no WhatsApp tem uma caixa associada.
Estrutura
Organização
└─ Lojas
└─ StoreWhatsappNumber (chatwootInboxId)
└─ Chatwoot Inbox (canal de atendimento)
└─ Agentes (vendedores)Roteamento de mensagem inbound para caixa
Quando o cliente manda uma mensagem, o WhatsappRouterService decide qual caixa usar:
Modo Evolution
- Busca loja preferida do cliente (
preferredStoreId) - Verifica se a loja tem instância Evolution conectada
- Se sim: roteia para a caixa Chatwoot dessa loja
- Se não: tenta loja e-commerce como fallback
Modo WABA Oficial
- Busca conversa aberta no Chatwoot para o cliente nessa caixa
- Se existe: continua na mesma conversa
- Se não existe: cria nova conversa na caixa da loja preferida ou e-commerce
Atribuição de agente
Quando uma conversa é criada em uma caixa, o sistema atribui automaticamente um agente:
Prioridade:
- Vendedor preferido do cliente (
preferredSellerId) — se for agente da caixa- Match: nome do agente Chatwoot começa com "preferredSeller -" + nome do vendedor, OU nome igual (case-insensitive)
- Distribuição por hash do telefone do cliente entre os agentes disponíveis da caixa
Fallback para e-commerce: Se a caixa da loja preferida não tem agentes, tenta a caixa da loja e-commerce. Se ainda assim não tem agentes, a conversa fica sem atribuição.
Business hours e controle de sessão de agentes
O BusinessHoursCronService executa 3 fases ao fechar a loja:
Fase 0 — No fechamento
- Registra Redis flag
bh:closed:{storeId}(TTL 20h) - Serve para detectar quando a loja reabre
Fase 2 — 30 min após fechamento
- Bloqueia novos logins de agentes (
blockAgentLogins) - Envia aviso de encerramento de sessão no Chatwoot
- Inclui horário de encerramento = closeTime + 1h
- Condição: Só bloqueia agentes cujas todas as lojas estão fechadas (proteção OR — agente com múltiplas lojas continua se alguma estiver aberta)
Fase 3 — 60 min após fechamento
- Rotaciona tokens de autenticação dos agentes (
rotateAgentsTokens) - Broadcast de
user:logoutvia Redis pubsub (ActionCable Chatwoot) - Encerramento imediato de sessão (sem esperar 401)
Reabertura
- Cron a cada minuto detecta flag
bh:closed:{storeId}que sumiu (TTL expirou) - Desbloqueia logins (
unblockAgentLogins) - Notifica clientes em espera (queue
BusinessHoursWaiting) - Cria/atualiza conversa no Chatwoot para cada cliente em espera
- Atribui agente e envia saudação
Expiração de conversa (janela 24h Meta)
Cron a cada 30 min: busca conversas com mensagem de boas-vindas enviada há 23h30 ou mais.
- Aplica label
conversa_expirada - Resolve a conversa no Chatwoot (status = resolved)
- Registra em
WindowExpiry - Evita reprocessar via Redis flag
bh:expiry:{conversationId}
Grace period: Conversas com flag bh:grace:{conversationId} (TTL 2h) não são expiradas ainda — foram criadas quando a loja reabriu.
Mensagens configuráveis por caixa
Todas as mensagens enviadas pelo sistema são configuráveis em ChatwootConfig por organização:
| Mensagem | Quando enviada | Variáveis |
|---|---|---|
menuMessage | Cliente entra sem loja preferida | — |
handoffMessage | Cliente é transferido para número de loja | , |
storeGreetingMessage | Loja saúda o cliente (Evolution) | |
activeConversationMessage | Cliente já tem conversa aberta em outra loja | , |
connectingMessage | Modo WABA, conectando ao agente | |
closedMessage | Loja fechada, cliente contacta fora do horário | — |
Menu de seleção de loja
Quando o cliente não tem loja preferida, o sistema exibe um menu:
- ≤ 3 lojas: Botões de resposta rápida (WhatsApp buttons)
- > 3 lojas: Menu de lista (WhatsApp list message)
- Máximo: 10 lojas no menu (limite do sistema)
Ao selecionar a loja:
- A loja é salva como
preferredStoreIddo cliente - Conversa é criada na caixa da loja selecionada
Trocar de loja
Se o cliente enviar a mensagem "trocar de loja", o menu é exibido novamente, independente de ter loja preferida. Essa verificação tem prioridade máxima no roteamento.