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:
- Sorts both user IDs alphabetically.
- Generates an MD5 hash of the sorted IDs (dm_participant_hash) for deduplication.
- Checks for an existing thread with the same hash. If found, returns it.
- 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?