Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Aston2710/mc-modeler/llms.txt

Use this file to discover all available pages before exploring further.

MC Modeler’s commenting system lets collaborators discuss specific parts of a BPMN diagram without leaving the canvas. Comments are threaded, anchored to diagram elements, and sync in real time via Supabase Realtime. Every collaborator — editor or viewer — can read and write comments; only the thread owner or the diagram owner can delete a thread.

Starting a comment thread

There are two ways to start a new comment thread on the canvas:
  • Single element — Click the element to select it; the bpmn-js context pad appears. Click the comment bubble icon in the context pad (CommentContextPadModule). This dispatches a bpmn:comment:create custom event that opens the NewThreadComposer pre-populated with the element’s label as the anchor.
  • Multi-element selection — Select two or more elements. The SelectionCommentTrigger overlay appears above the selection; clicking it opens the NewThreadComposer with a selection anchor containing all selected element IDs.
Type your comment and press Ctrl+Enter (or click Comment) to create the thread. The thread is attached to the element(s) via an Anchor object that stores the element ID and label:
// anchor types
{ type: 'element'; elementId: string; elementLabel?: string }
{ type: 'selection'; elementIds: string[] }
Threads remain visible in the Comments panel even if the referenced element is later deleted — they are flagged as orphaned and shown with an Eliminated badge.

The Comments panel

The CommentsPanel component renders inside the right panel and supports three filter tabs:
TabShows
OpenThreads with status === 'open'
ResolvedThreads with status === 'resolved'
AllEvery thread regardless of status
Clicking a thread card scrolls the canvas to the anchored element and selects it. Clicking it again collapses the thread.

Replying to a thread

Expand any open thread to reveal the reply textarea. Submit with Ctrl+Enter. Threads can be resolved (removes it from the Open tab) or reopened at any time.

Deleting comments

  • The thread creator and the diagram owner can delete an entire thread.
  • Any user can delete their own replies.
A confirmation step (“Delete this thread? Yes / No”) prevents accidental deletion.

@mentions

Type @ anywhere in the comment or reply textarea to trigger the MentionTextarea autocomplete dropdown. The dropdown shows up to six collaborators filtered by the characters typed after @.
@alice       → filters to users whose name contains "alice"
↑ / ↓        → navigate the dropdown
Enter / Tab  → insert "@Alice " and close the dropdown
Escape       → close the dropdown without inserting
The mention list is populated by listCollaborators (diagram level) merged with listProjectCollaborators (project level), deduped by userId. When a comment containing @Username is saved, the mentions UUID array on the comment_replies row is populated with the user IDs. A PostgreSQL trigger (comment_replies_mentions) validates that each mentioned user actually has access to the diagram, then enqueues a comment_mention notification for each valid mention.
-- supabase/migrations/0011_mention_thread_deeplink.sql (simplified)
INSERT INTO notification_outbox (recipient_id, recipient_email, kind, payload)
SELECT p.id, p.email, 'comment_mention',
       jsonb_build_object(
         'diagramId',    d_id,
         'diagramName',  d_name,
         'threadId',     new.thread_id,   -- deep-link to exact thread
         'actorName',    new.author_name,
         'excerpt',      left(new.content, 300),
         'elementLabel', anchor_label
       )
FROM ...

Real-time comment sync

The SupabaseCommentBinding (instantiated by useComments) listens to Supabase Realtime postgres_changes events on the comment_threads and comment_replies tables. New threads and replies appear for all connected users without a page reload. In local-only mode (no Supabase), YjsCommentBinding stores comment state in the Yjs document alongside diagram data. When Supabase is configured, comments live exclusively in Supabase tables — they are not part of the Yjs document.
// src/hooks/useComments.ts — collaborative mode setup
export function useComments(modelerRef, activeVersion = 0) {
  useEffect(() => {
    if (!isSupabaseConfigured || !user || !activeTabId) return
    const binding = new SupabaseCommentBinding(diagramId)
    setCommentBinding(binding)
    void binding.start()
    // ...
  }, [activeTabId, user?.id, activeVersion])
}

Notifications

In-app notification bell

The NotificationBell component shows a badge with the count of unread notifications. Clicking it opens the notification panel which lists the 50 most recent notifications. Notifications are pushed in real time via a Supabase Realtime channel scoped to the user (notifications:{userId}). Three notification kinds are supported:
KindTriggered by
comment_mentionSomeone @mentioned you in a comment
invite_redeemed_diagramA collaborator accepted your diagram invite link
invite_redeemed_projectA collaborator accepted your project invite link
// src/store/notificationStore.ts
export type NotificationKind =
  | 'invite_redeemed_diagram'
  | 'invite_redeemed_project'
  | 'comment_mention'

Email notifications

In addition to in-app notifications, MC Modeler delivers email notifications via a webhook to a Google Apps Script web app. A PostgreSQL trigger fires on every insert into notification_outbox and makes an async POST (pg_net) to the webhook URL. Failed deliveries are retried by a time-based Apps Script trigger.

Notification preferences

Users control which notifications they receive from the Notification preferences panel (notifications.prefsTitle):
Preference keyUI labelControls
prefEmailEmails enabledMaster toggle for all email delivery
prefInvitesAccepted invitationsinvite_redeemed_diagram and invite_redeemed_project
prefMentionsComment mentionscomment_mention
Preferences are persisted in the notification_prefs table (upserted on change) and loaded at session start alongside the notification list.
// src/store/notificationStore.ts
setPref: (key: keyof NotificationPrefs, value: boolean) => {
  set((s) => ({ prefs: { ...s.prefs, [key]: value } }))
  // upserts to notification_prefs table async
}
Every comment_mention notification payload includes a threadId. Clicking the notification navigates to the diagram (via ?d=<diagramId>) and highlights the specific thread (via ?thread=<threadId>), scrolling the canvas to the anchored element and expanding the thread card automatically.
// notification payload (comment_mention)
{
  "diagramId":    "uuid",
  "diagramName":  "Order Fulfilment",
  "threadId":     "uuid",        // added in migration 0011
  "actorName":    "Alice",
  "excerpt":      "What about the error path here @Bob?",
  "elementLabel": "Validate Order"
}

Comment visibility by role

Actionownereditorviewer
Read threads
Create threads
Reply to threads
Resolve / reopen
Delete own reply
Delete any thread

Build docs developers (and LLMs) love