As pessoas adoram se comunicar. Costumamos brincar que qualquer sistema de software sempre evolui para um sistema de mensagens. Este artigo explicará os requisitos do sistema e a abordagem passo a passo para projetar um modelo de dados para um sistema de mensagens.
Requisitos em poucas palavras
A principal funcionalidade de um sistema de mensagens em um aplicativo é enviar notificações/mensagens para um usuário ou um conjunto de usuários. Nosso sistema também permite enviar mensagens para um grupo de usuários. Grupos de usuários obviamente podem ser formados em alguns parâmetros como privilégios de acesso, localização geográfica dos usuários, etc.
Este sistema permite que os receptores respondam às mensagens. Ele também mantém o controle de quem leu a mensagem e quem não leu.
Além disso, o sistema possui um lembrete integrado mecanismo que permite que um remetente crie um lembrete e, em seguida, envie um lembrete a todos os destinatários de acordo.
Entidades e Relacionamentos
Nesse modelo de dados,
user
e message
são as principais entidades para armazenar detalhes de usuários e mensagens. Colunas no
user
table seriam atributos relacionados ao usuário como first_name
, last_name
, etc
Algumas colunas autoexplicativas na message
tabela seria subject
, message_body
, create_date
e expiry_date
. Eu também adiciono uma coluna de chave estrangeira chamada creator_id
nesta tabela que se refere ao id
coluna de user
tabela. Como o próprio nome sugere, significa o id do criador de uma mensagem. Como sempre haveria um criador para uma mensagem, mantenho essa coluna apenas na tabela de mensagens. Você pode estar se perguntando por que existe uma expiry_date
coluna na tabela. Eu adicionei esta coluna para gerenciar lembretes em uma mensagem. Explicarei mais sobre esta coluna mais adiante neste artigo.
A tabela mais importante neste modelo de dados é message_recipient
. Eu diria que todo o modelo de dados gira em torno apenas desta tabela. Um dos principais objetivos por trás da criação desta tabela é realizar o mapeamento entre as mensagens e seus destinatários. Assim, o recipient_id
coluna nesta tabela significa os IDs dos destinatários, e esta coluna se refere à coluna de ID de user
tabela.
Quando uma mensagem é enviada para um destinatário, um registro será inserido nesta tabela com o id do destinatário no recipient_id
coluna.
Agora você pode estar se perguntando qual é o recipient_group_id
coluna significa nesta tabela. Aqui, devo explicar primeiro como esse modelo pode ser estendido para um requisito de envio de mensagens para vários destinatários de uma só vez.
Enviando mensagem para um grupo
Eu preciso de outra tabela, chamada
group
, para manter os detalhes do grupo. Como há uma relação muitos-para-muitos entre o user
e group
tabelas, ou seja, um usuário pode fazer parte de mais de um grupo, vou criar outra tabela chamada user_group
. Por exemplo, se um grupo for formado com 25 usuários, haverá 25 registros, um para cada usuário, no
user_group
tabela.
Vamos voltar ao message_recipient
tabela. Eu adiciono uma referência à chave primária do user_group
tabela no message_recipient
tabela. Eu o nomeio recipient_group_id
. Esta coluna conterá o valor do grupo de usuários para o qual a mensagem é enviada.
Agora, sempre que uma mensagem for enviada a um grupo, vários registros serão inseridos no message_recipient
tabela com base no número de usuários no grupo e no recipient_group_id
será registrado de acordo com todos esses registros.
Deixe-me ilustrá-lo ainda mais com um exemplo. Suponha que uma mensagem seja enviada para um grupo de 10 pessoas. Nesse caso, um total de 10 registros, um para cada recipient_group_id
do grupo, será inserido no message_recipient
tabela.
Observe que, se a mensagem for enviada a um usuário, não a um grupo, o recipient_group_id
coluna permanece vazia. Nesse caso, o user_id
direto será registrado sob o recipient_id
coluna.
Vou adicionar mais uma coluna chamada is_read
na tabela para manter um sinalizador contra um usuário de mensagem que significa se a mensagem é lida ou não pelo usuário.
Chave exclusiva message_recipient
table – Deve haver uma chave única composta nas colunas message_id
, recipient_id
e recipient_group_id
, para garantir que exista apenas um registro para uma combinação exclusiva dessas colunas.
Eu mantenho o is_active
coluna em todas as tabelas, exceto as tabelas message e message_recipient, para habilitar uma ‘exclusão reversível’ de registros. Como adicionei um expiry_date
coluna na tabela de mensagens, um is_active
coluna não é necessária. Além disso, esta coluna não é necessária no message_recipient
table porque uma mensagem não pode ser revertida diretamente depois de enviada. No entanto, pode-se torná-lo inativo atualizando o expiry_date
para a mensagem para uma data no passado.
Responder a uma mensagem
Agora suponha que o sistema permita que os usuários respondam às mensagens recebidas. Eu estendo a mesma tabela
message
para atender a esse requisito em vez de criar uma nova tabela para respostas. Vou adicionar uma coluna chamada parent_message_id
para estabelecer uma relação hierárquica entre as mensagens. Vou inserir um novo registro para mensagem de resposta e atualizar o parent_message_id
coluna para mensagens de resposta. Este modelo suporta n-level de relacionamento hierárquico, ou seja, a resposta na mensagem de resposta também pode ser rastreada através deste modelo.
Painel para visualizar '% de leitura' de cada mensagem
O
is_read
sinalizador é registrado em cada registro de usuário de mensagem. O valor para este sinalizador permanece ZERO até que a mensagem seja lida pelo usuário. Ele será atualizado para ONE assim que a mensagem for lida pelo usuário. Com base no valor da coluna, pode-se determinar ‘read %’ para uma mensagem que é enviada a um grupo. Deixe-me escrever um exemplo de SQL para buscar esse relatório:
SELECT msg.subject, sent_to, msg.create_date, (summ / countt) * 100 AS Read_Per FROM (SELECT msg.subject, grp.name as sent_to, msg.create_date, SUM (is_read) AS summ, COUNT (is_read) AS countt FROM message_recipient msgrec, message msg, user_group ug, group grp WHERE msgrec.message_id = msg.id AND msgrec.recipient_group_id = ug.id AND ug.GROUP_ID = grp.id AND msgrec.recipient_group_id IS NOT NULL GROUP BY msg.subject, grp.name, msg.create_date UNION SELECT msg.subject, u.first_name || ' ' || u.last_name as sent_to, msg.create_date, SUM (is_read) AS summ, COUNT (is_read) AS countt FROM message_recipient msgrec, MESSAGE msg, user u WHERE msgrec.message_id = msg.id AND msgrec.recipient_id = u.id AND msgrec.recipient_group_id IS NULL GROUP BY msg.subject, name, msg.create_date);
Assunto | Enviado para | Enviado | Ler % |
---|---|---|---|
Entrega do projeto na terça-feira | Equipe de entrega do projeto | 13/09/2015 08:15 | 42% |
Encontre-me na segunda-feira | João D | 10/09/2015 13:30 | 100% |
Sincronize o ambiente de desenvolvimento com a produção | Equipe de DBA | 09/09/2015 09:11 | 80% |
Fechando NCRs de auditoria | Equipe NSS | 09/09/2015 17:50 | 45% |
Mecanismo de lembrete
Para uma funcionalidade de lembrete, adicionarei as seguintes colunas na tabela de mensagens:
Is_reminder
– Esta coluna sinaliza se um lembrete é necessário ou não para a mensagem.Reminder_frequency_id
– Esta coluna significa a frequência do lembrete. Deve ser diário ou semanal?Next_remind_date
– Esta coluna contém a data em que o próximo lembrete precisa ser enviado. O lembrete será enviado emnext_remind_date
para os usuários para os quais o sinalizador 'is_read' ainda é ZERO. Um novo valor para esta coluna será calculado sempre que um lembrete for enviado.Expiry_date
– Esta coluna é a data limite em que os lembretes não serão mais enviados aos usuários.
Cálculo do next_remind_date
seria o seguinte – Suponha que uma mensagem seja enviada aos usuários em 14/09, segunda-feira, com 05/10 como data de expiração. A mensagem é enviada com uma frequência semanal de lembretes. Nesse caso, lembretes serão enviados aos usuários nos dias 21 e 28/09 para respondê-los por e-mail e uma última vez em 05/10 para incentivá-los a responder nas próximas 24 horas.
Modelo de dados final
Conclusão
Um dos melhores usos deste sistema de mensagens é enviar notificações para usuários que estão inativos no sistema há muito tempo. Essas notificações podem ser enviadas com um mecanismo de lembrete ativado e as notificações serão enviadas aos usuários até que os usuários respondam à notificação. Os usuários serão desativados na data de expiração e após a data de expiração se nenhuma resposta às notificações for recebida por eles.
Eu pretendia construir um modelo de dados para um sistema de mensagens totalmente funcional, que pode ser encaixado em uma variedade de sistemas para enviar mensagens/notificações. Sinta-se à vontade para compartilhar suas opiniões/inputs/comentários sobre o artigo.