Discussion Hub — External Communication

Discussion Hub — External Communication

The Discussion Hub is the centralised interface for email-based external communication. Discussions allow your team to send messages to clients, freelancers, and external contacts directly from NexusRMS, with full email threading, delivery tracking, and internal-only notes.

What Are Discussions?

Discussions are CommunicationThread records with thread_type set to discussion. Unlike internal channels and DMs, discussion messages are delivered as emails to external recipients. Replies are threaded back into the same conversation using email Message-ID and In-Reply-To headers.

Discussion Types (13 Total)

Every discussion is assigned a discussion_type for categorisation and filtering:

  • Core types (6) — quote, invoice, document, freelancer, project, general
  • Project-specific types (7) — client, crew, equipment, logistics, venue, change, issue

Creating a Discussion

Discussions are created via CommunicationThread::createDiscussion() with the following parameters:

  • creatorId — The staff member's user ID (automatically assigned owner role)
  • subject — The email subject line for the thread
  • discussionType — One of the 13 types above (defaults to general)
  • contextType / contextId — Optional polymorphic link to a Quote, Invoice, Project, or Client record
  • initialMessage — Optional first message; if provided, message_count, last_activity_at, and last_message_preview are updated immediately

Participants

Discussion participants can be internal users, external email addresses, or freelancer node contacts. Key fields on CommunicationParticipant:

  • user_id — Internal user ID (null for external participants)
  • email — Email address for external participants
  • role — Participant role: owner, participant, cc, or bcc
  • freelancer_node_id — Links to a Freelancer Node for cross-database communication
  • is_external_freelancer — Boolean flag for freelancers from the Nodes system

Email Threading

Each discussion generates a unique email_thread_id in the format <[email protected]>. Outbound emails include a Message-ID header (stored in email_message_id) and replies reference it via In-Reply-To (stored in email_in_reply_to). This ensures Gmail, Outlook, and other clients group replies into the same conversation.

Internal vs External Messages

Each CommunicationMessage has an is_internal boolean flag:

  • is_internal = false — Visible to all participants; sent via email to external recipients
  • is_internal = true — Staff-only note; never included in outbound emails

Email Tracking (DiscussionEmailTracking)

Every outbound email creates a tracking record per recipient with the following lifecycle fields:

  • sent_at / delivered_at — Dispatch and server-confirmed delivery timestamps
  • opened_at / open_count — First open timestamp and total open count (tracked via a 1x1 transparent pixel per recipient, identified by tracking_pixel_id)
  • clicked_at / click_count — First link click timestamp and total click count
  • bounced_at / bounce_type / bounce_reason — Bounce timestamp with type: hard (permanent), soft (temporary), or complaint (spam report)

Recipient Types

  • client_contact (RECIPIENT_CLIENT_CONTACT) — A contact from your client CRM
  • freelancer (RECIPIENT_FREELANCER) — A freelancer connected via Nexus Nodes
  • external (RECIPIENT_EXTERNAL) — Any other external email address

API Routes

The Discussion Hub is powered by tenant API endpoints under /api/tenant/threads:

Method Endpoint Purpose
GET / POST /api/tenant/threads List all discussions (with filtering) or create a new one
GET /api/tenant/threads/{id} View a discussion with messages and participants
POST /api/tenant/threads/{id}/messages Add a message (internal or external)
POST /api/tenant/threads/{id}/send Send to external recipients via email
POST /api/tenant/threads/{id}/attachments Attach a document to the discussion
GET /api/tenant/threads/{id}/tracking Retrieve email tracking statistics
POST /api/tenant/threads/{id}/archive Archive the discussion
GET /api/tenant/threads/unread-count Total unread discussion count
GET /api/tenant/threads/category-counts Counts broken down by discussion type
GET /api/tenant/threads/by-context/{type}/{id} Discussions linked to a specific entity

Archiving and Status Management

Discussions follow the same three-status lifecycle as all communication threads: active (open for messages), archived (hidden from default view, accessible via filter), and closed (locked, no new messages). Use the archive endpoint to move completed discussions out of the active view. Archived discussions can be reopened at any time via the reopen() method.

Was this article helpful?