Skip to content

Add Slack and Microsoft Teams as channel adapters#1

Closed
AutomationEdgeHQ wants to merge 3 commits into
mainfrom
feature/slack-teams-channels
Closed

Add Slack and Microsoft Teams as channel adapters#1
AutomationEdgeHQ wants to merge 3 commits into
mainfrom
feature/slack-teams-channels

Conversation

@AutomationEdgeHQ

Copy link
Copy Markdown
Owner

Summary

  • Adds Slack and Microsoft Teams as channel adapters, mirroring the existing Telegram pattern
  • New webhook routes: POST /api/slack/events, POST /api/teams/events
  • Admin UI extended: /admin/event-handler/slack and /teams for credentials, /profile/slack and /profile/teams for per-user linking
  • No DB migration — reuses the cross-channel user_channels table

Why this design

The original AE spec suggested Vercel's chat + @chat-adapter/* SDK, App Router per-route files, lib/bot.ts (TypeScript), Redis state, and a new /notify-channel endpoint. None of that fits the framework as built — thepopebot is JS-ESM, uses a catch-all api/index.js router, already has its own channel adapter system (lib/channels/base.js), keeps channel state in SQLite, and routes notifications through lib/db/messages.js. So this PR instead mirrors lib/channels/telegram.js exactly. No new runtime dependencies were added — Slack uses raw fetch, Teams uses hand-rolled JWT validation against Microsoft's JWKS (avoids pulling botbuilder ~5MB+).

What's in

  • lib/channels/slack.jsSlackAdapter (HMAC signature verification, url_verification, app_mention/message.im, files, threaded replies, AssemblyAI audio transcription)
  • lib/channels/teams.jsTeamsAdapter (Bot Framework JWT validation, Activity parsing, Connector REST sends, typing activity)
  • lib/tools/slack.js, lib/tools/teams.js — HTTP/crypto helpers
  • api/index.js/slack/events, /teams/events in PUBLIC_ROUTES, switch cases, pushToDefaultChannel extended for both channels
  • lib/chat/slack-profile.js, lib/chat/teams-profile.js — backend state loaders
  • lib/chat/actions.js — server actions: getSlackStatus, validateSlackToken, issueSlackCode, unlinkSlackChannel, setSlackSystemMessages (and Teams equivalents). SLACK_*/TEAMS_* added to API_KEY_SECRETS.
  • lib/chat/components/profile-page.jsxProfileSlackPage, ProfileTeamsPage + tab entries
  • lib/chat/components/settings-secrets-page.jsxApiKeysSlackPage, ApiKeysTeamsPage (3-step guided setup each)
  • lib/chat/components/icons.jsxSlackIcon, TeamsIcon
  • templates/.env.exampleSLACK_BOT_TOKEN, SLACK_SIGNING_SECRET, TEAMS_APP_ID, TEAMS_APP_PASSWORD
  • docs/CHAT_INTEGRATIONS.md — full client setup walkthroughs for both platforms

What's NOT in (intentional follow-ups)

  • Teams file attachments — would require Graph token / SharePoint OBO. Text messages work today.
  • Teams system pushes require a serviceUrl. Captured per inbound message; persistence onto user_channels for the first-push-before-inbound case is a future enhancement.
  • No /notify-channel HTTP endpoint — existing lib/db/messages.js already fans out cross-channel via the adapter system.
  • @slack/web-api and botbuilder were considered and dropped — raw fetch + hand-rolled JWT keep the dep tree clean.

Webhook URLs to register

  • Slack Events Request URL: <APP_URL>/api/slack/events
  • Teams messaging endpoint: <APP_URL>/api/teams/events

Test plan

  • Build a ledger:dev Docker image and point a local jay-bot install at it
  • Configure Slack credentials in admin UI → verify webhook accepts url_verification challenge
  • Link a Slack user via /profile/slack/verify <code> flow → confirm user_channels row
  • DM the bot in Slack → response in thread
  • @mention bot in a Slack channel → threaded reply
  • Trigger a system message (e.g. GitHub webhook) → Slack admin receives push
  • Configure Teams credentials → click "Test credentials" → Microsoft issues token
  • Sideload Teams manifest, DM the bot, verify with /verify <code>
  • Send a Teams message → reply arrives in same conversation
  • Verify existing Telegram flow still works end-to-end (regression check)

Upstreaming

This branch is meant to be offerable to stephengpope/thepopebot once tested. The main branch of this fork is untouched — Phase 2 (survey-server + Ledger white-label) layers on top later.

🤖 Generated with Claude Code

jaykimelman and others added 3 commits May 23, 2026 20:59
Mirrors the existing Telegram channel pattern to add two new chat
platforms. Reuses the cross-channel infrastructure already in place:
the user_channels table, /verify command, system-message dispatch,
and adapter base class.

Slack
- SlackAdapter (lib/channels/slack.js) handles Events API webhooks,
  signature verification (HMAC-SHA256 of v0:<ts>:<body>),
  url_verification challenges, app_mention/message.im events, file
  attachments (images + audio transcription via AssemblyAI when
  configured), and threaded replies via thread_ts.
- HTTP helpers in lib/tools/slack.js use raw fetch against the Slack
  Web API — no @slack/web-api dependency added.

Microsoft Teams
- TeamsAdapter (lib/channels/teams.js) handles Bot Framework Activity
  webhooks with hand-rolled JWT validation against Microsoft's JWKS
  (cached 24h) — avoids pulling botbuilder (~5MB+).
- Replies sent via the Bot Framework Connector REST API with a
  client-credentials access token (cached + auto-refreshed).
- Typing indicator re-emitted every 8s while AI processes.
- File attachment downloads left as a follow-up (needs Graph
  auth path); text messages fully supported.

API routing
- /slack/events and /teams/events added to PUBLIC_ROUTES and the
  catch-all api/index.js POST switch.
- pushToDefaultChannel extended to dispatch to Slack and Teams adapters.
  Teams pushes require a serviceUrl captured from inbound messages, so
  system notifications only flow after the user has messaged the bot.

Admin UI (mirrors Telegram exactly)
- /profile/slack and /profile/teams tabs for users to link their
  channel via a one-time /verify <code> flow.
- /admin/event-handler/slack and /teams pages for admins to paste
  credentials, see the webhook/messaging URL, and validate.
- New SlackIcon and TeamsIcon SVGs.

Database
- No schema changes. Slack rows use channel='slack', Teams use
  channel='teams' in the existing user_channels table.

Env vars (templates/.env.example)
- SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET
- TEAMS_APP_ID, TEAMS_APP_PASSWORD

Docs
- docs/CHAT_INTEGRATIONS.md extended with end-to-end client setup
  walkthroughs for both platforms (Slack app creation + scopes,
  Azure Bot registration + manifest sideload).
The previous commit added the Slack/Teams adapters, server actions, and
React page components but did not include the consumer-facing Next.js
route files. Without those, /profile/slack, /profile/teams,
/admin/event-handler/slack, and /admin/event-handler/teams all 404.

Adds:
- web/app/profile/slack/page.js
- web/app/profile/teams/page.js
- web/app/admin/event-handler/slack/page.js
- web/app/admin/event-handler/teams/page.js

Each mirrors the existing Telegram route exactly — auth check, fetch
initial state via the matching backend module, render the component.

- lib/chat/components/index.js: export ProfileSlackPage, ProfileTeamsPage,
  ApiKeysSlackPage, ApiKeysTeamsPage so the route files can import them
  from 'thepopebot/chat'.
- lib/chat/components/settings-secrets-layout.jsx: add Slack + Teams tabs
  to EVENT_HANDLER_TABS so the admin sidebar nav exposes them.
- docker/event-handler/Dockerfile: optional dev tarball install. If a
  thepopebot-*.tgz exists alongside (created via `npm pack`), install
  from it instead of the npm registry. Lets contributors test
  working-tree changes in Docker without publishing.
- .gitignore: thepopebot-*.tgz so packed tarballs don't get committed.
…Tenant ID support

- api/index.js: handle url_verification before credential check (Slack challenge arrives before creds are entered)
- lib/config.js: register SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET, TEAMS_APP_ID, TEAMS_APP_PASSWORD, TEAMS_TENANT_ID in SECRET_KEYS
- lib/channels/commands/index.js: accept ! prefix in addition to / (Slack and Teams both intercept /verify natively)
- lib/tools/teams.js: dynamic token endpoint via getTokenEndpoint() — reads TEAMS_TENANT_ID for Single Tenant support, falls back to botframework.com for Multi Tenant
- lib/chat/actions.js: add TEAMS_TENANT_ID to API_KEY_SECRETS; return tenantIdSet from getTeamsStatus
- lib/chat/components/profile-page.jsx: show !verify (not /verify) in Slack and Teams binding flow
- lib/chat/components/settings-secrets-page.jsx: add collapsible setup guides for Slack and Teams; add Tenant ID field (Step 2) to Teams section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@AutomationEdgeHQ

Copy link
Copy Markdown
Owner Author

Superseded by cross-fork PR stephengpope#257. Closing internal draft to keep a single canonical thread.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants