Abdul Rahman 577cd68cb5 feat(slack): release the Slack team claim when the connection goes away (#23753)
Closes the loop on
https://github.com/twentyhq/twenty/pull/22984#discussion_r3673946334,
where the Slack app claimed a `team_id` on connect and never released
it. The `onDisconnect` hook it waited on merged in #23538, and
`twenty-sdk` 2.27.0 ships the `onDisconnectLogicFunction` manifest
field, so this bumps the app to it.

## Disconnect

`slack-team-release` releases the server-scoped `slack-team:{teamId}`
claim, so another Twenty workspace can connect that Slack team
afterwards. `kv.delete` on a SERVER key only clears a claim the calling
workspace owns, and the result reports a team only when that delete
actually removed something.

The connection is already deleted when the hook runs, so `getConnection`
cannot resolve the `team_id` anymore. `claimSlackTeam` records `teamId`
under a workspace-scoped
`slack-connected-account-team:{connectedAccountId}` key, written before
the claim itself so a failure between the two cannot leave a claim
nothing can resolve, and the release reads it back from there. That also
retires the TODO the review comment pointed at.

The release is skipped when a live connection still maps to the same
team, excluding the disconnecting account explicitly. That covers a
reconnect that re-claimed the team while the job was queued, and a
second connection to the same Slack workspace, whose claim would
otherwise have been dropped along with the first. The recorded team is
cleared either way, so the disconnecting account leaves nothing behind.

## Uninstall

Uninstalling the app drops its connections through the
`connectionProvider` and `application` cascades, which never reach the
disconnect hook, and the same operation deletes the app's logic
functions so the hook could not run anyway. The app declares an
`uninstallLogicFunction`: it runs before the app's metadata is
deleted, lists the remaining Slack connections, and releases each claim
through the same `releaseSlackTeamClaim` util. It deliberately skips the
live-connection check, since at that point every connection is still
listed.

## Known limits

A disconnect immediately followed by a reconnect has a window where the
queued release can clear a claim the reconnect just took. It self-heals,
because the reconnect's own onConnect re-claims the same key moments
later. Closing it properly needs a compare-and-set on the claim, which
the key-value store does not expose.

No unit tests are added for the release path. Earlier revisions of this
branch had specs for the disconnect guard, the uninstall sweep and the
no-op-release result; they were dropped, so those branches carry no
regression coverage. The app's existing 34 tests still pass, along
with lint, typecheck and `twenty dev:build`, the last being what used to
fail with `Duplicate universal identifiers` on the older SDK.
2026-08-06 13:57:33 +00:00
2026-06-11 11:02:28 +02:00

Twenty logo

The #1 Open-Source CRM

Website · Documentation · Roadmap · Discord · Figma

Twenty banner


Why Twenty

Twenty gives technical teams the building blocks for a custom CRM that meets complex business needs and quickly adapts as the business evolves. Twenty is the CRM you build, ship, and version like the rest of your stack.

Learn more about why we built Twenty


Installation

Cloud

The fastest way to get started. Sign up at twenty.com and spin up a workspace in under a minute, with no infrastructure to manage and always up to date.

Build an app

Scaffold a new app with the Twenty CLI:

npx create-twenty-app my-app

Define objects, fields, and views as code:

import { defineObject, FieldType } from 'twenty-sdk/define';

export default defineObject({
  nameSingular: 'deal',
  namePlural: 'deals',
  labelSingular: 'Deal',
  labelPlural: 'Deals',
  fields: [
    { name: 'name', label: 'Name', type: FieldType.TEXT },
    { name: 'amount', label: 'Amount', type: FieldType.CURRENCY },
    { name: 'closeDate', label: 'Close Date', type: FieldType.DATE_TIME },
  ],
});

Then ship it to your workspace:

npx twenty app:publish --private

See the app development guide for objects, views, agents, and logic functions.

Self-hosting

Run Twenty on your own infrastructure with Docker Compose, or contribute locally via the local setup guide.



Everything you need

Twenty gives you the building blocks of a modern CRM (objects, views, workflows, and agents) and lets you extend them as code. Here's a tour of what's in the box.

Want to go deeper? Read the User Guide for product walkthroughs, or the Documentation for developer reference.

Create your apps

Learn more about apps in doc

Stay on top with version control

Learn more about version control in doc

All the tools you need to build anything

Learn more about primitives in doc

Customize your layouts

Learn more about layouts in doc

AI agents and chats

Learn more about AI in doc

Plus all the tools of a good CRM

Learn more about CRM features in doc


Stack

Thanks

Greptile      Sentry      Crowdin

Thanks to these amazing services that we use and recommend for code review (Greptile), catching bugs (Sentry) and translating (Crowdin).

Join the Community

Star the repo · Discord · Feature requests · Releases · X · LinkedIn · Crowdin · Contribute

S
Description
The open alternative to Salesforce, designed for AI.
Readme AGPL-3.0 1.4 GiB
Languages
TypeScript 79.6%
MDX 17.3%
JavaScript 2.7%
Python 0.2%
SCSS 0.1%