Channels & Direct Messages

Channels & Direct Messages

Channels and direct messages form the internal messaging backbone of NexusRMS. Channels serve team-wide communication, while direct messages provide private one-to-one or small-group conversations. All are stored as CommunicationThread records with different thread_type values.

Channel Types

Type Constant Visibility Who Can Post
Public CHANNEL_PUBLIC Anyone can view and join All members
Private CHANNEL_PRIVATE Invite-only; hidden from non-members Invited members only
Announcement CHANNEL_ANNOUNCEMENT Anyone can view and join Owners and admins only (read-only for members)

Creating a Channel

Channels are created using the CommunicationThread::createChannel() factory method with the following parameters:

  • creatorId — The user ID of the person creating the channel (automatically assigned the owner role)
  • name — Channel name without the # prefix (the system prepends it automatically)
  • channelType — One of: public, private, or announcement (defaults to public)
  • isDefault — When true, new users joining the tenant are automatically added to this channel
  • description — Optional text describing the channel's purpose
  • icon — Optional Material Design icon name (e.g. mdi-bullhorn, mdi-calendar-check)

Default Channels

Three default channels are automatically created for every new tenant via CommunicationThread::createDefaultChannels():

Channel Icon Description
#general mdi-bullhorn Company-wide announcements and discussions
#projects mdi-calendar-check Project-related discussions
#warehouse mdi-warehouse Warehouse team discussions

All default channels are public and have is_default_channel set to true, meaning new users are added automatically upon joining the tenant.

Channel Roles

Each participant in a channel has a channel_role stored in the CommunicationParticipant record:

  • owner (CHANNEL_ROLE_OWNER) — Full control: manage settings, manage members, pin messages, delete the channel
  • admin (CHANNEL_ROLE_ADMIN) — Manage members, pin messages, moderate content
  • member (CHANNEL_ROLE_MEMBER) — Read and post messages (unless the channel is announcement-type)

Owners and admins are collectively referred to as moderators and can be queried using the scopeModerators() scope.

Direct Messages (1:1)

Direct messages use the dm thread type. They are created via CommunicationThread::findOrCreateDM() which:

  1. Sorts both user IDs alphabetically.
  2. Generates an MD5 hash of the sorted IDs (dm_participant_hash) for deduplication.
  3. Checks for an existing thread with the same hash. If found, returns it.
  4. If no existing thread is found, creates a new DM thread and adds both users as participants.

This ensures that two users always share exactly one DM thread, regardless of who initiated the conversation.

Group Direct Messages (3+ Participants)

Group DMs use the group_dm thread type. They are created via CommunicationThread::createGroupDM() with:

  • creatorId — The user who initiates the group (assigned the owner role)
  • userIds — Array of all participant user IDs (creator is included automatically if omitted)
  • name — Optional custom name for the group (defaults to "Group Chat")

Like 1:1 DMs, group DMs use an MD5 participant hash for deduplication. The same set of participants always maps to the same thread.

Thread Statuses

Status Method Meaning
active reopen() Thread is open and accepting new messages
archived archive() Thread is hidden from the main view but preserved for reference
closed close() Thread is locked and no longer accepts new messages

Participant Management

  • Adding — Use addParticipant(userId, email, role) with role values: owner, participant, cc, or bcc
  • Removing — Use removeParticipant(participantId) to remove a specific participant record
  • Checking — Use hasParticipant(userId) to verify whether a user is part of a thread

Notification Levels, Muting, and Pinning

Each participant can set their own notification_level for a thread: all (every message), mentions (only when @mentioned), or none (silent). Toggle muting with mute() and unmute() on CommunicationParticipant — muted participants receive no notifications regardless of level. The is_pinned flag on CommunicationThread keeps important threads at the top of the list.

Activity Tracking

The system automatically tracks message_count and last_activity_at on each thread via the updateActivity() method whenever a message is created, updated, or deleted. The last_message_preview field stores a truncated plain-text preview (100 characters) of the most recent message.

Was this article helpful?