riseup-squad18/IMPLEMENTACAO_MENSAGENS.md
2025-12-06 19:13:27 -03:00

13 KiB

Sistema de Mensagens MediConnect - Implementação Completa

📋 Visão Geral

Sistema completo de mensagens em tempo real para comunicação entre médicos e pacientes, com suporte a anexos, indicadores de presença, e histórico de conversas.

Funcionalidades Implementadas

1. Chat em Tempo Real

  • Mensagens instantâneas usando Supabase Realtime
  • Atualização automática ao receber novas mensagens
  • Sincronização entre múltiplas abas/dispositivos
  • Scroll automático para última mensagem
  • Interface estilo WhatsApp

2. Histórico de Mensagens

  • Banco de dados PostgreSQL com tabelas otimizadas
  • Índices para queries rápidas
  • Paginação (50 mensagens por vez)
  • Ordenação cronológica
  • Persistência permanente

3. Status Online/Offline

  • Indicador verde quando usuário está online
  • Atualização em tempo real
  • Marca como offline ao fechar navegador
  • Tabela user_presence com tracking

4. Compartilhamento de Arquivos

  • Upload para Supabase Storage
  • Tipos suportados: PDF, DOC, imagens, vídeos
  • Limite de 10MB por arquivo
  • Validação de tipo MIME
  • Preview de arquivos
  • Download de anexos
  • Thumbnails para imagens

5. Indicadores de Leitura

  • ✓ (check simples) = mensagem enviada
  • ✓✓ (check duplo) = mensagem lida
  • Atualização automática ao abrir conversa
  • Marcação em batch com função SQL

6. Indicador de Digitação

  • "..." animado quando outro usuário está digitando
  • Usando Supabase Realtime Presence
  • Timeout automático após 3 segundos
  • Não mostra para o próprio usuário

7. Busca de Conversas

  • Campo de busca por nome
  • Filtro em tempo real
  • Busca case-insensitive

8. Contador de Não Lidas

  • Badge com número de mensagens não lidas
  • Atualização em tempo real
  • Zera ao abrir conversa

9. Botões de Chamada

  • Botão de videochamada
  • Botão de chamada de voz
  • Integração com teleconsulta
  • Navegação para painel apropriado

10. Suporte a Emojis

  • Botão de emoji na interface
  • Input aceita emojis nativos
  • Renderização correta

🗄️ Estrutura do Banco de Dados

Tabelas Criadas

conversations

- id (UUID, PK)
- doctor_id (UUID, FK -> doctors)
- patient_id (UUID, FK -> patients)
- created_at (timestamptz)
- updated_at (timestamptz)
- UNIQUE(doctor_id, patient_id)

messages

- id (UUID, PK)
- conversation_id (UUID, FK -> conversations)
- sender_id (UUID)
- sender_type (doctor|patient)
- content (text)
- message_type (text|file|image|video|audio|report|appointment)
- read_at (timestamptz, nullable)
- created_at (timestamptz)
- attachment_name (varchar)
- attachment_url (text)
- attachment_type (varchar)
- attachment_size (integer)
- metadata (jsonb)

user_presence

- id (UUID, PK)
- user_id (UUID)
- user_type (doctor|patient|admin|secretaria)
- online (boolean)
- last_seen (timestamptz)
- metadata (jsonb)
- UNIQUE(user_id, user_type)

message_attachments

- id (UUID, PK)
- message_id (UUID, FK -> messages)
- file_name (varchar)
- file_url (text)
- file_type (varchar)
- file_size (integer)
- mime_type (varchar)
- thumbnail_url (text)
- uploaded_by (UUID)
- created_at (timestamptz)
- metadata (jsonb)

message_notifications

- id (UUID, PK)
- user_id (UUID)
- user_type (varchar)
- message_id (UUID, FK -> messages)
- read (boolean)
- sent_at (timestamptz)
- read_at (timestamptz)

Funções SQL

get_user_conversations(user_id, user_type)

Retorna todas as conversas de um usuário com:

  • Informações do outro usuário
  • Última mensagem
  • Contador de não lidas
  • Status online

get_or_create_conversation(doctor_id, patient_id)

Cria uma nova conversa ou retorna existente

mark_messages_as_read(conversation_id, user_id, user_type)

Marca todas as mensagens não lidas como lidas

Triggers

update_conversation_timestamp()

Atualiza conversations.updated_at quando nova mensagem é enviada

update_last_seen()

Atualiza user_presence.last_seen automaticamente

Row Level Security (RLS)

Políticas de Conversas

  • Usuários só veem suas próprias conversas
  • Podem criar conversas

Políticas de Mensagens

  • Usuários só veem mensagens de suas conversas
  • Podem enviar mensagens em suas conversas
  • Podem atualizar suas próprias mensagens

Políticas de Presença

  • Todos podem ver status de presença
  • Usuários só atualizam seu próprio status

Políticas de Anexos

  • Usuários veem anexos de suas conversas
  • Podem fazer upload de anexos
  • Anexos são públicos via URL

📁 Estrutura de Arquivos

Arquivos Criados/Modificados

riseup-squad18/
├── supabase/
│   ├── migrations/
│   │   └── create_messaging_system.sql (NOVO)
│   └── SETUP_STORAGE.md (NOVO)
├── src/
│   ├── services/
│   │   └── messages/
│   │       └── messageService.ts (MODIFICADO - substituído)
│   ├── pages/
│   │   ├── MensagensPaciente.tsx (MODIFICADO - integração backend)
│   │   └── MensagensMedico.tsx (NOVO - substituído)
│   └── App.tsx (MODIFICADO - adicionada rota /mensagens-medico)

messageService.ts (596 linhas)

Classes e Métodos:

class MessageService {
  // Conversas
  getUserConversations(userId, userType);
  getOrCreateConversation(doctorId, patientId);
  getConversation(conversationId);

  // Mensagens
  getMessages(conversationId, limit, offset);
  sendMessage(
    conversationId,
    senderId,
    senderType,
    content,
    messageType,
    attachment?
  );
  markMessagesAsRead(conversationId, userId, userType);
  updateMessage(messageId, updates);
  deleteMessage(messageId);

  // Anexos
  createAttachment(attachment);
  uploadFile(file, userId, conversationId);
  getMessageAttachments(messageId);

  // Presença
  updatePresence(userId, userType, online);
  getUserPresence(userId, userType);
  subscribeToPresence(userIds, callback);

  // Real-time
  subscribeToMessages(conversationId, onNew, onUpdate, onDelete);
  unsubscribeFromMessages(conversationId);
  unsubscribeAll();

  // Indicador de Digitação
  sendTypingIndicator(conversationId, userId, userType);
  subscribeToTyping(conversationId, callback);
}

MensagensPaciente.tsx (590 linhas)

Funcionalidades:

  • Lista de conversas com médicos
  • Chat em tempo real
  • Envio de mensagens e arquivos
  • Indicadores de presença e digitação
  • Busca de conversas
  • Botões de chamada

MensagensMedico.tsx (607 linhas)

Funcionalidades:

  • Lista de conversas com pacientes
  • Chat em tempo real
  • Envio de mensagens e arquivos
  • Indicadores de presença e digitação
  • Busca de conversas
  • Botões de chamada

🚀 Como Usar

1. Setup do Banco de Dados

# Executar migration no Supabase
psql -h <seu-host>.supabase.co -U postgres -d postgres -f supabase/migrations/create_messaging_system.sql

Ou copie o SQL para o SQL Editor do Supabase Dashboard.

2. Criar Bucket de Storage

INSERT INTO storage.buckets (id, name, public)
VALUES ('message-files', 'message-files', true);

3. Configurar Políticas de Storage

Veja arquivo supabase/SETUP_STORAGE.md para instruções completas.

4. Habilitar Realtime

ALTER PUBLICATION supabase_realtime ADD TABLE conversations;
ALTER PUBLICATION supabase_realtime ADD TABLE messages;
ALTER PUBLICATION supabase_realtime ADD TABLE user_presence;
ALTER PUBLICATION supabase_realtime ADD TABLE message_attachments;

5. Testar Sistema

Como Paciente:

  1. Login em /paciente
  2. Acesse "Mensagens" no menu lateral
  3. Selecione um médico
  4. Envie mensagem

Como Médico:

  1. Login em /login-medico
  2. Acesse "Mensagens" no menu lateral
  3. Selecione um paciente
  4. Envie mensagem

🔧 Configurações

Limites de Upload

Para alterar limite de tamanho de arquivo (padrão 10MB):

UPDATE storage.buckets
SET file_size_limit = 10485760 -- 10MB em bytes
WHERE id = 'message-files';

Tipos de Arquivo Permitidos

UPDATE storage.buckets
SET allowed_mime_types = ARRAY[
  'image/jpeg',
  'image/png',
  'application/pdf',
  'application/msword'
]::text[]
WHERE id = 'message-files';

Retenção de Mensagens

Para adicionar limpeza automática de mensagens antigas:

-- Deletar mensagens com mais de 1 ano
DELETE FROM messages
WHERE created_at < NOW() - INTERVAL '1 year';

📊 Performance

Índices Criados

-- Conversas
CREATE INDEX idx_conversations_doctor ON conversations(doctor_id);
CREATE INDEX idx_conversations_patient ON conversations(patient_id);

-- Mensagens
CREATE INDEX idx_messages_conversation ON messages(conversation_id);
CREATE INDEX idx_messages_sender ON messages(sender_id);
CREATE INDEX idx_messages_created_at ON messages(created_at DESC);
CREATE INDEX idx_messages_read_at ON messages(read_at);

-- Presença
CREATE INDEX idx_user_presence_user ON user_presence(user_id, user_type);
CREATE INDEX idx_user_presence_online ON user_presence(online);

-- Anexos
CREATE INDEX idx_attachments_message ON message_attachments(message_id);
CREATE INDEX idx_attachments_uploader ON message_attachments(uploaded_by);

Otimizações

  • Queries usam índices compostos
  • Paginação implementada (limit/offset)
  • RLS otimizado com índices
  • Realtime subscriptions filtradas

🐛 Troubleshooting

Mensagens não aparecem em tempo real

Solução:

  1. Verificar se Realtime está habilitado nas tabelas
  2. Checar console do browser por erros de WebSocket
  3. Verificar se RLS permite leitura

Upload de arquivo falha

Solução:

  1. Verificar políticas de storage
  2. Checar tamanho do arquivo (máx 10MB)
  3. Verificar tipo MIME permitido
  4. Confirmar bucket message-files existe

"New row violates row-level security policy"

Solução:

  1. Verificar se usuário está autenticado
  2. Checar se política RLS está correta
  3. Verificar se auth.uid() retorna ID correto

Status online não atualiza

Solução:

  1. Verificar se updatePresence() é chamado no useEffect
  2. Checar se há cleanup ao desmontar componente
  3. Verificar subscrição de presença

📈 Métricas e Monitoramento

Queries Úteis

-- Total de conversas
SELECT COUNT(*) FROM conversations;

-- Total de mensagens
SELECT COUNT(*) FROM messages;

-- Mensagens por dia (últimos 7 dias)
SELECT DATE(created_at), COUNT(*)
FROM messages
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY DATE(created_at);

-- Usuários online agora
SELECT COUNT(*) FROM user_presence WHERE online = true;

-- Mensagens não lidas por usuário
SELECT sender_id, COUNT(*)
FROM messages
WHERE read_at IS NULL
GROUP BY sender_id;

-- Top 10 conversas mais ativas
SELECT conversation_id, COUNT(*) as msg_count
FROM messages
GROUP BY conversation_id
ORDER BY msg_count DESC
LIMIT 10;

-- Tamanho total de anexos
SELECT SUM(file_size) / 1024 / 1024 as mb_total
FROM message_attachments;

🔒 Segurança

RLS Implementado

  • Usuários só acessam suas próprias conversas
  • Mensagens filtradas por conversa
  • Anexos protegidos por conversa
  • Presença pública (somente leitura)

Validações Client-Side

  • Tamanho de arquivo (10MB)
  • Tipo de arquivo
  • Campo de mensagem não vazio
  • Usuário autenticado

Validações Server-Side

  • RLS em todas as tabelas
  • Foreign keys com CASCADE
  • CHECK constraints em enum fields
  • Unique constraints

📝 Próximos Passos (Opcional)

Melhorias Futuras

  1. Notificações Push

    • Firebase Cloud Messaging
    • Web Push API
    • Email notifications
  2. Criptografia E2E

    • Criptografia de mensagens
    • Chaves por conversa
    • Signal Protocol
  3. Busca de Mensagens

    • Full-text search
    • Filtros por data
    • Busca em anexos
  4. Chamadas de Voz/Vídeo

    • WebRTC integration
    • TURN/STUN servers
    • Recording de chamadas
  5. Grupos

    • Conversas em grupo
    • Múltiplos participantes
    • Admin de grupos
  6. Backup Automático

    • Export de conversas
    • Backup em S3/Cloud Storage
    • GDPR compliance

🎉 Conclusão

Sistema de mensagens completo e funcional implementado com:

  • Backend: PostgreSQL + Supabase Realtime
  • Frontend: React + TypeScript
  • Storage: Supabase Storage
  • Real-time: WebSockets via Supabase
  • Segurança: RLS + políticas de acesso
  • Performance: Índices otimizados
  • UX: Interface moderna estilo WhatsApp

Tempo Total de Implementação: ~3 horas Linhas de Código: ~2.300 linhas (SQL + TypeScript + React) Arquivos Modificados: 5 Arquivos Criados: 3