Skip to Content
Community and lifestyle

Source document · API/docs/COMMUNITY_AND_LIFESTYLE.md

Community and lifestyle features

The community and lifestyle APIs are authenticated product features backed by PostgreSQL. They share user identity, but they have separate records and policy: a Moment is community content; a dating profile is opt-in discovery data; a meeting is a scheduled/active room whose audio/video is provided by LiveKit.

Moments and the community feed

EndpointBehavior
GET /api/v1/community/feedReturns up to 50 recent Moments visible to the caller. Public posts are visible; a caller can also see their own non-public posts. Posts from accounts the caller has blocked are omitted.
POST /api/v1/community/momentsCreates a Moment for the token owner. Body text can be empty if media is present; text is limited to 2,000 characters; up to five distinct media IDs may be attached. Visibility defaults to public.
POST /api/v1/community/moments/{id}/likeRecords a like for the caller. Database uniqueness makes duplicate likes idempotent.
POST /api/v1/community/moments/{id}/viewRecords a view once per content/user key and returns updated counts.
GET /api/v1/community/moments/{id}/countersReturns current like, view, and comment counts calculated by the server.
POST /api/v1/community/moments/{id}/commentsAdds a comment as the caller. The body must be non-empty and at most 2,000 characters.
GET /api/v1/community/moments/{id}/comments?limit=Returns up to 50 comments by default; explicit limits must be between 1 and 100.
POST /api/v1/community/moments/{id}/reportCreates a moderation report with a non-empty reason. It does not hide or remove the content immediately.
POST /api/v1/community/users/{id}/blockAdds a one-way block from the current user to the target user; self-block is rejected.
DELETE /api/v1/community/users/{id}/blockRemoves that caller-owned block.

Moment creation and media association are transactional. For each asset ID, the server requires the asset to belong to the author and have purpose moment; it then associates it with the Moment and makes it publicly readable. The client cannot attach an arbitrary user’s asset. The feed currently uses chronological order; no ranking, recommendation, or cursor pagination is implemented on this route.

Blocking is directional: the feed query excludes authors that the current viewer has blocked. This is not a claim that the database automatically removes both users from each other’s experience. Report review is a separate admin workflow under /api/v1/admin/community/reports and the moderation endpoints.

Dating profile opt-in and browse

PUT /api/v1/dating/profile upserts the authenticated user’s profile fields: bio, opted_in, and visible. The user ID is always derived from the bearer token. Browsing through GET /api/v1/dating/browse excludes the caller and returns only profiles with both opted_in=true and visible=true, ordered by most recently updated, capped at 20 by the HTTP handler.

This is intentionally an opt-in feature: creating a profile with opt-in or visibility false does not make it discoverable. The current browse route has no query filters, cursor, matching score, or user-block filter. Clients should avoid promising discovery/matching behavior that the API does not implement.

Curated content

GET /api/v1/curated-content returns up to 20 published entries ordered by configured sort order and recent creation time. It is public in the current router. The API returns metadata and any external URL; the external media/content itself is not proxied or hosted by this route. Unpublished entries are filtered by the PostgreSQL repository.

Meetings and LiveKit

EndpointBehavior
POST /api/v1/meetingsCreates a meeting hosted by the token owner in scheduled state, with title and optional scheduled_at.
GET /api/v1/meetingsLists up to 20 meetings other than cancelled ones, with scheduled meetings ordered before unscheduled records.
POST /api/v1/meetings/{id}/joinRecords/reopens the caller’s participant membership and returns the LiveKit URL plus short-lived participant token. The first join moves a scheduled meeting to active.
POST /api/v1/meetings/{id}/leaveMarks the caller’s active participant membership as left.
POST /api/v1/meetings/{id}/endEnds the meeting only when the caller is its host. Repeating an already completed end can return the ended meeting.

Meeting metadata and participant membership live in PostgreSQL. The LiveKit adapter returns a deterministic room name based on the meeting ID and signs a participant token scoped to that room. The default token lifetime is 20 minutes (the adapter bounds configured values to at most one hour). The app connects to LiveKit directly for media; the Go API does not proxy video or audio bytes.

Joining requires all three LiveKit variables: LIVEKIT_URL beginning with wss://, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET. Production configuration validation requires them. If the provider is unavailable or not configured, join returns a service-unavailable response; meeting metadata may still exist. A token grants room join, publish, subscribe, and data publishing until its expiry, so never log or persist it as a durable credential.

Moderation boundaries

POST /api/v1/admin/community/reports/{id}/moderate requires an administrator bearer token and a non-empty status string. Community reports are user-submitted records; only an admin can update their moderation status. Report status history and case-management workflow are not currently exposed as a separate state machine. See administration and reporting for the remaining admin operations.