Skip to main content

Like Groups API

StatusImplementation
✅ Shippedsrc/feats/groups/

A like group is how users apply to attend an event. The group is formed by one user (the creator) plus optional friends. Once enough event authors approve the group, the group is approved and a private chat is created for the participants.

See also: Approval algorithm, Like-groups model.

All endpoints require Authorization: Bearer <supabase-access-token>.

Endpoints

MethodPathDescription
GET/groupsList my groups (as creator or member)
GET/groups/:idGet a group
POST/groups/:id/membersAdd a friend to the group
DELETE/groups/:id/members/:userIdRemove a member
GET/groups/:id/approvalsList approvals for the group
POST/groups/:id/approveApprove the group (event author only)
POST/groups/:id/rejectReject the group (event author only)

Group creation happens via POST /events/:id/like.

Get group

GET /groups/:id
Authorization: Bearer <token>
{
"id": "uuid",
"eventId": "uuid",
"creatorId": "uuid",
"status": "pending",
"memberIds": ["uuid", "uuid"],
"createdAt": "2026-04-01T00:00:00Z"
}

Visibility: members of the group, the event creator, and event authors.

Manage members

POST /groups/:id/members
{ "userId": "friend-uuid" }

Rules:

  • Caller must be the group creator.
  • The user being added must be a friend of the group creator.
  • The user must not already be in another pending group for the same event.
  • Group is in pending (cannot mutate after approved / rejected).
LimitValue
Members per group10 (including creator)
DELETE /groups/:id/members/:userId

Removing members before approval recalculates the approval threshold; existing approvals still count. See Approval algorithm → edge cases.

Approvals

GET /groups/:id/approvals
{
"data": [
{
"id": "uuid",
"groupId": "uuid",
"authorId": "uuid",
"decision": "consent",
"createdAt": "2026-04-01T00:00:00Z"
}
]
}

The decision field is either consent (approve) or refuse (reject).

POST /groups/:id/approve
POST /groups/:id/reject

Authorization: caller must be a current author of the group's event. Each author can only vote once per group.

Approve — consensus algorithm

The threshold formula:

effectiveT = min(consentThreshold, eligible_organizers)

Where eligible_organizers = event authors who haven't refused yet.

Status transitions:

  • approved: consents >= effectiveT
  • rejected: eligible - refuses < effectiveT (threshold can no longer be reached)
  • pending: otherwise

When approved:

  1. Group status → approved.
  2. A chat of type approved_group is created with all members + all authors as participants.
  3. Response includes the new chatId.
{
"id": "group-uuid",
"status": "approved",
"approved": true,
"chatId": "new-chat-uuid"
}

Reject

When a single author refuses and the threshold becomes unreachable, status → rejected. No chat is created.

Errors

StatusReason
400Group not in pending state
403Caller is not group creator / event author / member
404Group not found
409Member already in another pending group for this event

Constants

ConstantValue
MAX_MEMBERS10 (including creator)
EXPIRATION_HOURS24
DEFAULT_PAGE_SIZE20
MAX_PAGE_SIZE100

Implementation notes

Source: src/feats/groups/.

  • The consensus algorithm uses min(consentThreshold, eligible_organizers); see Approval algorithm for the rationale.
  • memberKey is a canonical sorted string of member IDs, ensuring unique pending group compositions per event via a partial unique index.
  • Group lifecycle and chat creation are wrapped in a single Drizzle transaction so partial state cannot escape.
  • Approval decisions are recorded in an append-only like_group_audit table.