Messaging Features

Messaging Features

Every message in NexusRMS is stored as a CommunicationMessage record. Messages support rich text, @mentions, emoji reactions, read receipts, editing history, and multi-channel delivery tracking.

CommunicationMessage Model

The core fields on every message record:

Field Description
thread_idParent communication thread UUID
sender_idInternal user UUID (null for external senders)
sender_nameDisplay name of the sender
sender_emailEmail address of the sender
message_bodyMessage content in Markdown format
message_htmlRendered HTML version of the message
is_internalBoolean — true for staff-only internal notes
is_external_replyBoolean — true if this message arrived via email reply
sent_viaDelivery channel: web, email, api, or mobile

@Mentions

Type @username in any message to mention a colleague. The system handles mentions as follows:

  1. The extractMentions() method parses the message body using the regex pattern /@(\w+)/ to find all @username references.
  2. Matched usernames are looked up in the User model and their UUIDs are stored in the mentions JSON array on the message.
  3. Call getMentionedUsers() to retrieve the full User collection for all mentioned users.
  4. Notifications are automatically sent to each mentioned user.

Use the mentionsUser(userId) query scope to find all messages that mention a specific user.

Emoji Reactions

The CommunicationReaction model supports 12 emoji reactions: thumbsup, heart, joy, tada, open_mouth, cry, fire, check, x, star, hundred, and rocket. Reaction features include:

  • groupByEmoji() — groups all reactions on a message by emoji, returning each emoji with its count and the list of users who reacted.
  • userHasReacted(messageId, userId, emoji) — checks whether a specific user has already reacted with a given emoji.
  • Toggle behaviour — clicking a reaction you have already added removes it; clicking a new one adds it.
  • Auto-populated fields — the emoji_name and reacted_by_name are automatically set during creation.

Read Receipts

The CommunicationReadReceipt model provides detailed read tracking:

  • first_read_at — timestamp of the initial read event.
  • last_read_at — timestamp of the most recent read event.
  • read_count — total number of times the message was viewed.
  • read_via — channel used: web, mobile, or email.
  • user_agent and ip_address — captured for audit purposes.

Key methods:

  • markAsReadBy(userId) — records a read event on the message's read_by JSON array.
  • isReadBy(userId) — checks whether a specific user has read the message.
  • getReadPercentage(messageId, totalParticipants) — returns the percentage of participants who have read the message.
  • allRead(messageId, totalParticipants) — returns true when every participant has read the message.

Message Editing

Messages can be edited after sending. The editing process:

  1. The edit(newMessageBody, editedBy) method is called with the new Markdown content.
  2. The original message is preserved in original_message_body.
  3. The edited_at timestamp and edited_by user UUID are recorded.
  4. The message_html field is re-rendered from the updated Markdown.
  5. The isEdited() method returns true for any previously edited message.

Message Preview

The getPreview(length) method strips HTML tags and style blocks from message_html, then truncates to the specified character count (default 100). This is used in thread list cards to show the last message preview.

Auto-Tracking on Message Creation

When a new CommunicationMessage is created, the model's boot event listener automatically:

  • Calls thread->updateActivity() to refresh last_activity_at and message_count.
  • Increments the unread_count for all thread participants except the sender.
  • For external senders (no sender_id), all internal participants receive the unread increment.

Typing Indicators and Query Scopes

Typing indicators can be toggled via the typing_indicators_enabled setting. When enabled, other participants see a real-time indicator while someone composes a message. Available query scopes: internal() for staff-only messages, external() for client-visible messages, edited() for messages with edit history, and mentionsUser(userId) for messages mentioning a specific user.

Was this article helpful?