You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
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.