Comments
Threaded comments on entity records with one level of nesting, activity logging, and real-time updates.
Comments
The Comments module adds threaded discussion to any entity record. Comments support one level of reply nesting, display author information from user profiles, log activity on creation, and update in real time via the Realtime module.
Overview
Comments are scoped to a single entity and tenant. The module lives in features/comments/ and provides server actions for CRUD, React Query hooks for client-side state, and pre-built UI components for rendering threaded conversations. Comments appear on entity detail pages, typically in a dedicated section below the entity content.
Key Concepts
CommentRecord -- The core data type representing a comment:
id,tenant_id,entity_id-- identity and scopingparent_id-- null for top-level comments, set for replies (one level deep only)user_id,body,created_at-- content and metadataauthor-- joined fromprofilestable (display_name, email)replies-- child comments assembled during thread building
One-Level Threading -- Replies can only be added to top-level comments, not to other replies. The reply button is only shown on comments at depth 0. This keeps conversations readable without deep nesting.
Activity Logging -- Every new comment creates an activity record via logActivity() with action comment_added. The activity description is the comment body truncated to 100 characters.
Ownership Enforcement -- Users can only delete their own comments. The deleteComment action verifies user_id matches the current user before proceeding.
How It Works
Thread Building
The listComments() server action fetches all comments for an entity, then builds the threaded structure in memory:
- Fetch all comments ordered by
created_atascending - Join with
profilestable to get author display names - Build a lookup map by comment ID
- Iterate: if a comment has a
parent_idand that parent exists, push it into the parent'srepliesarray. Otherwise, add it to the top-level list.
This returns a flat list of top-level comments, each with a replies array.
Client-Side Data Management
Three React Query hooks manage comment state:
useComments(entityId)-- fetches threaded comments via/api/comments?entityId=...useCreateComment(entityId)-- mutation that POSTs to/api/commentsand invalidates the comment queryuseDeleteComment(entityId)-- mutation that DELETEs via/api/comments/\{id\}and invalidates
The commentsQueryKey(entityId) function returns ["comments", entityId], which aligns with the Realtime module's entity listeners for automatic cache invalidation when comments change remotely.
UI Components
CommentThread is the top-level component. It displays the full comment list with loading and empty states, plus a CommentInput at the bottom for new comments. Each comment is rendered by SingleComment, which shows the author avatar, name, timestamp, body, and action buttons (Reply for top-level, Delete for own comments).
CommentCount is a lightweight component that displays just the count, suitable for use in entity cards or list rows.
API Reference
Server Actions
| Function | Location | Purpose |
|---|---|---|
listComments(entityId) | features/comments/server/actions.ts | Fetch and thread all comments for an entity |
createComment(entityId, body, parentId?) | Same | Create a comment (with optional parent for replies) |
deleteComment(id) | Same | Delete own comment (ownership verified) |
getCommentCount(entityId) | Same | Count of comments on an entity |
Hooks
| Hook | Purpose |
|---|---|
useComments(entityId) | Fetch threaded comments |
useCreateComment(entityId) | Create comment mutation |
useDeleteComment(entityId) | Delete comment mutation |
commentsQueryKey(entityId) | Stable query key for cache sharing |
Components
| Component | Purpose |
|---|---|
CommentThread | Full threaded comment UI with input |
CommentInput | Text input for writing comments |
CommentCount | Comment count badge |
For Agents
Agents do not currently have a dedicated tool for posting comments. Comments are a human-to-human collaboration feature. However, agents can observe comment activity through the searchEntities tool (activity records include comment_added events) and the entity's activity timeline.
If comment functionality is needed for agents in the future, a postComment tool could be added to the entity tool group.
Related Modules
- Entity System (
features/entities/) -- comments are scoped to entities - Realtime (
features/realtime/) -- entity realtime listeners includecommentstable changes - Activity -- comment creation logs an activity record for the timeline
Realtime
Supabase Realtime subscriptions for live data updates, entity presence tracking, chat message delivery, and typing indicators.
Entity Graph
Interactive relationship graph visualization using @xyflow/react and D3 force-directed layout, with filtering, search, focus mode, and embeddable block support.