Skip to main content
The social module is built around a set of interconnected entities that model a social network: users create and join communities, publish posts and stories, leave comments, add reactions, and follow each other. Content is organized through feeds, and media is managed via files.
Who is this for? This reference describes the core server data model. It’s essential for data import, analytics integration, and understanding API response structures.

Entity Reference

13 core entities with full field definitions, types, and relationship mappings

Relationship Patterns

Polymorphic join patterns, post composition, comment threading, and feed system

Enums & Import Tips

Comprehensive enum values and 10 practical data import guidelines

Conventions

Entity-Relationship Diagram

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

Entity Reference

A registered user within the network. Users can create content, join communities, follow others, and react to content.Relationships:
  • 1:N → Post (as postedUserId)
  • 1:N → Comment (as userId)
  • 1:N → Story (as creatorId)
  • 1:N → Poll (as userId)
  • M:N → Community (via CommunityUser join)
  • 1:N → Follow (as from or to)
A group or space where users gather, share posts, and interact. Every community has a backing channel (1:1) and can be associated with categories.
Direct DB queries: Several community fields (displayName, tags, metadata, avatarFileId, categoryIds, hasFlaggedComment, hasFlaggedPost, notificationMode) are actually stored on the backing Channel document, not on the Community document itself. The API serializer merges both into a single response.
Relationships:
  • 1:1 → Channel (every community has a backing channel)
  • M:N → CommunityCategory (via categoryIds[])
  • 1:N → CommunityUser (members)
  • 1:N → Post (via polymorphic targetId where targetType = "community")
  • 1:N → Story (via polymorphic targetId where targetType = "community")
  • 1:N → Feed (via polymorphic targetId where targetType = "community")
A label/tag that can be associated with communities. Communities reference categories via categoryIds[] (many-to-many).Relationships:
  • M:N → Community (referenced by community.categoryIds[])
The join entity between User and Community. Represents a user’s membership, roles, and status within a community.Relationships:
  • N:1 → User
  • N:1 → Community
  • Composite key: (userId, communityId)
The primary content unit. Posts can target a community or a user’s profile feed. Posts support a parent–child composition model where a single logical post (e.g., a gallery) is a parent with child posts for each attachment. See Post Composition Model.Relationships:
  • N:1 → User (creator via postedUserId)
  • N:1 → Community or User (via targetId + targetType)
  • 1:N → Post (children via parentPostId, self-referential)
  • 1:N → Comment (via comment.referenceId where referenceType = "post")
  • 1:N → Reaction (via reaction.referenceId where referenceType = "post")
  • N:1 → Feed (via feedId)
  • 0:1 → Poll (via data.pollId when created as poll post)
  • 0:N → File (attachments via child posts or data.fileId)
A comment attached to a Post or Story. Comments support two-level threading — see Comment Threading Model.Relationships:
  • N:1 → User (creator via userId)
  • N:1 → Post or Story (via referenceId + referenceType)
  • 1:N → Comment (replies via parentId, self-referential)
  • N:1 → Comment (root thread via rootId)
  • 1:N → Reaction (via reaction.referenceId where referenceType = "comment")
  • 0:N → File (via attachments[].fileId)
Tracks reactions (likes, love, etc.) on content. Each reaction is stored as its own document — one document per user-reaction-reference combination. Reactions use a polymorphic reference to support multiple content types.
Reaction names are freeform strings, not a fixed enum. The reactions field on Post/Comment/Story aggregates these as {reactionName: count}.Aggregated view: When querying reactions for a reference, the API returns an aggregated reactors[] array grouped by reference. Each entry contains reactionId, reactionName, userId, and createdAt.
Relationships:
  • N:1 → Post (when referenceType = "post")
  • N:1 → Comment (when referenceType = "comment")
  • N:1 → Story (when referenceType = "story")
  • N:1 → Message (when referenceType = "message")
  • N:1 → User (via userId)
A user-to-user follow relationship. Supports request-based following with status tracking.FollowCount (separate aggregation entity):Relationships:
  • N:1 → User (from — the follower)
  • N:1 → User (to — the followed)
A container that groups posts for a specific target (community or user). Each target can have up to three feed types that represent different stages of the post approval workflow.Relationships:
  • N:1 → Community (when targetType = "community")
  • N:1 → User (when targetType = "user")
  • 1:N → Post (posts reference feed via post.feedId)
A poll embedded within a post. Polls have a question with up to 10 answers and can be open or closed.Answer (nested object):UsersAnswered (vote tracking):Relationships:
  • N:1 → User (creator)
  • 1:1 → Post (poll is embedded via post.data.pollId)
A live video streaming session. Rooms support direct streaming (single host via RTMP/SRT) or co-host mode (multi-participant via WebRTC). Rooms are surfaced in the social feed via Posts with dataType = "room" and data.roomId. They have a lifecycle (idle → live → ended/recorded) and can optionally attach a live chat channel.Relationships:
  • N:1 → User (creator via createdBy)
  • N:1 → Community (via targetId where targetType = "community")
  • 1:1 → Post (room is embedded via post.data.roomId; room references back via referenceId)
  • 1:N → Room (children via parentRoomId, self-referential)
  • 0:1 → File (thumbnail via thumbnailFileId)
  • 0:1 → Channel (live chat via liveChannelId)
Ephemeral content with an expiration time. Stories can target a user’s profile or a community.StoryTarget (aggregated ring state):Relationships:
  • N:1 → User (creator via creatorId)
  • N:1 → Community (when targetType = "community")
  • N:1 → User (when targetType = "user")
  • 1:N → Comment (via comment.referenceId where referenceType = "story")
  • 1:N → Reaction (via reaction.referenceId where referenceType = "story")
  • 0:N → File (via data.fileId, data.thumbnailFileId)
An uploaded media file (image, video, audio, or generic file). Files are referenced by other entities via fileId.Relationships: Referenced by: Post (data.fileId, child post attachments), Comment (attachments[].fileId), Story (data.fileId), User (avatarFileId), Community (avatarFileId), CommunityCategory (avatarFileId), Poll answers (answers[].fileId).

Polymorphic Reference Patterns

Two polymorphic foreign key patterns are used throughout the data model. Understanding these is critical for correct data joins.
Critical for data integration: Misunderstanding these patterns is the most common source of join errors. Always check both the ID and its accompanying type field.
Used to associate content with its owner/container.How to join:

Post Composition Model (Parent–Child Posts)

Posts use a parent–child composition pattern to represent multi-attachment content (e.g., image galleries, mixed-media posts).
1

Top-level posts

A top-level post has parentPostId = null.
2

Child posts

A child post has parentPostId pointing to the parent’s postId.
3

Parent tracks children

The parent post holds children[] (array of child post IDs) and childrenNumber.
4

One attachment per child

Each child post holds a single attachment (one fileId or videoFileId per child).
5

Structure type derivation

The structureType field on the parent indicates the derived type: image, video, file, text, etc. if all children are the same type, or mixed if children have different data types.
6

Querying top-level posts

When querying posts, filter by parentPostId = null to get only top-level posts. Then load children[] to get attachments.

Comment Threading Model

Comments support two-level threading using parentId and rootId.
1

Top-level comments

Top-level comments have referenceId → Post/Story, parentId = null, rootId = null.
2

Replies

Replies set parentId to the direct parent comment and rootId to the thread root.
3

Shared root

All replies in a thread share the same rootId, regardless of nesting depth.
4

Children tracking

Parent comments track replies via children[] (array of child comment IDs) and childrenNumber.
5

Content reference

Comments reference their parent content (Post or Story) via referenceId + referenceType.

Feed System

Feeds organize posts for a specific target. Each community or user can have up to three feed types representing the post approval workflow:

Feed Endpoints

Community Feed

Posts published in a specific community. Filtered by targetType = "community".

User Feed

Posts published on a specific user’s profile. Filtered by targetType = "user".

Global Feed

Aggregated feed across communities and users. Configurable per network.

Following Feed

Posts from users the current user follows.

Post → Feed Mapping

  • Every post has a feedId pointing to the Feed it belongs to.
  • The Feed’s targetId + targetType tells you which community or user owns it.
  • To find all published posts in a community: find the Feed where targetId = communityId, targetType = "community", feedType = "published", then query posts by that feedId.

Key Enums Reference

Data Import Tips

Most entities expose three IDs (userId, userPublicId, userInternalId). For joining data across entities, use userId or the corresponding 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.
Always check targetType + targetId on posts:
  • targetType = "community" → the post belongs to a community; join on targetId = community.communityId.
  • targetType = "user" → the post is on a user’s profile feed; join on targetId = user.userId.
Reaction names (e.g., "like", "love", "wow") are freeform strings, not a fixed enum. When aggregating, group by reactionName. The reactions object on Post/Comment/Story already provides {name: count} aggregations.
A poll is created as part of a post. The post’s data object will contain a pollId during creation. To join: Post.data.pollId → Poll.pollId. Not all posts have polls — only those with structureType = "poll" or where data.pollId exists.
Stories have an expiresAt timestamp. To query only active stories, filter where expiresAt > NOW(). Expiry duration is configurable per network (1–1440 minutes). Expired stories remain in the database but are no longer shown in story rings.
Soft-deleted records have isDeleted: true. Exclude these by default for analytics unless you need deletion history. Posts also support permanent (hard) deletes — these records are removed entirely.
When querying posts via feeds, pay attention to feedType:
  • published → live, visible posts (this is what you want for most analytics).
  • reviewing → posts awaiting approval.
  • declined → rejected posts.
To avoid double-counting in analytics, filter by parentPostId = null when counting top-level posts. Child posts are attachments/media within a parent post, not standalone content.
To get only top-level comments (not replies), filter by parentId = null. To reconstruct full threads, group by rootId.
A user’s relationship with a community is captured in the CommunityUser join entity. Check communityMembership:
  • member → active member.
  • banned → banned from the community.
  • none → not a member.

API Overview

Server-to-server API capabilities, authentication methods, and getting started guide

Webhook Events

Real-time event notifications for content, user, and moderation events

SDK Social Overview

Client-side SDK implementation for social features, posts, communities, and more