Skip to content

Chat Systems 3.6.0

Choose a tag to compare

@github-actions github-actions released this 28 Oct 09:18
· 178 commits to main since this release
64ee5bc

Upgrading from 3.5.0

  • Pull both images and restart api, realtime, worker and frontend together; the API
    runs migrations 75–79 on start, which add the huddle_invites table,
    hooks.disabled_reason, a thread target on scheduled messages, one pending mention email
    per person and message, and slack_imports.heartbeat_at, so snapshot first. On its first
    start the worker moves every account photo into the object store's avatars/ prefix (see
    the RUNBOOK upgrade note); 3.5.0 cannot read photos there, so going back means restoring
    the snapshot.
  • Re-send pending email invites. An emailed invite link now names the invite it stands
    for, and links sent before the upgrade do not: they answer Invalid or expired invite.
    Revoke and re-send any email invite that has not been accepted yet. Shared invite links are
    unaffected.
  • For WebSocket clients: huddle.join needs only huddle_id; channel_id, workspace_id
    and dm_partner_id are ignored.
  • For API clients: GET /messages/{id}/thread takes limit and cursor instead of
    offset, returns the newest replies first, and includes reactions. A deleted message with
    replies is listed as a tombstone (deleted_at set, empty content).
  • For API clients: copy_attachments_from on POST /channels/{id}/messages is now
    forwarded_from; it also records metadata.forwarded_from.
  • For API clients: reading a channel no longer marks its threads' notifications read;
    POST /threads/{id}/read does. A push's badge_count is the total across workspaces, and a
    thread reply not sent to the channel no longer counts in the channel's unread counters.
  • For WebSocket clients: send { "type": "activity", "active": bool } when the person starts
    or stops using the app. Push is held back only while a session says it is active, so a
    client that never sends it gets push even with its socket open. A huddle.ring to somebody
    who paused the workspace is no longer delivered.
  • For API clients: POST /users/me/avatar takes a multipart file and sets the account photo.
    An account photo set with PATCH /users/me to a workspace file is no longer readable to the
    workspace.
  • For API clients: ImportRun carries retryable, and
    POST /workspaces/{ws_id}/slack-imports/{import_id}/retry queues a failed run again. An
    import report counts guests, users_suspended and channels_archived.
  • Building the frontend image yourself: pass --build-arg PREVIOUS_IMAGE=<the frontend image you run now> to keep its chunks for tabs opened before the upgrade, and
    --build-arg APP_VERSION=<version> to name the build. A proxy in front of the frontend
    should not cache index.html or version.json; nginx now sends no-cache for both.
  • For API clients: posting, reacting, scheduling and incoming webhooks answer 403 on an
    archived channel. POST /channels/{id}/unarchive undoes DELETE /channels/{id}, both
    publish channel.updated (is_archived), and Browse channels lists archived channels
    with is_archived.
  • For API clients: POST /workspaces/{id}/invites returns the invite with invite_url and
    email_sent, and GET /workspaces/{id}/invites/{invite_id}/link hands out a pending email
    invite's link again. An empty SMTP_HOST now means no email: invites say so instead of
    claiming they were sent.

Security

  • A private channel's huddle is its members'. Joining a huddle is checked against the
    huddle itself: its channel's members, the two people of a DM huddle, or someone invited
    from inside it. Active huddles lists only channels you are in, and only someone in a
    huddle can invite to it.
  • An email invite ends when the invite does. Revoking it, its expiry and its use limit now
    stop the emailed link too, and the role it grants is the one the invite has today.
  • A private channel's member list is its members'. GET /channels/{id}/members follows
    the same access as reading the channel.
  • A suspended or removed person stops acting. Suspending or erasing an account turns off
    every webhook, slash command and workflow that person set up, and removing someone from a
    workspace turns off theirs there; activating the account again does not turn them back on.
    Each scheduled message, workflow run and webhook also checks its author when it fires: a
    suspended author's scheduled message fails with author_inactive, and a webhook whose
    creator can no longer read its channel turns itself off and says why under Integrations.
  • A workflow whose builder left can be taken over. A workspace admin opens it under
    Workflows and chooses Take over; it becomes theirs, stays off until they turn it on, and
    the audit log records it.
  • A private Slack channel stays private. The Slack import merges a channel into an
    existing one of the same name only when both are the same kind; otherwise it imports it as
    <name>-slack and says so in the report.

Fixed

  • Opening a message lands on it. From Activity, a desktop notification, a phone push or
    search, a direct message opens its conversation, a thread reply opens its thread scrolled to
    it, and a public channel you have not joined opens on the message with Join channel. Old
    message links resolve the same way, and a message that is gone says so instead of opening
    #general. GET /messages/{id}/location says where a message lives; push payloads and the
    notification frame carry thread_parent_id.
  • Search goes past twenty. Show more pages through message and file results.
  • Threads keep up. A long thread reads back to its first reply with Show earlier
    replies
    . Deleting a reply takes it off the count, and an open thread shows other people's
    reactions, pins and deletions as they happen. A deleted parent with replies stays as This
    message was deleted
    , so its thread stays together; retention removes a thread once its last
    reply is past the period, and no reply ever appears in the channel on its own. Replies can
    be sent to the channel too with Also send to #channel, and scheduled from the thread
    composer.
  • Sending never loses work. A message or thread reply that fails to send keeps its text
    and files, survives a refresh of the list, and offers Retry (with the same files) or
    Discard (back into the composer). Files in the composer stay with their channel when you
    switch away, and a file that failed to upload says why and must be retried or removed
    before sending. A scheduled message that failed shows the reason with Send now and
    Remove. Forwarding a message no longer notifies the people or the @channel in the
    quote.
  • Unread, Activity and the badge agree. Reading a channel or DM clears its Activity rows,
    reading a thread clears the thread's, and a message or mention that arrives in the channel
    you are looking at is read at once instead of leaving a badge. A reply kept in its thread no
    longer marks the channel unread. A mention from another workspace no longer lands in the
    open one's sidebar, and the app icon always shows the total across workspaces, push
    included. A channel with unread messages opens on the first of them under the New line,
    also on a fresh load, with Jump to first unread while it is above the view; New
    messages
    sits over the list again instead of under it.
  • Notifications arrive once, where they should. Email me what I missed goes out for a
    mention or DM still unread five minutes later, whether or not a push was sent, never for one
    you have read, once however often the event is redelivered, and with a link to the message
    (or the workspace, for several). An open tab nobody is using no longer holds back push:
    push waits only while a window is in front and in use. A paused workspace does not ring for
    huddles, and the pause menu names the workspace it pauses. A webhook's creator is notified
    of what their hook posts, under the bot's name. Preferences → Notifications has the
    Desktop notifications while the app is open switch, and a desktop notification and a push
    about the same channel replace each other instead of showing twice.
  • Waking up reconnects, and a deploy no longer breaks an open tab. The socket reconnects
    as soon as the network comes back or the tab is shown again, instead of waiting out its
    backoff, and a socket left half-open by sleep is replaced within two seconds. Switching to
    a workspace you joined after connecting shows you online there at once. A gap too long to
    replay now also refreshes unread counts, pins and the sidebar. After a deploy, an open tab
    shows A new version is available with Reload, a lazy page or the emoji picker whose
    chunk is gone reloads once onto the new build, and release images keep the previous
    release's chunks.
  • An archived channel is closed. Nothing can be posted, reacted, scheduled or sent by a
    webhook into it; its composer becomes an Archived bar, and workspace admins and the
    channel's admins can Unarchive it there. Archiving and unarchiving post a line in the
    channel and reach everyone viewing it at once.
  • An export without DMs has no DM files. files.jsonl follows the same DM choice and date
    range as the messages.
  • A retention audit row counts its own workspace. Each workspace's Retention purge entry
    used to carry the totals of every workspace purged before it in the same run.
  • Joining a channel you were looking at goes live. After Join channel on a channel opened
    without being in it, new messages and changes arrived only after a reconnect.
  • Inviting works without email. Every invite shows its link to copy, and the form says
    when email is not set up instead of Invite sent. Workspace settings → Members lists
    pending invites with Copy invite link and Revoke.
  • SSO from an invite lands in the workspace. The invite page offers Continue with SSO,
    and the invite is used on the way back from the provider, activating the invited account.
  • Forgot password does the right thing. Somebody invited but not registered gets their
    invite again, an SSO account is told to sign in with SSO, and a too-short new password no
    longer uses up the reset link.
  • An account photo shows everywhere and stays. A photo set under Preferences → Account
    is the account's, not a file of the workspace that was open: every workspace you share with
    someone shows it, and file retention no longer deletes it. Replacing or removing a photo
    deletes the old one.
  • A status picked as Edit profile opens is kept. The form showed before the workspace
    profile had arrived, and its arrival then reset the emoji already picked.
  • A Slack import keeps what it found. Slack guests arrive as guests, people who had left
    Slack arrive as suspended accounts with their name still on their messages, and archived
    channels arrive archived. Reactions map through the full emoji set, skin tones included, and
    the workspace's custom emoji. An import that was running when the worker restarted is marked
    failed after five minutes, and Start again picks it up where it stopped.