Orkestia
Blog
Chat

Members and moderation

Invite people into a chat space, set roles and display names, and moderate with suspend, timeout, ban, remove, key rotation and reconcile

The platform decides who belongs to a chat space. The relay only enforces it: a key that is not on the roster cannot connect. Every change on this page goes through a workflow, and the console's Chat → Members section (Membros) is a front end for the same workflows.

Who becomes a member

PrincipalJoins whenLeaves when
End user of the appThey open the chat for the first time while their account is active and seatedTheir account is disabled or deleted, or they lose their seat, and reconcile runs. Or an admin removes or suspends them
Staff actorYou attach it with buzz.actor.attach (see Actors in chat)You detach it, or its end-user seat stops being eligible and reconcile runs

People are admitted lazily. An end user with a seat does not appear on the relay until they open the chat, so unused seats cost nothing on the relay.

Invite people

A person needs an account in the identity app before they can open its chat. The console's Invite tab (Convidar) takes a list of emails and, for each one, runs two workflows:

  1. identity.end-user.create with identity_app_uuid and email, skipped when the person already exists in the app;
  2. identity.end-user.invite with identity_app_uuid and end_user_uuid (or email), which mails them their access to the app.

When they sign in and open the chat page, they are admitted. From the API:

start_workflow("identity.end-user.create", {"identity_app_uuid": "<app>", "email": "person@example.com"})
start_workflow("identity.end-user.invite", {"identity_app_uuid": "<app>", "end_user_uuid": "<from create>"})

Seats still apply. If the app has no free end-user seat, the person cannot sign in until you add seats. See Billing and seats.

Look at the roster

data.buzz.member.list (org members, read-only) lists every member of a space with:

FieldMeaning
statusactive, suspended or removed
relay_statein_sync, pending_add, pending_role, pending_remove, removed or error
moderationThe ban or timeout in effect (kind, until, reason), or null
last_seen_atWhen the person last opened the chat
status_reason_codeWhy a member left, for example end_user_not_seated, end_user_disabled, removed, admin_reason
relay_error_codeA stable code when the last relay change failed, for example relay_unreachable

data.buzz.member.directory is the view the chat page itself uses: active people and actors with display names and roles, and for actors how to reach them. It returns no platform ids and no emails. End users can call it only for their own app's space, and only after they have opened the chat.

Roles

buzz.member.set-role with space_uuid, member_uuid and role (admin or member) promotes or demotes a member on the relay. A relay admin can manage channels on the relay. Channel roles (owner, admin, member, guest) are set per channel; see Channels.

Display names

Other members see a person's display name. It is resolved on the server and is never derived from an email address:

  1. a name the person chose, or an admin set;
  2. otherwise a name from their profile, when one exists;
  3. otherwise a neutral fallback such as Member 1a2b (in the space's locale).

A name is 1 to 64 characters, has no control characters and no @, and is not the person's email local-part.

WhoHow
The person"Your name in the chat" on the chat page, which runs buzz.member.set-display-name with display_name
An organization adminbuzz.member.admin-set-display-name with space_uuid, member_uuid, display_name. The stored name wins until the person renames themselves
An actorIts name is set when you attach it, not with these workflows

Moderation

All of these are signed with the space's owner key on the relay, refuse agents, and (except suspend, remove, role and rotate) are for organization admins.

WantWorkflowInputsEffect
Silence someone for a whilebuzz.member.timeoutspace_uuid, member_uuid, duration_seconds (60 to 2,592,000), reasonThey stay connected but cannot post until it ends. Sessions are kept
End a timeout earlybuzz.member.clear-timeoutspace_uuid, member_uuid, reasonLifts it. Nothing to lift is not an error
Keep someone outbuzz.member.banspace_uuid, member_uuid, duration_seconds (60 to 31,536,000, omit for permanent), reasonThey cannot connect. Their chat sessions are revoked
Let them backbuzz.member.unbanspace_uuid, member_uuid, reasonLifts the ban. Revoked sessions stay revoked; they open the chat again
Remove one messagebuzz.message.moderate-deletespace_uuid, channel_id, event_id, public_reasonEvery chat client stops showing it. The optional reason is shown to the channel

Bans and timeouts show up in data.buzz.member.list under moderation.

Removing someone

WantWorkflowEffect
Suspend, keep the recordbuzz.member.set-status with status: "suspended" (and "active" to reinstate)Off the relay at once. The member row stays
Removebuzz.member.remove with space_uuid, member_uuid, reasonOff the space and the relay. Past messages stay attributed to them
Suspected key leakbuzz.member.rotate-key with space_uuid, member_uuidA new key is admitted, the old one removed, sessions revoked. Old messages stay under the old key
Sign-out everywhereThe person signs out on the chat page (buzz.session.revoke)Revokes the session records only. A key already in a browser keeps working until one of the rows above runs

Disabling an end user in the identity app, or taking away their seat, does not remove them from the relay on the spot. It happens the next time the space is reconciled.

Maintenance

The console's Maintenance tab (Manutenção) holds the repair workflows.

WorkflowUse
buzz.member.reconcile with space_uuid, dry_run, prune_unknownSuspends members whose seat, account or actor binding lapsed, then brings the relay roster in line with the platform. Safe to repeat. Run with dry_run: true first. prune_unknown (default false) also removes relay members the platform does not know, which matters only for a relay you adopted

The console's Activity tab (Atividade) shows the actor ledger, covered in Actors in chat.

Ask your AI assistant

prompts
Invite ana@example.com and bruno@example.com to my identity app "<app name>" so they can use its chat. Show me the identity.end-user.create and identity.end-user.invite calls before starting them.

List the members of my chat space who are suspended, banned or timed out, with the reason code for each.

Time out the member named "<name>" in my chat space for one hour with the reason "spam". Find their member_uuid with data.buzz.member.list and confirm with me first.

Run buzz.member.reconcile on my chat space as a dry run and explain what it would change.

For AI agents

RuleDetail
Find the memberdata.buzz.member.list returns member_uuid and display_name. Never guess a uuid from a name
Human callersEvery buzz.member.* change except the end user's own set-display-name and set-notifications refuses agents. Prepare the call for a person
Confirm firstBan, timeout, remove, rotate-key and moderate-delete affect a real person. Say what will happen and wait
Honest revocationDo not tell a user that signing out removed access. Removal is buzz.member.remove or buzz.member.set-status
Dry runbuzz.member.reconcile with dry_run: true before a real run