Files
twenty/packages/twenty-apps
Abdul Rahman 0bf4b53af3 feat(slack): cache the Slack bot user id at connect time (#23726)
## What

Caches the Slack bot user id in workspace kv so the channel welcome
stops calling `auth.test` on every channel-join event.

## Why

Slack fires `member_joined_channel` for **every** person joining **any**
channel the bot sits in, not just for the bot itself. The welcome path
had to answer "was that our bot?", and did it by resolving the Slack
connection and calling `auth.test` — a connection lookup plus an
external API call, on every event, to conclude "no, that was a human, do
nothing".

The bot user id never changes for a given connection, so asking Slack
repeatedly is the wrong shape.

## How

`registerSlackConnection` already calls `auth.test` in the `onConnect`
hook and had `user_id` in hand, so it now writes it to workspace kv.
`resolveSlackBotUserId` reads it, falling back to `auth.test` (and
backfilling) for connections created before this change.

Reconnecting is the only thing that can change the bot user id, and
reconnecting re-runs that hook — so the cache is self-correcting and
needs no TTL.

Because resolving the id no longer needs a Slack client, the bot check
moved ahead of the connection lookup:

| per join event | before | after |
|---|---|---|
| Twenty round trips | 1 | 1 |
| Slack API calls | 1 | 0 |

A secondary win: previously `getSlackClient()` ran before the bot check
and threw on failure, so a revoked Slack connection made **every
unrelated human join** fail its job and retry. Now a human join answers
from kv and returns cleanly; the connection is only touched when there
is genuinely something to post.

## Claim ordering

Moving the client lookup after the claim opened a window where the claim
is held but nothing was posted, so that path now releases the claim
before throwing. The invariant the file follows is unchanged: release on
any failure that produced no message, keep it once a message is out (a
retry must not repost the channel message).

## Renames

`claimSlackTeam` → `registerSlackConnection`, and the logic function
`slack-team-claim` → `slack-register-connection`, since it now does more
than claim the team and connect-time work will keep landing there.

**The universal identifier value is unchanged** (`a29ae15d-…`) — it is
the app's stable identity and what the connection provider binds
`onConnectLogicFunction` to. Only the constant's name moved. Worth a
second pair of eyes in review, since that is exactly the kind of thing a
rename sweep regenerates by reflex.

Note this changes `name` and `sourceHandlerPath`/`builtHandlerPath` in
the manifest. Both are updates keyed on the unchanged identifier, not a
delete-and-recreate, so installed apps re-sync cleanly — but the app
needs rebuilding so the bundle path matches.


<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/23722?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->



## Cache correctness

A wrong cached id fails silently — the bot's own join reads as someone
else's and the welcome never fires — so the entry is bounded and
self-healing in three ways:

- **Failed write drops the key.** Leaving the previous id in place would
keep a superseded value authoritative. An absent cache is rebuilt from
`auth.test`; a wrong one is believed.
- **Entries expire after 7 days.** `registerSlackConnection` rewrites on
every connect, so the expiry only matters when that write never lands.
- **A kv outage falls through to `auth.test`** rather than throwing,
which keeps the human joins that make up nearly all these events from
failing their job.
2026-08-06 09:50:53 +00:00
..