Add Slack and Microsoft Teams as channel adapters#257
Conversation
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>
stephengpope
left a comment
There was a problem hiding this comment.
Really nice work on this — the channel adapters are clean, and I love that there are zero new npm deps (built-in crypto for both) and that everything stays inert without config. No impact on existing Telegram/web users. 🙌
One thing I'd suggest pulling out before merge: the Dockerfile and .gitignore changes. They're a dev-convenience for baking a local tarball, but they're unrelated to the Slack/Teams feature and carry a real risk:
COPY thepopebot-*.tgz* ./ is its own instruction with no concrete fallback file. When the glob matches zero files, BuildKit fails the build (failed to compute cache key: not found) — it never reaches the RUN fallback. The existing COPY package.json package-lock.json* ./ only works because package.json is always present alongside the optional glob.
The catch: CI's build-event-handler job builds from context: . and never runs npm pack, so there's no .tgz in the context. That would break the published event-handler image that everyone upgrades from — not just Slack/Teams users.
Suggestion: drop the Dockerfile + .gitignore changes from this PR and keep the rest (adapters, config keys, routes, UI). That leaves a purely additive feature with no pipeline risk. The tarball workflow could land separately if it's still wanted, with a concrete fallback so the zero-match case can't break the build.
Per @stephengpope review on PR stephengpope#257: the COPY thepopebot-*.tgz* + fallback branch and matching .gitignore entry are an AE-side dev convenience for baking working-tree changes into the event-handler image without publishing. They're unrelated to the Slack/Teams feature itself. More importantly, the new COPY had no concrete fallback file. When the glob matches zero files BuildKit fails the build before reaching the RUN's runtime fallback. Upstream CI's build-event-handler job builds from context: . and never runs npm pack, so it would always hit the zero-match case and break the published event-handler image. Restoring docker/event-handler/Dockerfile and .gitignore to their state prior to e13bc27 leaves this PR purely additive: adapter code, config keys, Next.js routes, admin nav, UI. The tarball convenience lives only in the AE fork; if it's ever wanted upstream it should land as its own PR with a concrete fallback so the zero-match case can't bite.
|
Thanks for the review @stephengpope — and the catch on the Dockerfile change is dead right. I hadn't traced through the CI implication that Pushed The tarball convenience lives only in my fork now. If it ever makes sense upstream I'll send it as its own PR with a concrete fallback file so the zero-match case can't bite. Ready for re-review whenever you have a minute. |
Folds the Slack + Teams channel adapters into the AE mainline alongside MFA, so ae-main is the single production line (branding + status + MFA + Slack/Teams). Ends the fragile temp-merge-at-build-time dance that risked dropping Slack/Teams from the droplet on every build. feature/slack-teams-channels stays as the record of the still-open upstream PR stephengpope#257; if Stephen merges it, git reconciles on the next upstream sync. Conflict: lib/config.js SECRET_KEYS — kept both the SMTP (MFA) keys and the TEAMS_* keys. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Adds Slack and Microsoft Teams as channel adapters alongside the existing Telegram + web channels. Both work end-to-end in personal DMs with two-way messaging, JWT/HMAC webhook verification, and channel binding via a non-conflicting
!verify <code>command (Slack and Teams both intercept/commands).Tested locally via ngrok and in production on a DigitalOcean droplet with Cloudflare-issued Let's Encrypt wildcard SSL.
What's included
app_mention+message.imevents,url_verificationhandled before credentials checklogin.microsoftonline.com/{tenantId}/oauth2/v2.0/tokeninstead ofbotframework.com— common gotcha on first install)!verify <code>binding flow for bothFiles changed (7)
Compatibility
Test plan
🤖 Generated with Claude Code