Skip to main content

Circles

Overview

Circles are private, small-group spaces within CommonPlace that allow users to share content with a specific subset of their friends. Unlike public posting, circle posts are only visible to members of the selected circle(s). This feature supports the platform's emphasis on human-scale social contexts by enabling more intimate sharing without broadcasting to everyone.

There are two types of circles: static circles where members are explicitly invited, and dynamic circles where membership is determined by view rules (such as relationship types). Circles support full lifecycle management including creation, member invitation, role management (admin/member), and deletion. Each circle maintains its own feed pacing state so users can catch up on a per-circle basis.

Circles integrate deeply with the post system through audience controls. When creating a post, users can select "Circles" as the audience and choose one or more circles to share with. The feed supports filtering by individual circles, and new post counts per circle are displayed in the filter dropdown.

Relevant Invariants

  • Invariant #7: "Human-Scale Social Contexts" -- Circles are intentionally small groups of mutual friends, not broadcast channels.
  • Invariant #14: "Privacy Is Infrastructure" -- Circle posts are only visible to circle members through RLS policies.
  • Invariant #19: "Complexity Must Be Earned" -- Circle creation is rate-limited, and new accounts face additional restrictions.

User Experience

User Flow

  1. Creating a circle: Navigate to the Circles page and click "Create Circle". Provide a name and optional description. For dynamic circles, define view rules instead of inviting members.
  2. Inviting friends: Within a circle, use the invite modal to select friends to invite. Blocked users are automatically excluded from the available friends list.
  3. Accepting an invite: Invited users see pending invitations and can accept or decline.
  4. Posting to a circle: When composing a post, select "Circles" as the audience and choose target circles.
  5. Viewing circle posts: Filter the main feed by a specific circle, or visit the circle's detail page.
  6. Managing members: Admins can invite, remove, promote/demote members, and update circle details.
  7. Leaving or deleting: Members can leave; admins can delete the circle.

Technical Implementation

Key Files

FilePurpose
src/hooks/useCircles.jsMain hooks: useCircles (list all), useCircle (single circle management), useAvailableFriends (invite candidates), useCirclePosts (circle feed)
src/hooks/useCircleFeedState.jsPer-circle feed pacing: useCircleFeedState, useCircleNewPostCount, useMarkCircleChecked, useAllCirclesNewPostCounts
src/components/circles/CreateCircleModal.jsxModal for creating a new static circle
src/components/circles/CreateDynamicCircleModal.jsxModal for creating a dynamic circle with view rules
src/components/circles/CreateCircleChooser.jsxChooser between static and dynamic circle creation
src/components/circles/InviteFriendModal.jsxModal for inviting friends to a circle
src/components/circles/CharterEditor.jsxEditor for circle charters (guidelines)
src/components/circles/CharterDisplay.jsxDisplay component for circle charters

useCircles() Hook

Fetches all circles the current user belongs to, separating them into active memberships and pending invites. For each circle, it fetches the member count.

Returns:

  • myCircles -- Active circle memberships with member count, user role, and circle details
  • pendingInvites -- Circles the user has been invited to but not yet accepted
  • createCircle(name, description) -- Creates a static circle via the create_circle RPC function (SECURITY DEFINER). Rate-limited.
  • createDynamicCircle(name, description, rules) -- Creates a dynamic circle with view rules
  • acceptInvite(circleId) / declineInvite(circleId) -- Handle invitations

useCircle(circleId) Hook

Manages a single circle with full CRUD operations.

Returns:

  • circle, members, pendingInvites, viewRules, userMembership
  • Derived: isAdmin, isMember, isInvited, isDynamic, memberCount, isOnlyAdmin
  • Actions: updateCircle, inviteFriend, cancelInvite, removeMember, updateMemberRole, leaveCircle, deleteCircle, updateViewRules

useAvailableFriends(circleId) Hook

Fetches friends who can be invited to a circle. Excludes users who are already members/invited and users who are blocked in either direction.

useCirclePosts(circleId) Hook

Fetches posts shared to a specific circle with pagination (20 per page). Uses an RPC function get_circle_posts_excluding_blocked to filter out posts from blocked users, with a fallback to a direct query if the RPC function is not available.

Database Tables

TablePurpose
circlesCircle definitions: name, description, circle_type (static/dynamic), created_by
circle_membersMembership records: circle_id, user_id, role (admin/member), status (member/invited), invited_by, responded_at
circle_view_rulesView rules for dynamic circles: rule_type, rule_values, mutual_only
post_circlesAssociates posts with circles (many-to-many)
circle_feed_statePer-user, per-circle feed pacing state
circle_sharesRecords of posts shared to circles (for the share-to-circle feature)

Rate Limiting

Circle creation uses tier-aware rate limiting via useTierAwareRateLimit. New accounts face additional restrictions and cannot create circles until their account matures. Circle invitations are also rate-limited.

Edge Cases

ScenarioBehavior
New account tries to create circleBlocked with isNewAccountRestriction flag and descriptive error message
Last admin tries to leaveisOnlyAdmin flag is set; UI should warn before allowing
Blocked user in available friendsAutomatically excluded by useAvailableFriends which checks blocks in both directions
Circle deletedAll associated circle_members and post_circles records are cascade deleted
Post shared to multiple circlesMultiple post_circles records are created; post appears in each circle's feed
Dynamic circle with view rulesMembership is determined by rules rather than explicit invites; rules can be updated by admin
  • Feed -- Feed supports per-circle filtering and shows new post counts per circle
  • Friends -- Only friends can be invited to circles
  • Posts -- Posts can target circles as their audience

Last updated: 2026-02-07