Skip to main content
The chat module provides real-time messaging through channels (group chats, direct conversations, broadcasts). Users join channels as channel users, exchange messages within message feeds (threads), and can attach media, reactions, and mentions. Channels are the top-level container. Each channel has one or more message feeds (threads), and each feed contains messages ordered by a monotonically increasing segment. Messages support threading via a self-referential parentId.
Who is this for? This reference describes the core chat server data model. It’s essential for data import, analytics integration, and understanding API response structures. For social entities (User, Community, Post, Comment, etc.), see the Social Data Model Reference.

Conventions

ConventionDescription
Triple-ID patternMost entities expose three IDs: a primary {entity}Id, a {entity}PublicId (stable external identifier), and a {entity}InternalId (database-level reference). For joins, prefer public IDs.
Soft deleteNearly every entity has an isDeleted boolean. Deleted records remain in the database with isDeleted: true. Filter these out unless you specifically need deletion history.
TimestampscreatedAt and updatedAt (ISO 8601 date-time) are present on all entities. Some also have editedAt.
MetadataA freeform metadata object is available on most entities for custom fields.
FlaggingflagCount (number of reports) and hashFlag (bloom-filter structure) track moderation state on messages. Channels bubble up flags via hasFlaggedMessage.

Entity-Relationship Diagram

The following diagram shows the core entities and their relationships in the chat module.

Entity Reference

A chat room, conversation, or group. Channels are the top-level container for messaging. Every community has a 1:1 backing channel. Channels can be standard (open), private, direct conversations, broadcast, community-backed, or live (attached to a room).
FieldTypeDescription
channelIdstringPrimary key. Public channel identifier.
channelInternalIdstringInternal database identifier.
channelPublicIdstringPublic identifier (same as channelId).
typeenumstandard | private | conversation | broadcast | community | live.
displayNamestringChannel display name.
isDistinctbooleanIf true, reuses existing channel for the same user set (conversations).
tagsstring[]Tags for filtering/categorization.
metadataobjectArbitrary custom fields.
avatarFileIdstringFK → File. Channel avatar image.
lastActivitydate-timeTimestamp of last activity (message, event, etc.).
memberCountinteger(Computed) Number of members.
messageCountinteger(Computed) Number of messages.
moderatorMemberCountintegerCount of moderator members.
isPublicbooleanWhether channel is publicly listed.
notificationModeenumdefault | silent | subscribe.
isMutedboolean(Computed) Whether the channel is currently muted (based on muteTimeout).
muteTimeoutdate-timeWhen the channel-level mute expires.
isRateLimitedboolean(Computed) Whether rate limiting is active (based on rateLimitTimeout).
rateLimitnumberMaximum messages per rate limit window.
rateLimitWindownumberRate limit window in milliseconds.
rateLimitTimeoutdate-timeWhen the current rate limit expires.
messageAutoDeleteEnabledbooleanWhether auto-delete by flag threshold is enabled.
autoDeleteMessageByFlagLimitnumberFlag count threshold for auto-deletion.
messagePreviewIdstring(Computed) ID of the latest message preview.
attachedToobjectLinked resources: {postId, videoStreamId, roomId}.
isDeletedbooleanSoft-delete flag.
createdAtdate-timeCreation timestamp.
updatedAtdate-timeLast update timestamp.
Relationships:
  • 1:1 → Community (community-type channels back a community; see Channel ↔ Community Relationship)
  • 1:N → ChannelUser (members)
  • 1:N → MessageFeed (message threads within the channel)
  • 0:1 → Room (live-type channels are attached to a room via attachedTo.roomId)
  • 0:1 → File (avatar via avatarFileId)
The join entity between User and Channel. Represents a user’s membership, roles, and read state within a channel.
FieldTypeDescription
userIdstringFK → User. User’s public ID.
userInternalIdstringUser’s internal ID.
userPublicIdstringUser’s public ID.
channelIdstringFK → Channel. Channel’s public ID.
channelInternalIdstringChannel’s internal ID.
channelPublicIdstringChannel’s public ID.
membershipenumnone | member | banned.
rolesstring[]Role public IDs assigned within this channel.
permissionsstring[]Resolved permissions from roles.
isBannedboolean(Computed) true when membership = "banned".
isMutedboolean(Computed) true when muteTimeout > now.
muteTimeoutdate-timeWhen the user-level mute expires in this channel.
readToSegmentnumberLast-read message segment (read cursor).
lastMentionedSegmentnumberSegment of last @mention for this user.
lastActivitydate-timeUser’s last activity in the channel.
createdAtdate-timeRecord creation timestamp.
updatedAtdate-timeLast update timestamp.
Relationships:
  • N:1 → User
  • N:1 → Channel
  • Composite key: (userId, channelId)
A message within a channel. Messages belong to a MessageFeed and support threading (replies). Each message is stored as its own document.
FieldTypeDescription
messageIdstringPrimary key. Internal message ID.
publicIdstringPublic-facing message ID.
channelIdstringFK → Channel. Channel this message belongs to.
channelPublicIdstringChannel’s public ID.
messageFeedIdstringFK → MessageFeed. The feed/thread containing this message.
parentIdstringFK → Message (self). Parent message ID for replies. null for top-level messages.
creatorIdstringFK → User. Creator’s internal ID.
creatorPublicIdstringCreator’s public ID.
dataTypeenumtext | image | video | file | audio | custom | json | imagemap.
dataobjectMessage payload. For media types, includes fileId and optionally thumbnailFileId.
segmentnumberOrdering position within the feed.
tagsstring[]Tags associated with this message.
metadataobjectArbitrary custom fields.
mentionedUsersarrayMentioned users: [{type: "user"|"channel", userIds: [...]}].
childCountintegerNumber of direct replies.
reactionsobjectMap of reactionName → count.
reactionCountintegerTotal reaction count.
myReactionsstring[]Current user’s reaction names.
flagCountintegerNumber of moderation reports.
hashFlagobject(Computed) Bloom-filter flag structure.
editedAtdate-timeLast content edit timestamp.
isDeletedbooleanSoft-delete flag.
createdAtdate-timeCreation timestamp.
updatedAtdate-timeLast update timestamp.
Threading model: See Message Threading Model below for details on how replies work.
Relationships:
  • N:1 → User (creator via creatorId)
  • N:1 → Channel (via channelId)
  • N:1 → MessageFeed (via messageFeedId)
  • 1:N → Message (replies via parentId, self-referential)
  • 1:N → Reaction (via reaction.referenceId where referenceType = "message")
  • 0:1 → File (attachment via data.fileId)
A message thread/feed within a channel. Each channel has one or more message feeds. The feed tracks the latest message and provides a message preview for UI display.
FieldTypeDescription
messageFeedIdstringPrimary key.
channelIdstringFK → Channel. The channel this feed belongs to.
channelPublicIdstringChannel’s public ID.
channelTypeenumChannel type: standard | private | conversation | broadcast | community | live.
namestringFeed display name.
creatorIdstringFK → User. Feed creator’s internal ID.
creatorPublicIdstringCreator’s public ID.
lastMessageIdstringFK → Message. Most recent message.
lastMessageTimestampdate-timeTimestamp of the most recent message.
messagePreviewIdstring(Computed) ID of the preview message.
childCountintegerNumber of messages in this feed.
isDeletedbooleanSoft-delete flag.
editedAtdate-timeLast metadata edit timestamp.
createdAtdate-timeCreation timestamp.
updatedAtdate-timeLast update timestamp.
Relationships:
  • N:1 → Channel (via channelId)
  • N:1 → User (creator via creatorId)
  • 1:N → Message (messages reference feed via messageFeedId)
Tracks reactions (likes, love, etc.) on messages. Each reaction is stored as its own document — one document per user-reaction-reference combination. Reactions use a polymorphic reference that supports multiple content types across both chat and social modules.
FieldTypeDescription
reactionIdstringPrimary key. Unique reaction instance ID.
reactionNamestringFreeform name, e.g., "like", "love", "wow".
userIdstringFK → User. Who reacted.
userInternalIdstringReactor’s internal ID.
referenceIdstringFK → Message (in chat context). The content being reacted to.
referenceTypeenumpost | comment | story | message. For chat, this is always message.
createdAtdate-timeWhen the reaction was added.
updatedAtdate-timeWhen the reaction was last updated.
Reaction names are freeform strings, not a fixed enum. The reactions field on Message aggregates these as {reactionName: count}. The same Reaction entity is shared across both social and chat modules — only the referenceType differs.
Relationships:
  • N:1 → Message (when referenceType = "message")
  • N:1 → User (via userId)
An uploaded media file (image, video, audio, or generic file). Files are referenced by messages and channels via fileId. The File entity is shared across both social and chat modules.
FieldTypeDescription
fileIdstringPrimary key. Cloud storage key.
fileUrlstringHTTP download URL.
typeenumimage | file | video | audio | clip.
accessTypeenumpublic (open download) | network (requires authentication).
altTextstringAlternative text (max 180 chars).
feedTypestringFeed type associated with this file.
statusenumuploaded | transcoding | transcoded | transcodeFailed. Processing status (mainly for video/audio).
isDeletedbooleanSoft-delete flag.
videoUrlobjectVideo URLs by resolution: {1080p, 720p, 480p, 360p, original}. Present for video files.
attributes.namestringOriginal file name.
attributes.extensionstringFile extension/format.
attributes.sizenumberFile size in bytes.
attributes.mimeTypestringMIME type.
attributes.metadataobject(Schemaless) Additional metadata. May contain width, height, exif, gps if set by the uploading client, but these sub-fields are not enforced by the schema.
createdAtdate-timeUpload timestamp.
updatedAtdate-timeLast update timestamp.
Relationships: Referenced by: Message (data.fileId, data.thumbnailFileId), Channel (avatarFileId).

Message Threading Model

Messages support single-level threading within a message feed:
1

Top-level messages

Top-level messages have parentId = null. They belong directly to the feed.
2

Replies

Replies have parentId set to the parent message’s ID.
3

Child tracking

childCount on each message tracks its direct reply count.
4

Segment ordering

Messages are ordered by segment within their feed (monotonically increasing). All messages (top-level and replies) live in the same feed and share the same segment counter.

Reconstructing Threads

  1. Query messages by messageFeedId.
  2. Top-level messages: parentId = null.
  3. Group replies by parentId.
  4. Order all messages by segment.

Channel ↔ Community Relationship

Every community in the social module has a 1:1 backing channel with type = "community". This relationship connects the social and chat modules:
Cross-module linking: The Community entity stores a channelId foreign key pointing to its backing channel. Community-type channels inherit the community’s membership — a user who is a community member is also a channel member. When importing data that spans both modules, ensure the Community’s channelId FK is correctly linked.

Key Enums Reference

EnumValuesUsed By
Channel.typestandard, private, conversation, broadcast, community, liveChannel .type
Channel.notificationModedefault, silent, subscribeChannel .notificationMode
ChannelUser.membershipnone, member, bannedChannelUser .membership
Message.dataTypetext, image, video, file, audio, custom, json, imagemapMessage .dataType
Reaction.referenceTypepost, comment, story, messageReaction .referenceType

Data Import Tips

Most entities expose three IDs (channelId, channelPublicId, channelInternalId). For joining data across entities, use the public ID — these are the values used in foreign key references. Internal IDs are database-level identifiers and may not appear in all API responses.
Every community has a 1:1 backing channel (with type = "community"). When importing both communities and channels, ensure corresponding records are linked. The community stores a channelId foreign key.
Messages within a feed are ordered by segment (a monotonically increasing integer). Preserve segment ordering during import to maintain correct message sequence. Each feed maintains its own independent segment counter.
The ChannelUser entity uses a composite key of (userId, channelId). When importing, deduplicate on both fields to avoid creating duplicate membership records.
Several fields are derived at read time and should not be imported as stored values:
  • Channel.isMuted — derived from muteTimeout > now.
  • Channel.isRateLimited — derived from rateLimitTimeout > now.
  • Channel.memberCount / messageCount — aggregated from related records.
  • ChannelUser.isBanned — derived from membership = "banned".
  • ChannelUser.isMuted — derived from muteTimeout > now.
  • Message.myReactions — derived per-request for the current user.
  • MessageFeed.messagePreviewId — derived from latest message.
Soft-deleted records have isDeleted: true. Exclude these by default for analytics unless you need deletion history.
Message reactions follow the same model as social reactions (see Social Data Model Reference). Each reaction is stored as a separate document with referenceType = "message" and referenceId pointing to the message. The reactions object on Message provides pre-aggregated {name: count} maps.
To get only top-level messages (not replies), filter by parentId = null. To reconstruct threads, group replies by parentId and order by segment. See Message Threading Model for the full pattern.