ADR-005 — Slack ingress

Shipped 2026-05-25. Phases 1 through 5 landed sequentially: ingress interface + Teams relocation, inbound webhook + signing verify, outbound + dispatcher integration, admin Slack config UI, channel-to-tenant mapping.

Context

Before this ADR every Brand-Owner's tenants reached their agents through one ingress: Microsoft Teams via the Bot Framework. Future resellers don't all sell to Microsoft shops. Slack is the overwhelming majority of B2B SaaS chat; the same agent runtime should service Slack just as well as Teams.

Decision

Introduce an Ingress abstraction in the runtime so Teams + Slack + future Discord share a common dispatch path. Each ingress implementation owns inbound normalisation, outbound reply delivery, identity mapping (channel user id → User row), and thread mapping (channel threads → conversation history).

Per-Brand BYO is mandatory for Slack — each Brand creates their own Slack App in their workspaces; Aroovo never owns the bot identity for a Brand's tenants. Credentials live encrypted in the same Secret vault that holds Entra client secrets and LLM provider keys, scoped by brandId.

Out of scope

  • Discord ingress. Same shape as Slack, queued for a separate motion once Slack stabilises in production.
  • Slack slash commands and interactive blocks. Ship DM + thread + @mention only on this ADR.
  • Slack workflow steps and shortcuts.
  • Slack file uploads. Initial scope is text only.

Phases

  1. Phase 1 — Ingress interface + Teams relocation. Extract Teams-specific code behind the new interface; no behaviour change.
  2. Phase 2 — Slack inbound + signing verify. Receive Slack Event API webhooks; verify the signing secret per Slack's HMAC scheme.
  3. Phase 3 — Outbound + dispatcher integration. chat.postMessage via the Brand's bot token; thread continuity via thread_ts.
  4. Phase 4 — Admin Slack config UI. Paste-only install for the bot token + signing secret; per-Brand scope.
  5. Phase 5 — Channel-to-tenant mapping. One Slack workspace can host bots for multiple Brand customers if needed; channel-level isolation keeps the conversations separate.

Operational notes

  • 14-day cap on a Slack thread before it's archived; matches the existing Teams thread retention.
  • The PII redactor (used for Teams) is reused on the Slack inbound path.
  • The Aroovo Brand (id='aroovo') stays Teams-only for now; adding Aroovo's own Slack follows the same BYO pattern.

References

Full markdown: adr-005-slack-ingress.md.

Related: Concepts — Multi-channel ingress, How-to — Add Slack ingress.