feat: initial project structure (Model Project) - Backend + Multi-Frontend + Docker
This commit is contained in:
@@ -0,0 +1,382 @@
|
||||
# Inbox Interna — Arquitetura & Roadmap
|
||||
|
||||
**Data:** 2026-04-23
|
||||
**Status:** v1 (Escalações + Human API) ✅ | v2.1 (DM entre Colaboradores) ✅ | v2.2 (Planejado: Group Chat + Broadcast)
|
||||
|
||||
---
|
||||
|
||||
## 📋 O que é?
|
||||
|
||||
**Inbox Interna** = Centro de comunicação interna da equipe para gerenciar escalações de clientes, pedidos de ajuda da IA e colaboração entre setores.
|
||||
|
||||
É onde:
|
||||
- 🎯 **Escalações chegam** quando cliente pede falar com humano no WhatsApp
|
||||
- 🤖 **IA pede ajuda** quando não consegue resolver algo (Human API)
|
||||
- 💬 **Equipe colabora** deixando mensagens de contexto sobre protocolos
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Arquitetura Atual (v1)
|
||||
|
||||
### Tipos de Threads
|
||||
|
||||
| Tipo | Trigger | Origem | Exemplo |
|
||||
|------|---------|--------|---------|
|
||||
| **escalation** | Cliente escala no WhatsApp | Motor NewWhats | Protocolo #123: cliente reclamando |
|
||||
| **human_api** | IA não consegue responder | Motor NewWhats | "Qual é a política de devolução?" |
|
||||
| **ajuda** | Colaborador solicita suporte | UI "Preciso de ajuda" | Dúvida sobre procedimento |
|
||||
| **mensagem** | Anotação de contexto | Colaboradores | "Cliente quer falar com gerente" |
|
||||
| **sistema** | Avisos automáticos | Sistema | "Handoff expirou" |
|
||||
|
||||
### Estrutura de Dados
|
||||
|
||||
```sql
|
||||
internal_messages {
|
||||
id UUID
|
||||
tenant_id INT (isolamento multi-tenant)
|
||||
thread_id UUID (agrupa msgs da mesma conversa)
|
||||
from_account INT (FK → accounts.id)
|
||||
type VARCHAR (escalation|human_api|ajuda|mensagem|sistema)
|
||||
content TEXT
|
||||
ref_id VARCHAR (protocolo ou human_api_request.id)
|
||||
chat_id VARCHAR (vinculado ao chat do WhatsApp)
|
||||
lida BOOLEAN (marca como lida)
|
||||
created_at TIMESTAMP
|
||||
}
|
||||
|
||||
sector_brain_nodes {
|
||||
id UUID
|
||||
sector_id INT
|
||||
type VARCHAR (knowledge|rules|escalation|persona)
|
||||
title VARCHAR
|
||||
content TEXT
|
||||
active BOOLEAN
|
||||
sort_order INT
|
||||
}
|
||||
```
|
||||
|
||||
### Fluxo Atual
|
||||
|
||||
```
|
||||
┌─ WhatsApp ─────┐
|
||||
│ Cliente fala │
|
||||
│ com IA │
|
||||
└────────┬────────┘
|
||||
│
|
||||
┌────▼──────────┐
|
||||
│ Motor NewWhats│
|
||||
│ (porta 8008) │
|
||||
└────────┬──────┘
|
||||
│
|
||||
┌──────▼────────────────┐
|
||||
│ Precisa de ajuda? ────┼─→ Cria Human API request
|
||||
│ Cliente quer humano? ─┼─→ Cria Escalação + Protocolo
|
||||
└──────┬────────────────┘
|
||||
│
|
||||
┌──────▼──────────────┐
|
||||
│ Inbox Interna │
|
||||
│ (internal_messages)│
|
||||
│ │
|
||||
│ Colaborador lê ←──┤── Thread
|
||||
│ Responde ──→┤── Mensagem
|
||||
│ Encerra ←──┤── Reset handoff
|
||||
└──────┬──────────────┘
|
||||
│
|
||||
┌──────▼────────────────┐
|
||||
│ Resposta volta à IA │
|
||||
│ IA continua conversa │
|
||||
│ com cliente │
|
||||
└───────────────────────┘
|
||||
```
|
||||
|
||||
### Filtros (Abas)
|
||||
|
||||
- **Todos** — todas as threads abertas
|
||||
- **Human API** — apenas pedidos de ajuda da IA
|
||||
- **Escalação** — clientes que escalaram
|
||||
- **Ajuda** — colaboradores pedindo suporte interno
|
||||
- **Mensagem** — anotações de contexto
|
||||
- **Sistema** — avisos automáticos
|
||||
|
||||
---
|
||||
|
||||
## 🔴 Lacunas Atuais (v1)
|
||||
|
||||
### ❌ Falta: Comunicação Livre entre Colaboradores
|
||||
|
||||
**Situação atual:**
|
||||
- Só há threads de CONTEXTO (vinculadas a escalações/human API)
|
||||
- Colaboradores não conseguem falar entre si sem um protocolo
|
||||
- Sem forma de fazer DM privada, group chat por setor, ou broadcast
|
||||
|
||||
**Exemplos de uso que FALTAM:**
|
||||
```
|
||||
João: "Maria, qual é o status do pedido #456?"
|
||||
(não há como enviar DM privada)
|
||||
|
||||
Secretária (broadcast): "Servidor em manutenção em 5 min!"
|
||||
(não há como mandar aviso para todos)
|
||||
|
||||
Setor Financeiro: "Pessoal, cliente quer falar sobre boleto..."
|
||||
(não há como falar só com o time do setor)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Sugestão: Coluna de Colaboradores (v2)
|
||||
|
||||
### Análise da Sugestão ✅
|
||||
|
||||
**Layout proposto:**
|
||||
```
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ Abas: Todos | Human API | Escalação | Ajuda | ... │
|
||||
├──────────────────┬──────────────────────────────────┐
|
||||
│ COLABORADORES │ THREADS / CONTEXTO │
|
||||
│ (Coluna) │ │
|
||||
│ │ Protocolo #123 │
|
||||
│ • João (online) │ ├─ Cliente: Fulano │
|
||||
│ • Maria (busy) │ ├─ Setor: Secretária │
|
||||
│ • Pedro (away) │ ├─ Última msg: há 2min │
|
||||
│ • Carla (offline)│ └─ [Responder] [Encerrar] │
|
||||
│ │ │
|
||||
│ [+] Novo │ Protocolo #122 │
|
||||
│ │ ├─ Tipo: Human API │
|
||||
│ │ ├─ Pergunta: "Política..?" │
|
||||
│ │ └─ [Responder] │
|
||||
└──────────────────┴──────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Vantagens ✅
|
||||
|
||||
| Aspecto | Ganho |
|
||||
|---------|-------|
|
||||
| **Navegação rápida** | Clique em colaborador = DM privada |
|
||||
| **Presença visual** | Cor indica online/busy/offline |
|
||||
| **Unread badges** | Quantas DMs não lidas por pessoa |
|
||||
| **Busca** | Filtrar colaboradores por nome |
|
||||
| **Contexto duplo** | Ver threads E falar com pessoas |
|
||||
| **Similar a Slack/WhatsApp** | UX familiar para usuários |
|
||||
| **Iniciar conversa** | Botão [+] abre nova DM |
|
||||
| **Gestão de setores** | Filter "mostrar só meu setor" |
|
||||
|
||||
### Desvantagens ⚠️
|
||||
|
||||
| Risco | Mitigation |
|
||||
|-------|------------|
|
||||
| **Coluna muitas pessoas** | Busca + virtualization se >50 pessoas |
|
||||
| **Clutter na UI** | Coluna colapsável (toggle) |
|
||||
| **Sem histórico persistente** | Arquitetar tabela `direct_messages` |
|
||||
| **Sem notificações SSE** | Adicionar evento SSE `direct_message.new` |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Proposta de Implementação (v2)
|
||||
|
||||
### Fase 1: Estrutura de Dados
|
||||
|
||||
```sql
|
||||
-- Threads de chat direto (novo tipo)
|
||||
direct_messages {
|
||||
id UUID PRIMARY KEY
|
||||
tenant_id INT NOT NULL
|
||||
from_account INT NOT NULL (FK → accounts.id)
|
||||
to_account INT NOT NULL (FK → accounts.id) -- NULL = group chat
|
||||
content TEXT NOT NULL
|
||||
lida BOOLEAN DEFAULT false
|
||||
created_at TIMESTAMP DEFAULT now()
|
||||
}
|
||||
|
||||
-- Group chats por setor
|
||||
group_chats {
|
||||
id UUID PRIMARY KEY
|
||||
tenant_id INT NOT NULL
|
||||
sector_id INT NOT NULL (FK → sectors.id)
|
||||
name VARCHAR NOT NULL
|
||||
topic TEXT
|
||||
created_at TIMESTAMP DEFAULT now()
|
||||
}
|
||||
|
||||
group_chat_members {
|
||||
id UUID PRIMARY KEY
|
||||
group_chat_id UUID (FK → group_chats.id)
|
||||
account_id INT (FK → accounts.id)
|
||||
joined_at TIMESTAMP DEFAULT now()
|
||||
}
|
||||
```
|
||||
|
||||
### Fase 2: UI Layout
|
||||
|
||||
**Nova estrutura:**
|
||||
```
|
||||
├── Sidebar esquerdo
|
||||
│ └─ COLABORADORES (coluna conversável)
|
||||
│ ├─ [🔍 Buscar...]
|
||||
│ ├─ 🟢 João (2 DMs não lidas)
|
||||
│ ├─ 🟡 Maria (online)
|
||||
│ ├─ ⚪ Pedro (away)
|
||||
│ ├─ ⚫ Carla (offline)
|
||||
│ └─ [+] Iniciar DM
|
||||
│
|
||||
└── Conteúdo principal
|
||||
├─ Abas: Todos | Human API | Escalação | Ajuda | Mensagem | Sistema
|
||||
└─ Threads de contexto (atuais)
|
||||
```
|
||||
|
||||
### Fase 3: Funcionalidades
|
||||
|
||||
```
|
||||
📌 DM Privada
|
||||
- Clique em colaborador → abre chat
|
||||
- Histórico persistente
|
||||
- Marca como lido
|
||||
|
||||
👥 Group Chat por Setor
|
||||
- Secretária, Financeiro, etc.
|
||||
- Mensagens visíveis para todo o setor
|
||||
- Notificação de @menção
|
||||
|
||||
📢 Broadcast
|
||||
- Só owner/manager
|
||||
- Aviso para TODOS os colaboradores
|
||||
- "Sistema está em manutenção em 5 min"
|
||||
|
||||
🔔 Notificações SSE
|
||||
- `direct_message.new` → atualiza badge
|
||||
- `group_message.new` → notifica setor
|
||||
- `broadcast.sent` → notifica todos
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Comparação: Atual vs Proposto
|
||||
|
||||
### Inbox Interna v1 (Atual)
|
||||
|
||||
```
|
||||
Uso: Gerenciar escalações + ajuda da IA
|
||||
Threads: Escalação, Human API, Ajuda, Sistema
|
||||
Colaboradores: Implícitos (apenas quem responde)
|
||||
Chat: Não há comunicação livre
|
||||
Comunicação: Apenas REATIVA (resposta a eventos)
|
||||
```
|
||||
|
||||
### Inbox Interna v2 (Proposto)
|
||||
|
||||
```
|
||||
Uso: Escalações + IA + Chat interno + Broadcasts
|
||||
Threads: Escalação, Human API, Ajuda, Sistema, DM, Group, Broadcast
|
||||
Colaboradores: Listados na coluna, clickable
|
||||
Chat: DMs privadas + Group por setor
|
||||
Comunicação: Reativa + Proativa (falar entre si)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Priorização
|
||||
|
||||
| # | Feature | Complexidade | Impacto | Prioridade |
|
||||
|---|---------|--------------|--------|-----------|
|
||||
| 1 | **Coluna Colaboradores** | 🟡 Média | Alto | 🔴 **ALTA** |
|
||||
| 2 | **DM Privada** | 🟢 Baixa | Muito Alto | 🔴 **ALTA** |
|
||||
| 3 | **Group Chat por Setor** | 🟡 Média | Alto | 🟡 **MÉDIA** |
|
||||
| 4 | **Broadcast** | 🟢 Baixa | Médio | 🟡 **MÉDIA** |
|
||||
| 5 | **Notificações SSE** | 🟡 Média | Alto | 🔴 **ALTA** |
|
||||
| 6 | **Busca/Filter** | 🟢 Baixa | Médio | 🟢 **BAIXA** |
|
||||
|
||||
---
|
||||
|
||||
## 📝 Implementação Concluída (Fase 1)
|
||||
|
||||
### ✅ Completados (2026-04-23)
|
||||
|
||||
Backend:
|
||||
- [x] Tabela `direct_messages` criada com indexes
|
||||
- [x] Endpoint: `POST /api/admin/inbox/direct-message` ← enviar DM
|
||||
- [x] Endpoint: `GET /api/admin/inbox/direct/:otherAccountId` ← histórico
|
||||
- [x] Endpoint: `GET /api/admin/inbox/direct-messages` ← últimas DMs
|
||||
- [x] Endpoint: `GET /api/admin/inbox/colleagues` ← listar colaboradores
|
||||
- [x] Endpoint: `PATCH /api/admin/inbox/direct/:messageId/read` ← marcar como lida
|
||||
- [x] DirectMessage model com 6 métodos (send, getConversation, getLastMessages, getUnreadCount, markAsRead, getUnreadCountByContact)
|
||||
- [x] DirectMessageService exportado em admin-app/src/services/api.ts
|
||||
|
||||
Frontend:
|
||||
- [x] CollaboratorsPanel.tsx: coluna com busca, status, badges de não lida
|
||||
- [x] DMConversationView.tsx: chat bubbles, input, auto-scroll
|
||||
- [x] InboxInternaTab.tsx: integração two-column (Inbox + Colaboradores tabs)
|
||||
- [x] Auto-load conversation quando abrir chat
|
||||
- [x] Auto-mark-as-read ao abrir conversa
|
||||
- [x] 30-segundo auto-refresh de colaboradores
|
||||
|
||||
Database:
|
||||
```sql
|
||||
direct_messages {
|
||||
id SERIAL PRIMARY KEY,
|
||||
tenant_id INT,
|
||||
from_account INT,
|
||||
to_account INT,
|
||||
content TEXT,
|
||||
read_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
}
|
||||
-- Indexes: (tenant_id, from_to pairs, read_status, created_at DESC)
|
||||
```
|
||||
|
||||
### 🔄 Próximos Passos
|
||||
|
||||
- [ ] SSE: adicionar evento `direct_message.new` para notificação real-time
|
||||
- [ ] Group Chat por Setor (Fase 2)
|
||||
- [ ] Broadcast para todos (Fase 2)
|
||||
- [ ] Busca em conversas
|
||||
- [ ] Pinning/Marking de mensagens importantes
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Mockup
|
||||
|
||||
```
|
||||
Inbox Interna v2 (esboço)
|
||||
|
||||
┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ COLABORADORES ┃ [Todos] [Human API] [Escalação]... ┃
|
||||
┣━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
┃ [🔍 Buscar...] ┃ ┃
|
||||
┃ ┃ ┌────────────────────────────────┐ ┃
|
||||
┃ 🟢 João 2 ┃ │ Protocolo #123 │ ┃
|
||||
┃ 🟡 Maria 0 ┃ │ ├─ Cliente: Fulano Silva │ ┃
|
||||
┃ ⚪ Pedro 1 ┃ │ ├─ Setor: Secretária │ ┃
|
||||
┃ ⚫ Carla 0 ┃ │ ├─ Criado: há 15 min │ ┃
|
||||
┃ ┃ │ ├─ Status: Aberto │ ┃
|
||||
┃ [+] Iniciar DM ┃ │ └─ [Responder] [Encerrar] │ ┃
|
||||
┃ ┃ └────────────────────────────────┘ ┃
|
||||
┃ ┃ ┃
|
||||
┃ ┃ ┌────────────────────────────────┐ ┃
|
||||
┃ ┃ │ Human API Request │ ┃
|
||||
┃ ┃ │ ├─ Pergunta: "Qual política..."│ ┃
|
||||
┃ ┃ │ ├─ Setor: Financeiro │ ┃
|
||||
┃ ┃ │ └─ [Responder] │ ┃
|
||||
┃ ┃ └────────────────────────────────┘ ┃
|
||||
┗━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Conclusão
|
||||
|
||||
**A sugestão da coluna de colaboradores é excelente** porque:
|
||||
|
||||
1. ✅ Resolve a lacuna de comunicação entre colaboradores
|
||||
2. ✅ UX familiar (similar a Slack/WhatsApp)
|
||||
3. ✅ Melhora discoverabilidade (ver quem está online)
|
||||
4. ✅ Simples de implementar (coluna + nova tabela)
|
||||
5. ✅ Impacto alto na experiência de colaboração
|
||||
|
||||
**Recomendação:** Implementar em **duas fases**:
|
||||
- **Fase 1 (rápida)**: Coluna + DM privada + SSE
|
||||
- **Fase 2 (depois)**: Group chat + broadcast
|
||||
|
||||
---
|
||||
|
||||
**Autor:** Claude
|
||||
**Revisor:** Necessário
|
||||
**Status:** Draft para aprovação
|
||||
Reference in New Issue
Block a user