DOCS: Atualizado a documentação do Omnichannel
This commit is contained in:
parent
85627152f6
commit
f55e823e61
38
.env.example
38
.env.example
@ -1,40 +1,38 @@
|
|||||||
# Deploy (docker-compose) environment variables
|
# Deploy (docker-compose) environment variables
|
||||||
|
#
|
||||||
# Postgres (used by postgres service)
|
# Docker Compose sobe somente frontend e backend.
|
||||||
POSTGRES_USER=omnichannel
|
# O PostgreSQL deve existir fora do compose, em uma instancia local, VM, RDS,
|
||||||
POSTGRES_PASSWORD=change-me
|
# container separado ou banco corporativo.
|
||||||
POSTGRES_DB=omnichannel
|
|
||||||
|
|
||||||
# App database connection (used by backend)
|
# App database connection (used by backend)
|
||||||
DB_HOST=postgres
|
DB_HOST=db.empresa.local
|
||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
DB_USER=omnichannel
|
DB_USER=omnichannel
|
||||||
DB_PASSWORD=change-me
|
DB_PASSWORD=change-me
|
||||||
DB_NAME=omnichannel
|
DB_NAME=omnichannel
|
||||||
|
|
||||||
# Ports (optional, if you want to reference in compose later)
|
|
||||||
FRONTEND_PORT=3000
|
|
||||||
BACKEND_PORT=3001
|
|
||||||
|
|
||||||
# Backend HTTP/JWT
|
# Backend HTTP/JWT
|
||||||
|
NODE_ENV=development
|
||||||
PORT=3001
|
PORT=3001
|
||||||
FRONTEND_URL=http://localhost:3000
|
FRONTEND_URL=http://localhost:4000
|
||||||
JWT_SECRET=change-this-long-random-secret
|
JWT_SECRET=change-this-long-random-secret
|
||||||
JWT_EXPIRES_IN=8h
|
JWT_EXPIRES_IN=8h
|
||||||
|
REQUEST_BODY_LIMIT=25mb
|
||||||
|
|
||||||
# Auth providers: ldap,microsoft or only one of them
|
# Auth providers: ldap,microsoft or only one of them
|
||||||
AUTH_PROVIDERS=ldap,microsoft
|
AUTH_PROVIDERS=ldap,microsoft
|
||||||
|
|
||||||
# LDAP / Active Directory
|
# LDAP / Active Directory
|
||||||
LDAP_ENABLED=true
|
LDAP_ENABLED=true
|
||||||
LDAP_URL=ldaps://kratos.sothistelecom.com:636
|
LDAP_URL=ldaps://servidor-ad:636
|
||||||
LDAP_DOMAIN=sothis.com.br
|
LDAP_DOMAIN=empresa.com.br
|
||||||
# Alternative when the bind user is not username@domain:
|
LDAP_USER_DN_TEMPLATE={{username}}@empresa.com.br
|
||||||
LDAP_USER_DN_TEMPLATE={{username}}@sothis.com.br
|
LDAP_SEARCH_BASE=DC=empresa,DC=com
|
||||||
# Optional search to enrich the authenticated profile:
|
|
||||||
LDAP_SEARCH_BASE=DC=sothistelecom,DC=com
|
|
||||||
LDAP_SEARCH_FILTER=(&(objectClass=user)(sAMAccountName={{username}}))
|
LDAP_SEARCH_FILTER=(&(objectClass=user)(sAMAccountName={{username}}))
|
||||||
# LDAP_BIND_DN=CN=ldap-reader,OU=Users,DC=example,DC=com
|
LDAP_TIMEOUT_MS=5000
|
||||||
|
|
||||||
|
# Optional LDAP bind account when search requires service credentials
|
||||||
|
# LDAP_BIND_DN=CN=ldap-reader,OU=Users,DC=empresa,DC=com
|
||||||
# LDAP_BIND_PASSWORD=change-me
|
# LDAP_BIND_PASSWORD=change-me
|
||||||
|
|
||||||
# Microsoft Entra ID OAuth
|
# Microsoft Entra ID OAuth
|
||||||
@ -42,5 +40,5 @@ MICROSOFT_ENABLED=false
|
|||||||
MICROSOFT_TENANT_ID=common
|
MICROSOFT_TENANT_ID=common
|
||||||
MICROSOFT_CLIENT_ID=
|
MICROSOFT_CLIENT_ID=
|
||||||
MICROSOFT_CLIENT_SECRET=
|
MICROSOFT_CLIENT_SECRET=
|
||||||
MICROSOFT_REDIRECT_URI=http://localhost:3001/auth/oauth/microsoft/callback
|
MICROSOFT_REDIRECT_URI=http://localhost:4001/auth/oauth/microsoft/callback
|
||||||
MICROSOFT_SUCCESS_REDIRECT_URL=http://localhost:3000/login
|
MICROSOFT_SUCCESS_REDIRECT_URL=http://localhost:4000/login
|
||||||
|
|||||||
598
README.md
598
README.md
@ -1,478 +1,99 @@
|
|||||||
# Omnichannel Sothis
|
# Omnichannel Sothis
|
||||||
|
|
||||||
Plataforma omnichannel para atendimento com foco inicial em WhatsApp, autenticação corporativa, controle de acesso por perfil, filas por especialidade, agenda de contatos, templates de mensagens e painéis operacionais para agente, supervisor e administrador.
|
Plataforma omnichannel para atendimento com foco inicial em WhatsApp. O sistema combina atendimento em tempo real, Agente Virtual para triagem, filas por especialidade, abertura ativa por template, agenda de contatos, painéis operacionais e administração de usuários/perfis.
|
||||||
|
|
||||||
Este repositório é a raiz do ambiente local/deploy. Ele contém o `docker-compose.yml`, as migrations de banco em `database/` e espera os projetos `frontend/` e `backend/` clonados ou presentes na mesma pasta.
|
O projeto foi construído para validar e evoluir um MVP de atendimento corporativo, com perfis de agente, supervisor e administrador.
|
||||||
|
|
||||||
## Estado Atual do Produto
|
## Principais Recursos
|
||||||
|
|
||||||
O produto hoje permite:
|
- Login corporativo via LDAP/Active Directory.
|
||||||
|
- Estrutura para Microsoft OAuth / Entra ID.
|
||||||
|
- JWT próprio da aplicação com perfis e especialidades.
|
||||||
|
- Atendimento WhatsApp em tempo real via `whatsapp-web.js`.
|
||||||
|
- Socket.IO para atualização de chats/mensagens.
|
||||||
|
- Agente Virtual Sothis para triagem e roteamento.
|
||||||
|
- Fila por especialidade.
|
||||||
|
- Assumir, liberar, transferir e fechar atendimento.
|
||||||
|
- Abertura ativa com templates aprovados.
|
||||||
|
- Agenda de contatos com WhatsApp, telefone/SMS, email, etiqueta e observação.
|
||||||
|
- Painel do agente.
|
||||||
|
- Painel operacional do supervisor.
|
||||||
|
- Painel administrativo com usuários, acessos, templates, IA, canais e configurações.
|
||||||
|
- Conteúdos da IA e regras/travas.
|
||||||
|
- Migrations SQL versionadas.
|
||||||
|
|
||||||
- Login via Active Directory/LDAP e Microsoft OAuth.
|
## Stack Técnica
|
||||||
- Redirecionamento da Home conforme perfil do usuário.
|
|
||||||
- Atendimento WhatsApp em tempo real com socket.
|
|
||||||
- Triagem automática inicial pelo Agente Virtual Sothis.
|
|
||||||
- Fila de atendimento por especialidade.
|
|
||||||
- Assumir, liberar e transferir atendimentos.
|
|
||||||
- Controle da janela de 24 horas do WhatsApp.
|
|
||||||
- Envio e recebimento de texto, imagem, vídeo, áudio e documentos.
|
|
||||||
- Lazy loading de mídias históricas.
|
|
||||||
- Agenda geral de contatos.
|
|
||||||
- Novo atendimento ativo via templates aprovados.
|
|
||||||
- Notas pessoais do atendente.
|
|
||||||
- Administração de usuários, perfis e especialidades.
|
|
||||||
- Workflow de criação, aprovação, reprovação e exclusão de templates.
|
|
||||||
- Painel mensal do admin e painel operacional do supervisor.
|
|
||||||
|
|
||||||
## Perfis e Acesso
|
### Backend
|
||||||
|
|
||||||
### Usuário sem perfil
|
- Node.js 20+ recomendado.
|
||||||
|
- NestJS `^11.1`.
|
||||||
|
- TypeScript `^6.0`.
|
||||||
|
- PostgreSQL via `pg`.
|
||||||
|
- Socket.IO `^4.8`.
|
||||||
|
- `whatsapp-web.js` `^1.34`.
|
||||||
|
- LDAP via `ldapts`.
|
||||||
|
- JWT via `jsonwebtoken`.
|
||||||
|
- Logs com `winston`.
|
||||||
|
|
||||||
Quando um usuário autentica pela primeira vez e ainda não tem perfil/especialidade definida, ele cai em uma tela vazia informando que não está atribuído a uma área/perfil.
|
### Frontend
|
||||||
|
|
||||||
A liberação desse usuário é feita no painel do admin em `Usuários & Acessos`.
|
- React `^18.3`.
|
||||||
|
- Vite `^5.4`.
|
||||||
|
- React Router `^6.30`.
|
||||||
|
- Socket.IO Client `^4.8`.
|
||||||
|
|
||||||
### Agente
|
### Banco
|
||||||
|
|
||||||
O agente:
|
- PostgreSQL 16 recomendado.
|
||||||
|
- O banco não é gerenciado pelo `docker-compose.yml` deste repositório.
|
||||||
|
- As migrations ficam em `database/migrations`.
|
||||||
|
|
||||||
- Vê somente atendimentos das especialidades em que está vinculado.
|
### Docker
|
||||||
- Pode ver chamados da especialidade enquanto estão na fila.
|
|
||||||
- Só pode responder depois de assumir o atendimento.
|
|
||||||
- Pode liberar um atendimento para voltar para a fila.
|
|
||||||
- Pode transferir atendimento somente depois de assumir.
|
|
||||||
- Pode transferir para outra especialidade ou para outro usuário elegível.
|
|
||||||
- Pode editar/salvar contato na agenda.
|
|
||||||
- Pode criar notas pessoais.
|
|
||||||
- Pode abrir novo atendimento usando template aprovado.
|
|
||||||
|
|
||||||
### Supervisor
|
O Docker Compose da raiz sobe somente:
|
||||||
|
|
||||||
O supervisor:
|
- `backend`
|
||||||
|
- `frontend`
|
||||||
|
|
||||||
- Acessa a Home operacional da supervisão.
|
O banco deve ser externo ao compose: VM, banco corporativo, RDS, container separado ou PostgreSQL local gerenciado fora deste projeto.
|
||||||
- Vê indicadores e filas das especialidades que supervisiona.
|
|
||||||
- Pode usar templates, base de conhecimento, auditoria, atendimento, abrir atendimento, disparo em massa e contatos.
|
|
||||||
- Pode solicitar novos templates, mas eles entram primeiro em aprovação do admin.
|
|
||||||
|
|
||||||
### Admin
|
|
||||||
|
|
||||||
O admin:
|
|
||||||
|
|
||||||
- Não precisa pertencer a uma especialidade.
|
|
||||||
- Vê todas as filas e todos os atendimentos já roteados/classificados.
|
|
||||||
- Não vê conversas ainda em triagem automática do Agente Virtual Sothis (`bot_triage`).
|
|
||||||
- Cria e gerencia especialidades.
|
|
||||||
- Define perfis de usuários.
|
|
||||||
- Pode tornar outro usuário admin.
|
|
||||||
- Pode definir se um usuário atua como agente ou supervisor em especialidades.
|
|
||||||
- Pode aprovar, reprovar e excluir templates.
|
|
||||||
- Acessa a visão mensal administrativa.
|
|
||||||
- Também pode atender, usando o menu administrativo.
|
|
||||||
|
|
||||||
## Regras de Atendimento WhatsApp
|
|
||||||
|
|
||||||
### Triagem automática pelo Agente Virtual Sothis
|
|
||||||
|
|
||||||
Toda primeira mensagem recebida no WhatsApp passa pela triagem automática do Agente Virtual Sothis quando ainda não existe atendimento classificado.
|
|
||||||
|
|
||||||
Regras atuais:
|
|
||||||
|
|
||||||
- Mensagens vazias são registradas, mas não disparam triagem.
|
|
||||||
- Mídia sem legenda é registrada, mas não aciona o Agente Virtual Sothis automaticamente.
|
|
||||||
- A triagem é serializada por conversa para evitar respostas duplicadas quando o WhatsApp dispara eventos quase simultâneos.
|
|
||||||
- O backend guarda `last_routed_message_id` para evitar processar a mesma mensagem mais de uma vez.
|
|
||||||
|
|
||||||
Fluxo de decisão:
|
|
||||||
|
|
||||||
1. Se a mensagem já contém uma intenção clara, o Agente Virtual Sothis roteia direto para a especialidade.
|
|
||||||
2. Se a primeira mensagem é genérica, o Agente Virtual Sothis envia a saudação completa e mantém a conversa em `bot_triage`.
|
|
||||||
3. Se a segunda mensagem ainda não identifica intenção, o Agente Virtual Sothis pede explicitamente: suporte, financeiro ou comercial.
|
|
||||||
4. Se a terceira mensagem ainda for inválida, a conversa cai automaticamente em Suporte.
|
|
||||||
|
|
||||||
Exemplos de intenção:
|
|
||||||
|
|
||||||
- Suporte: suporte, bug, problema, técnico.
|
|
||||||
- Financeiro: boleto, dinheiro, cartão, atraso, fatura.
|
|
||||||
- Comercial: produto, novo, contratar, proposta.
|
|
||||||
|
|
||||||
### Estados do atendimento
|
|
||||||
|
|
||||||
A tabela `whatsapp_chat_atribuicoes` representa o estado do atendimento:
|
|
||||||
|
|
||||||
- `bot_triage`: conversa ainda está com o Agente Virtual Sothis.
|
|
||||||
- `queued`: conversa está na fila da especialidade, sem atendente.
|
|
||||||
- `assigned`: conversa foi assumida ou atribuída diretamente a um atendente.
|
|
||||||
|
|
||||||
Regras:
|
|
||||||
|
|
||||||
- Conversas em `bot_triage` não aparecem para agentes.
|
|
||||||
- Conversas em `queued` aparecem para usuários da especialidade.
|
|
||||||
- Conversas em `assigned` continuam visíveis para a especialidade, mas só o responsável responde.
|
|
||||||
- Admin vê todas as conversas roteadas, exceto `bot_triage`.
|
|
||||||
|
|
||||||
### Assumir, liberar e transferir
|
|
||||||
|
|
||||||
Para responder um chamado, o usuário precisa assumir o atendimento.
|
|
||||||
|
|
||||||
- Ao assumir, `user_id` passa a ser o usuário atual.
|
|
||||||
- Ao liberar, o atendimento volta para fila da especialidade.
|
|
||||||
- Transferência só fica disponível depois que o usuário assume.
|
|
||||||
- Transferência para a mesma especialidade pode apontar para outro usuário.
|
|
||||||
- Transferência para outra especialidade cai na fila da nova especialidade.
|
|
||||||
- A observação da transferência fica visível para o próximo atendente e é limpa depois que o atendimento é respondido.
|
|
||||||
|
|
||||||
### Janela de 24 horas
|
|
||||||
|
|
||||||
O produto respeita a regra operacional do WhatsApp:
|
|
||||||
|
|
||||||
- Conversas têm uma janela de 24 horas representada por `conversation_started_at` e `expires_at`.
|
|
||||||
- Ao abrir atendimento ativo para um cliente, o atendente deve usar template aprovado.
|
|
||||||
- Depois do primeiro contato ativo, o atendimento fica bloqueado para novas mensagens livres até o cliente responder.
|
|
||||||
- Quando o cliente responde, o bloqueio `awaiting_customer_reply` é removido e o atendente pode seguir a conversa.
|
|
||||||
|
|
||||||
## Mensagens e Mídias
|
|
||||||
|
|
||||||
### Envio de mensagens
|
|
||||||
|
|
||||||
Mensagens enviadas por atendente são formatadas com identificação:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Atendente: Nome do Usuário
|
|
||||||
|
|
||||||
Mensagem
|
|
||||||
```
|
|
||||||
|
|
||||||
No WhatsApp, essa identificação é enviada usando negrito:
|
|
||||||
|
|
||||||
```text
|
|
||||||
*Atendente: Nome do Usuário*
|
|
||||||
|
|
||||||
Mensagem
|
|
||||||
```
|
|
||||||
|
|
||||||
Se uma mídia for enviada sem texto, o backend não envia cabeçalho solto. A mídia segue sem legenda.
|
|
||||||
|
|
||||||
### Recebimento de mídias
|
|
||||||
|
|
||||||
Tipos suportados:
|
|
||||||
|
|
||||||
- Imagens: PNG, JPG, JPEG, WEBP.
|
|
||||||
- Vídeos: MP4, WEBM.
|
|
||||||
- Áudios: MP3, OGG, WAV.
|
|
||||||
- Documentos: exibidos como card de arquivo.
|
|
||||||
|
|
||||||
Para preservar performance, o histórico de mensagens não carrega Base64 de mídia diretamente. O frontend busca a mídia sob demanda pelo endpoint:
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /whatsapp/media/:chatId/:messageId
|
|
||||||
```
|
|
||||||
|
|
||||||
### Limites de upload
|
|
||||||
|
|
||||||
O backend aceita JSON até `25mb` por padrão, configurável via:
|
|
||||||
|
|
||||||
```env
|
|
||||||
REQUEST_BODY_LIMIT=25mb
|
|
||||||
```
|
|
||||||
|
|
||||||
O frontend bloqueia anexos acima de 15 MB para evitar falhas de payload e degradação da experiência.
|
|
||||||
|
|
||||||
## Chat
|
|
||||||
|
|
||||||
A tela `/chat` exibe somente conversas reais vindas do backend/WhatsApp. Não existe fallback local de conversas.
|
|
||||||
|
|
||||||
Recursos atuais:
|
|
||||||
|
|
||||||
- Lista de conversas ativas com scroll.
|
|
||||||
- Chat com altura delimitada e scroll interno.
|
|
||||||
- Separador de datas nas mensagens.
|
|
||||||
- Horário por mensagem.
|
|
||||||
- Deduplicação visual de mensagens enviadas localmente e confirmadas por socket.
|
|
||||||
- Ocultação de mensagens vazias.
|
|
||||||
- Botão para assumir atendimento.
|
|
||||||
- Botão para sair do atendimento.
|
|
||||||
- Transferência de atendimento.
|
|
||||||
- Painel de contato do cliente.
|
|
||||||
- Envio de mídia.
|
|
||||||
|
|
||||||
Indicadores na lista:
|
|
||||||
|
|
||||||
- Bolinha amarela: chamado está na fila da especialidade e ainda não foi atribuído.
|
|
||||||
- Bolinha azul: chamado está atribuído ao usuário atual.
|
|
||||||
- Bolinha vermelha: chamado está atribuído a outra pessoa.
|
|
||||||
- Badge de especialidade: mostra para qual fila o chamado foi roteado.
|
|
||||||
- Ícone de contato: indica que o contato está salvo na agenda.
|
|
||||||
|
|
||||||
## Home do Agente
|
|
||||||
|
|
||||||
A Home do agente usa dados reais do chat quando o WhatsApp está conectado.
|
|
||||||
|
|
||||||
Recursos atuais:
|
|
||||||
|
|
||||||
- Últimos atendimentos.
|
|
||||||
- Preview do chat com scroll automático para a última mensagem.
|
|
||||||
- Respostas sugeridas baseadas no contexto.
|
|
||||||
- Envio da resposta sugerida direto para o chat correto.
|
|
||||||
- Comunicados e notas.
|
|
||||||
- Notas pessoais persistidas por usuário.
|
|
||||||
- Relógio/data em tempo real.
|
|
||||||
- Atalhos para scripts, relatórios pessoais, disparo em massa e base de conhecimento.
|
|
||||||
|
|
||||||
## Novo Atendimento
|
|
||||||
|
|
||||||
A tela `/new-attendance` permite iniciar contato ativo.
|
|
||||||
|
|
||||||
Regras:
|
|
||||||
|
|
||||||
- WhatsApp é o canal funcional.
|
|
||||||
- Email e SMS aparecem bloqueados como funcionalidades em construção.
|
|
||||||
- O atendente pode buscar contatos da agenda.
|
|
||||||
- Também pode digitar novo número, nome, empresa e observação.
|
|
||||||
- O telefone tem máscara e seletor de país.
|
|
||||||
- Países disponíveis atualmente: Brasil, EUA, Argentina, Chile e México.
|
|
||||||
- O primeiro contato ativo exige seleção de template aprovado.
|
|
||||||
- Ao iniciar atendimento, o sistema salva/atualiza o contato na agenda e abre o chat daquela conversa.
|
|
||||||
|
|
||||||
## Agenda de Contatos
|
|
||||||
|
|
||||||
A agenda é geral, não vinculada a uma especialidade específica.
|
|
||||||
|
|
||||||
Tabela principal:
|
|
||||||
|
|
||||||
```text
|
|
||||||
agenda_contatos
|
|
||||||
```
|
|
||||||
|
|
||||||
Campos funcionais:
|
|
||||||
|
|
||||||
- Nome.
|
|
||||||
- Empresa.
|
|
||||||
- Telefone.
|
|
||||||
- Observação.
|
|
||||||
- Chat ID.
|
|
||||||
- Usuário que criou/atualizou.
|
|
||||||
|
|
||||||
Na conversa, o telefone não é editável quando vem do WhatsApp, mas nome, empresa e observação podem ser atualizados.
|
|
||||||
|
|
||||||
## Templates WhatsApp
|
|
||||||
|
|
||||||
Templates ficam na tabela:
|
|
||||||
|
|
||||||
```text
|
|
||||||
whatsapp_templates
|
|
||||||
```
|
|
||||||
|
|
||||||
Campos relevantes:
|
|
||||||
|
|
||||||
- `name`
|
|
||||||
- `content`
|
|
||||||
- `area_id`
|
|
||||||
- `status`
|
|
||||||
- `requested_by_role`
|
|
||||||
- `admin_approved_at`
|
|
||||||
- `meta_submitted_at`
|
|
||||||
- `meta_approved_at`
|
|
||||||
|
|
||||||
Status atuais:
|
|
||||||
|
|
||||||
- `approved`: template aprovado e disponível para uso.
|
|
||||||
- `meta_review`: enviado para aprovação da Meta.
|
|
||||||
- `admin_review`: aguardando aprovação do admin.
|
|
||||||
- `rejected`: reprovado pelo admin.
|
|
||||||
|
|
||||||
Regras:
|
|
||||||
|
|
||||||
- Admin cria template e envia para aprovação.
|
|
||||||
- Supervisor cria template, mas ele entra em aprovação do admin.
|
|
||||||
- Admin pode aprovar e enviar para Meta.
|
|
||||||
- Admin pode reprovar.
|
|
||||||
- Admin pode excluir.
|
|
||||||
- A aprovação da Meta é simulada: templates em análise são aprovados automaticamente depois de um intervalo configurado no código.
|
|
||||||
- A listagem possui filtro por especialidade e scroll para não ocupar a página inteira.
|
|
||||||
|
|
||||||
## Painel Admin
|
|
||||||
|
|
||||||
A Home do admin é uma visão mensal.
|
|
||||||
|
|
||||||
Recursos atuais:
|
|
||||||
|
|
||||||
- Filtro por especialidade no topo.
|
|
||||||
- KPIs mensais.
|
|
||||||
- Total de atendimentos.
|
|
||||||
- Tempo médio.
|
|
||||||
- TME.
|
|
||||||
- TMR.
|
|
||||||
- Satisfação.
|
|
||||||
- Atendentes ativos.
|
|
||||||
- Gráfico de atendimentos por dia.
|
|
||||||
- Donut de distribuição por canal.
|
|
||||||
- Ranking de atendentes.
|
|
||||||
- Painel de avisos.
|
|
||||||
- Menu administrativo lateral.
|
|
||||||
|
|
||||||
Menu atual:
|
|
||||||
|
|
||||||
- Home.
|
|
||||||
- Operação.
|
|
||||||
- Usuários & Acessos.
|
|
||||||
- Templates.
|
|
||||||
- Base de conhecimento IA.
|
|
||||||
- Auditoria.
|
|
||||||
- Canais.
|
|
||||||
- Atendimento.
|
|
||||||
- Abrir Atendimento.
|
|
||||||
- Disparo em Massa.
|
|
||||||
- Contatos.
|
|
||||||
- Configurações.
|
|
||||||
- Sair.
|
|
||||||
|
|
||||||
## Usuários & Acessos
|
|
||||||
|
|
||||||
Tela administrativa para usuários, perfis e especialidades.
|
|
||||||
|
|
||||||
Regras atuais:
|
|
||||||
|
|
||||||
- Usuários vêm do banco/autenticação.
|
|
||||||
- Admin Demo, Supervisor Demo e Atendente Demo foram removidos por migration.
|
|
||||||
- Admin pode editar um usuário em modal.
|
|
||||||
- Se o usuário for admin, não há seleção de especialidades.
|
|
||||||
- Se não for admin, é possível vincular múltiplas especialidades.
|
|
||||||
- Para cada especialidade, o usuário pode atuar como agente ou supervisor.
|
|
||||||
- A criação/edição de especialidades é feita pelo admin.
|
|
||||||
- A definição de supervisores agora ocorre no vínculo do usuário, não dentro da especialidade.
|
|
||||||
|
|
||||||
## Painel Supervisor / Operação
|
|
||||||
|
|
||||||
O painel de supervisor também é usado como visão de operação no menu do admin.
|
|
||||||
|
|
||||||
Recursos atuais:
|
|
||||||
|
|
||||||
- Filtro por especialidade.
|
|
||||||
- KPIs do dia.
|
|
||||||
- Atendimentos finalizados.
|
|
||||||
- Atendimentos em aberto.
|
|
||||||
- Conversas na fila.
|
|
||||||
- Tempo médio do dia.
|
|
||||||
- Atendentes online simulados.
|
|
||||||
- Painel do time.
|
|
||||||
- Fila de espera.
|
|
||||||
- Atribuição via modal.
|
|
||||||
- Gráfico do dia por hora.
|
|
||||||
|
|
||||||
Sempre que há dado operacional disponível, os painéis usam a origem real consolidada. Indicadores sem origem consolidada ainda usam dados de apoio para compor a visão.
|
|
||||||
|
|
||||||
## Autenticação
|
|
||||||
|
|
||||||
Endpoints principais:
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /auth/config
|
|
||||||
POST /auth/login
|
|
||||||
GET /auth/oauth/microsoft/start
|
|
||||||
GET /auth/oauth/microsoft/callback
|
|
||||||
```
|
|
||||||
|
|
||||||
Providers suportados:
|
|
||||||
|
|
||||||
- LDAP/Active Directory.
|
|
||||||
- Microsoft OAuth.
|
|
||||||
|
|
||||||
Variáveis relevantes:
|
|
||||||
|
|
||||||
```env
|
|
||||||
AUTH_PROVIDERS=ldap,microsoft
|
|
||||||
LDAP_ENABLED=true
|
|
||||||
LDAP_URL=ldaps://...
|
|
||||||
LDAP_DOMAIN=...
|
|
||||||
MICROSOFT_ENABLED=false
|
|
||||||
MICROSOFT_TENANT_ID=common
|
|
||||||
MICROSOFT_CLIENT_ID=
|
|
||||||
MICROSOFT_CLIENT_SECRET=
|
|
||||||
```
|
|
||||||
|
|
||||||
## Endpoints Principais
|
|
||||||
|
|
||||||
### WhatsApp
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /whatsapp/status
|
|
||||||
GET /whatsapp/chats
|
|
||||||
GET /whatsapp/messages/:chatId
|
|
||||||
GET /whatsapp/media/:chatId/:messageId
|
|
||||||
POST /whatsapp/send
|
|
||||||
POST /whatsapp/start-attendance
|
|
||||||
POST /whatsapp/assign
|
|
||||||
POST /whatsapp/transfer
|
|
||||||
DELETE /whatsapp/release/:chatId
|
|
||||||
GET /whatsapp/assignment/:chatId
|
|
||||||
```
|
|
||||||
|
|
||||||
### Templates
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /whatsapp/templates
|
|
||||||
POST /whatsapp/templates
|
|
||||||
POST /whatsapp/templates/update/:id
|
|
||||||
POST /whatsapp/templates/approve-admin/:id
|
|
||||||
POST /whatsapp/templates/reject-admin/:id
|
|
||||||
DELETE /whatsapp/templates/:id
|
|
||||||
```
|
|
||||||
|
|
||||||
### Admin / Acessos
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /admin/access/options
|
|
||||||
GET /admin/access/overview
|
|
||||||
GET /admin/access/areas
|
|
||||||
POST /admin/access/areas
|
|
||||||
PUT /admin/access/areas/:id
|
|
||||||
GET /admin/access/users
|
|
||||||
PUT /admin/access/users/:id
|
|
||||||
```
|
|
||||||
|
|
||||||
## Banco de Dados
|
|
||||||
|
|
||||||
Migrations principais:
|
|
||||||
|
|
||||||
- `005_templates.sql`: criação inicial de templates.
|
|
||||||
- `006_whatsapp_assignment_queue.sql`: fila e atribuição de WhatsApp.
|
|
||||||
- `007_whatsapp_triage_state.sql`: estado de triagem automática.
|
|
||||||
- `008_agent_notes.sql`: notas pessoais do atendente.
|
|
||||||
- `009_customer_contacts.sql`: primeira versão de contatos.
|
|
||||||
- `010_agenda_contatos.sql`: agenda geral consolidada.
|
|
||||||
- `011_whatsapp_opening_templates.sql`: templates de abertura ativa.
|
|
||||||
- `012_whatsapp_awaiting_customer_reply.sql`: bloqueio até resposta do cliente.
|
|
||||||
- `013_remove_demo_access_users.sql`: remoção de usuários demo.
|
|
||||||
- `014_whatsapp_template_workflow.sql`: workflow de aprovação de templates.
|
|
||||||
|
|
||||||
## Estrutura do Repositório
|
## Estrutura do Repositório
|
||||||
|
|
||||||
```text
|
```txt
|
||||||
omnichannel/
|
omnichannel/
|
||||||
├── backend/ # API NestJS e regras de negócio
|
├── backend/ # API NestJS e regras de negócio
|
||||||
├── frontend/ # Interface React/Vite
|
├── frontend/ # Interface React/Vite
|
||||||
├── database/migrations/ # Migrations SQL
|
├── database/migrations/ # Migrations SQL
|
||||||
├── docker-compose.yml # Orquestração local
|
├── docs/ # Wiki operacional e arquitetura
|
||||||
├── .env.example # Exemplo de variáveis
|
├── docker-compose.yml # Sobe backend e frontend
|
||||||
└── README.md
|
└── README.md
|
||||||
```
|
```
|
||||||
|
|
||||||
## Como Subir Localmente
|
## Como Subir com Docker Compose
|
||||||
|
|
||||||
Pré-requisitos:
|
1. Configure `.env.development` na raiz com os dados do banco externo.
|
||||||
|
2. Garanta que o PostgreSQL externo esteja acessível a partir do container backend.
|
||||||
- Node.js compatível com os projetos.
|
3. Suba backend e frontend:
|
||||||
- Docker e Docker Compose.
|
|
||||||
- PostgreSQL via `docker-compose`.
|
|
||||||
|
|
||||||
Na raiz:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose up -d --build
|
docker compose up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
Também é possível rodar frontend e backend em modo desenvolvimento:
|
URLs padrão:
|
||||||
|
|
||||||
|
- Frontend: `http://localhost:4000`
|
||||||
|
- Backend: `http://localhost:4001`
|
||||||
|
|
||||||
|
Health:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:4001/health
|
||||||
|
```
|
||||||
|
|
||||||
|
## Como Rodar em Desenvolvimento
|
||||||
|
|
||||||
|
Backend:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
@ -480,66 +101,71 @@ npm install
|
|||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Frontend:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd frontend
|
cd frontend
|
||||||
npm install
|
npm install
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
URLs locais comuns:
|
URLs comuns:
|
||||||
|
|
||||||
- Frontend: `http://localhost:5173`
|
- Frontend Vite: `http://localhost:5173`
|
||||||
- Backend: `http://localhost:3001`
|
- Backend: `http://localhost:3001`
|
||||||
- Status WhatsApp: `http://localhost:3001/whatsapp/status`
|
|
||||||
|
|
||||||
## Variáveis de Ambiente
|
## Banco e Migrations
|
||||||
|
|
||||||
Principais variáveis da raiz:
|
As migrations SQL estão em:
|
||||||
|
|
||||||
```env
|
```txt
|
||||||
POSTGRES_USER=omnichannel
|
database/migrations
|
||||||
POSTGRES_PASSWORD=change-me
|
|
||||||
POSTGRES_DB=omnichannel
|
|
||||||
|
|
||||||
DB_HOST=postgres
|
|
||||||
DB_PORT=5432
|
|
||||||
DB_USER=omnichannel
|
|
||||||
DB_PASSWORD=change-me
|
|
||||||
DB_NAME=omnichannel
|
|
||||||
|
|
||||||
PORT=3001
|
|
||||||
FRONTEND_URL=http://localhost:3000
|
|
||||||
JWT_SECRET=change-this-long-random-secret
|
|
||||||
JWT_EXPIRES_IN=8h
|
|
||||||
|
|
||||||
REQUEST_BODY_LIMIT=25mb
|
|
||||||
```
|
```
|
||||||
|
|
||||||
No frontend, a URL da API deve vir de:
|
Elas representam a intenção de schema final/evolutivo do produto, mas o projeto ainda precisa de um runner formal para aplicar tudo em ordem em ambientes novos.
|
||||||
|
|
||||||
```env
|
Para ambiente novo, antes de subir backend para uso real:
|
||||||
VITE_API_URL=http://localhost:3001
|
|
||||||
```
|
|
||||||
|
|
||||||
## Limitações Conhecidas
|
1. criar o banco PostgreSQL;
|
||||||
|
2. aplicar as migrations em ordem;
|
||||||
|
3. validar tabelas principais;
|
||||||
|
4. criar/atribuir usuário admin;
|
||||||
|
5. subir backend e frontend.
|
||||||
|
|
||||||
- O WhatsApp Web carrega conversas por lazy loading. Nem sempre todo histórico aparece imediatamente após conectar o QR Code.
|
Detalhes em:
|
||||||
- O status real de presença do contato foi removido por limitação prática da biblioteca/WhatsApp Web.
|
|
||||||
- O painel de supervisor ainda possui indicadores simulados onde não há métrica real consolidada.
|
|
||||||
- Email, SMS e ligação não estão operacionais como canais de atendimento.
|
|
||||||
- A aprovação da Meta para templates é simulada.
|
|
||||||
- Mídias ainda trafegam via Base64 no JSON; para produção, o ideal é evoluir para upload/armazenamento próprio e envio por referência.
|
|
||||||
|
|
||||||
## Regras Importantes Para Desenvolvimento
|
- [Deploy e operação](./docs/deploy.md)
|
||||||
|
- [Database](./backend/docs/database.md)
|
||||||
|
|
||||||
- Não reintroduzir fallback local de conversas no chat. O `/chat` deve exibir apenas conversas reais vindas do backend/WhatsApp.
|
## Documentação
|
||||||
- Toda alteração de banco deve virar nova migration numerada.
|
|
||||||
- Não permitir resposta sem atendimento assumido.
|
|
||||||
- Não permitir transferência sem atendimento assumido.
|
|
||||||
- Conversas em `bot_triage` não devem aparecer para agentes.
|
|
||||||
- Admin pode ver todas as filas e atendimentos roteados.
|
|
||||||
- Novo atendimento ativo deve usar template aprovado.
|
|
||||||
- Depois de contato ativo, bloquear novas mensagens livres até resposta do cliente.
|
|
||||||
- Mídia sem texto não deve enviar cabeçalho solto de atendente.
|
|
||||||
|
|
||||||
|
Wiki raiz:
|
||||||
|
|
||||||
|
- [docs/README.md](./docs/README.md)
|
||||||
|
- [Deploy e operação](./docs/deploy.md)
|
||||||
|
- [Arquitetura geral](./docs/arquitetura.md)
|
||||||
|
- [Fluxos end-to-end](./docs/fluxos-end-to-end.md)
|
||||||
|
- [Regras de negócio](./docs/regras-negocio.md)
|
||||||
|
- [ADRs](./docs/adrs.md)
|
||||||
|
- [Ambientes](./docs/ambientes.md)
|
||||||
|
- [Runbook](./docs/runbook.md)
|
||||||
|
|
||||||
|
Backend:
|
||||||
|
|
||||||
|
- [backend/docs/README.md](./backend/docs/README.md)
|
||||||
|
- [Auth](./backend/docs/auth.md)
|
||||||
|
- [WhatsApp](./backend/docs/whatsapp.md)
|
||||||
|
- [Admin](./backend/docs/admin.md)
|
||||||
|
- [Swagger/OpenAPI](./backend/docs/swagger.md)
|
||||||
|
|
||||||
|
## Estado Atual e Próximos Passos
|
||||||
|
|
||||||
|
O produto já foi validado em demo com cliente final. Antes de produção real, os principais fechamentos são:
|
||||||
|
|
||||||
|
- implementar guards JWT no backend;
|
||||||
|
- validar autorização por perfil no backend;
|
||||||
|
- formalizar runner de migrations;
|
||||||
|
- configurar backup/restore do banco externo;
|
||||||
|
- persistir sessão WhatsApp em volume;
|
||||||
|
- criar Swagger com DTOs;
|
||||||
|
- adicionar testes nos fluxos críticos.
|
||||||
|
|||||||
@ -14,25 +14,3 @@ services:
|
|||||||
- "4001:3001"
|
- "4001:3001"
|
||||||
env_file:
|
env_file:
|
||||||
- .env.development
|
- .env.development
|
||||||
depends_on:
|
|
||||||
postgres:
|
|
||||||
condition: service_healthy
|
|
||||||
|
|
||||||
postgres:
|
|
||||||
image: postgres:16-alpine
|
|
||||||
restart: always
|
|
||||||
env_file:
|
|
||||||
- .env.development
|
|
||||||
ports:
|
|
||||||
- "5434:5432"
|
|
||||||
volumes:
|
|
||||||
- pgdata:/var/lib/postgresql/data
|
|
||||||
- ./database/init:/docker-entrypoint-initdb.d
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
pgdata:
|
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
# Arquitetura e Integracao do Modulo WhatsApp (Omnichannel)
|
|
||||||
|
|
||||||
## Visao Geral do Sistema
|
|
||||||
|
|
||||||
Este documento descreve a arquitetura de alto nivel do modulo de **WhatsApp** integrado ao ecossistema **Sothis Omnichannel**. A solucao une uma interface web moderna de atendimento, uma API NestJS robusta e o controle nativo do WhatsApp Web via automacao e WebSockets em tempo real.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Diagrama de Fluxo e Integracao
|
|
||||||
|
|
||||||
O fluxo de comunicacao entre os diferentes componentes do ecossistema e estruturado conforme o diagrama a seguir:
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph TD
|
|
||||||
%% Componentes
|
|
||||||
FE[Frontend - React/Vite]
|
|
||||||
BE[Backend - NestJS]
|
|
||||||
DB[(Banco PostgreSQL)]
|
|
||||||
PERSIST[(Persistencia JSON Local)]
|
|
||||||
PUPP[Puppeteer Client - WhatsApp Web]
|
|
||||||
WPP[Servidores do WhatsApp]
|
|
||||||
|
|
||||||
%% Relacionamentos do Frontend
|
|
||||||
FE <-->|WebSockets: Socket.io| BE
|
|
||||||
FE -->|HTTP: Enviar Mensagem / Atribuir / Liberar| BE
|
|
||||||
|
|
||||||
%% Relacionamentos do Backend
|
|
||||||
BE <-->|Transacoes SQL| DB
|
|
||||||
BE <-->|Leitura/Escrita Cache| PERSIST
|
|
||||||
BE <-->|Automacao de Headless Chrome| PUPP
|
|
||||||
|
|
||||||
%% WhatsApp Web
|
|
||||||
PUPP <-->|Sincronizacao Nativa| WPP
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Divisao de Responsabilidades
|
|
||||||
|
|
||||||
### 1. Frontend (Interface Operacional)
|
|
||||||
* **Visualizacao**: Renderiza o historico de bolhas de mensagens e arquivos de midia (imagens, audios, anexos).
|
|
||||||
* **Posse de Chat (Ownership)**: Permite ao operador assumir chats livres (`takeChat`) ou libera-los (`releaseChat`), aplicando travas visuais se a conversa estiver sob a posse de outro colaborador.
|
|
||||||
* **UX Ininterrupta**: Aplica de-duplicação temporal em milissegundos e cria bolhas locais com ID temporario antes do disparo de rede para garantir experiencia livre de lag.
|
|
||||||
|
|
||||||
### 2. Backend (Orquestracao e Integracao)
|
|
||||||
* **Automacao (whatsapp-web.js)**: Carrega o headless Chrome (via Puppeteer), autentica a sessao por QR Code, inicializa o cliente e gerencia reconexoes.
|
|
||||||
* **Transmissao em Tempo Real**: Escuta eventos de mensagem (`message_create`) do Puppeteer, formata o payload (com suporte a midias baixadas e resolucao inteligente de nomes) e distribui via Socket.io Gateway para a interface do atendente.
|
|
||||||
* **Processamento Pesado**: Aceita payloads de midia em Base64 de ate 50MB no canal de entrada para evitar falhas de upload.
|
|
||||||
|
|
||||||
### 3. Banco de Dados PostgreSQL (Persistencia Transacional)
|
|
||||||
* **Controle de Atribuicoes**: A tabela `whatsapp_chat_atribuicoes` atua como fonte unica da verdade (*Single Source of Truth*) para posse de atendimento.
|
|
||||||
* **Chaves Estrangeiras**: Vincula transacionalmente o ID do chat (`chat_id`) com chaves numericas de usuarios (`user_id`) e setores operacionais (`area_id`).
|
|
||||||
|
|
||||||
### 4. Cache JSON Local (whatsapp-chats-persist.json)
|
|
||||||
* **Performance de Listagem**: Evita multiplas consultas a servidores de rede locais ou API do WhatsApp na listagem inicial de chats operacionais.
|
|
||||||
* **Historico e previews**: Armazena carimbos de tempo (timestamps), contadores de nao lidas e previews de midia de forma otimizada.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Casos de Uso Principais
|
|
||||||
|
|
||||||
### A. Assumir Chat Automaticamente ao Enviar Mensagem
|
|
||||||
1. O operador envia uma mensagem em uma conversa livre.
|
|
||||||
2. O frontend verifica se o chat esta sem dono e faz um POST para `/whatsapp/assign`.
|
|
||||||
3. O backend insere na tabela `whatsapp_chat_atribuicoes` o ID do atendente e o ID numerico de sua respectiva area de trabalho.
|
|
||||||
4. A transacao e confirmada. O frontend atualiza a UI marcando o operador como dono e libera o canal de conversacao.
|
|
||||||
|
|
||||||
### B. Envio e Recebimento de Midias
|
|
||||||
1. O cliente envia uma imagem pelo WhatsApp.
|
|
||||||
2. O Puppeteer no backend detecta a mensagem com midia e baixa seus bytes em tempo real.
|
|
||||||
3. O backend emite via socket os metadados e os bytes brutos (`mimetype`, `data` em base64, `filename`).
|
|
||||||
4. O frontend identifica a presenca da midia e renderiza o player de audio, imagem ou link de download de forma nativa e estetica.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Politicas de Segurança e Versionamento
|
|
||||||
* As pastas de sessoes (`/whatsapp-session`), arquivos locais de persistencia JSON e logs de desenvolvimento estao estritamente declarados nos arquivos `.gitignore` para nao serem expostos nos repositorios Git.
|
|
||||||
* Credenciais de banco residem exclusivamente em arquivos `.env.*` mantidos fora do controle de versao.
|
|
||||||
Loading…
Reference in New Issue
Block a user