For the complete documentation index, see llms.txt. This page is also available as Markdown.

Data Collaboration

In-app discussion threads anchored to specific data entities, with replies tracked back from a Slack workspace via OAuth + the Slack Events API. Per-entity scope; opt-in.

ODD Platform's Data Collaboration feature lets users start in-app discussions about a specific data entity, with replies tracked back into the platform from a messenger. Conversations stay attached to the entity that anchored them, so an operator returning to a dataset months later can read the original threads — context, decisions, and follow-ups — without leaving the catalog.

The feature is exposed as a Discussions tab on every data entity's detail page (per-entity scope; not a global hub). At the moment Slack is the only supported messenger; integration with other providers would extend the same per-entity threading model.

The feature is disabled by default (datacollaboration.enabled=false). When disabled, every /api/datacollaboration/... route plus the /api/slack/events webhook return 404 Not Found — the controllers are gated by @ConditionalOnDataCollaboration.

How a discussion flows

  • A user opens the Discussions tab on a data entity, picks a Slack channel from the bot's autocomplete, and posts a thread-root message. The platform writes the message to its own message store and queues it for delivery into Slack.

  • A background sender (DataCollaborationMessageSenderJob) drains the queue. Each message is retried up to datacollaboration.sending-messages-retry-count times (default 3) before being marked failed.

  • When a Slack user replies in the thread, Slack POSTs an event_callback to the platform's /api/slack/events webhook. The platform translates the reply into an in-platform message linked to the same data entity, and the new reply appears under the original thread on the Discussions tab.

  • Per-entity history is queryable: thread-root messages and replies are paginated by entity ID. The platform retains its own copy of every message, so historical threads stay available even if the Slack channel rotates or the Slack workspace is migrated.

Slack — the full Slack app, not the alert webhook

The Slack integration that powers Data Collaboration is a full Slack app, distinct from the outgoing webhook the Notifications subsystem uses for alert messages. The data-collaboration app uses OAuth (datacollaboration.slack-oauth-token) and the Slack Events API to read replies back into the platform — bidirectional. The alerting Slack integration is a one-way incoming webhook that the platform POSTs alert messages to (notifications.receivers.slack.url) — no replies, no thread state.

An operator who has already set up the alert webhook still needs to set up the Slack app separately to enable Discussions; the two configurations are independent. See Main Concepts → Terms & Aliases for the canonical side-by-side comparison.

Where to set it up

Known operator caveats

The Data Collaboration surface — and specifically the Slack integration that powers it today — carries several behaviours that are non-obvious from the configuration reference and the feature description above. Each item below states what an operator might assume, what the platform actually does, and what to do today.

Slack channel autocomplete is cached for 60 seconds, matches on a prefix, and lists only channels the bot already belongs to. The platform's Slack channel lookup uses a Caffeine async-loading cache keyed on a fixed sentinel, with expireAfterWrite(1, MINUTES). When an operator invites the platform's bot to a new Slack channel, the channel becomes reachable from the bot's perspective immediately on the Slack side — but the platform's autocomplete continues to return the cached list (which does not include the new channel) for up to 60 seconds. After the cache TTL expires, the next autocomplete request triggers a fresh fetch and the channel appears.

Two further behaviours shape what the autocomplete shows. The typed filter is a prefix match (startsWith), not a substring match — typing the middle of a channel name returns no suggestions, so users must type from the start of the channel name. And the list only includes public channels the bot has been added to; private channels, DMs, and archived channels are never offered, so a channel that is missing from the picker usually means the bot has not been invited to it.

If you cannot wait 60 seconds (operator demo, time-sensitive setup), restarting the platform forces the cache to rebuild on first call.

Where to next

Last updated