Modernize: interactive-messages -> Bolt, Sentry 10, TS/CI + GHCR/Coolify deploy - #91
Open
ddbruce wants to merge 1 commit into
Open
Modernize: interactive-messages -> Bolt, Sentry 10, TS/CI + GHCR/Coolify deploy#91ddbruce wants to merge 1 commit into
ddbruce wants to merge 1 commit into
Conversation
…10, tests Migrate off Slack's deprecated @slack/interactive-messages adapter to @slack/bolt while preserving the /inorout poll behavior (inline + modal poll creation, voting, anon/multiple, reset/lock/move/delete, ephemeral author-only guards). The Poll vote/tally core (Poll.ts) is unchanged. SDK / routing: - Remove @slack/interactive-messages + express + body-parser; add @slack/bolt 4.x. Bolt serves a single endpoint (/slack/events) for the slash command AND interactivity, plus a custom /health route. - @slack/web-api 6 -> 7, @slack/types current, dotenv 10 -> 17. - Give poll vote buttons stable action_ids (vote_<n>) and the options select action_id "poll_options" so Bolt can route them (Bolt matches actions by action_id, not element type). Poll.ts parses buttons by element type, so vote tallying is unaffected. Add callback_id "poll_modal" to the modal view. Sentry: - @sentry/node 6 -> 10. Replace the removed configureScope() with Sentry.setUser()/setExtra() in Poll.ts. TypeScript / tooling: - tsconfig: target es5 -> ES2022, keep commonjs, add rootDir/skipLibCheck. - ESLint (broken 10.x + legacy .eslintrc) -> ESLint 9 flat config with typescript-eslint 8. Add ts-jest tests for the vote/tally logic (8). - Multi-stage Dockerfile (build tsc, ship out/ + prod deps), node:24-alpine, non-root, HEALTHCHECK. Replace dead Drone CI with GitHub Actions (lint + compile + test + amd64 build). - Add scripts/deploy.sh + config.example.sh (amd64 -> GHCR -> Coolify redeploy). Verified: tsc compiles, 8 unit tests pass, boots on Bolt 4 (/health 200, unsigned /slack/events 401), amd64 image builds with 0 npm vulnerabilities. Behavior deltas to verify in staging (documented in the PR): single unified Slack Request URL, transient "processing" messages dropped, and error responses are now ephemeral instead of replacing the poll. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces Slack's deprecated
@slack/interactive-messagesadapter with@slack/bolt, and modernizes the rest of the stack. The/inoroutpoll behavior is preserved: inline + modal poll creation, voting, anonymous/multiple modes, and the reset/lock/move/delete options with author-only ephemeral guards. The vote/tally core (Poll.ts) is unchanged and is now unit-tested.Verified:
tsccompiles, 8 unit tests pass (vote tally, reset, single-vs-multiple, anonymous, author parsing), boots on Bolt 4 with/health→ 200 and unsigned/slack/events→ 401; amd64 image builds with 0 npm vulnerabilities.Changes
@slack/interactive-messages+express+body-parser; added@slack/bolt4.x.@slack/web-api6→7, dotenv 10→17. Vote buttons got stableaction_ids (vote_<n>) and the options select gotpoll_optionsso Bolt can route them (Bolt matches by action_id, not element type); the modal view gotcallback_id: "poll_modal".configureScope()withsetUser()/setExtra().targetes5 → ES2022 (kept commonjs); ESLint (the broken 10.x + legacy.eslintrc) → ESLint 9 flat config with typescript-eslint 8; ts-jest tests added.tsc, shipout/+ prod deps only),node:24-alpine, non-root,HEALTHCHECK; dead Drone CI → GitHub Actions (lint + compile + test + amd64 build);scripts/deploy.sh+config.example.sh.Bolt serves one endpoint. Point both of these at the same URL:
https://<host>/slack/eventshttps://<host>/slack/events(Previously they were split:
/slack/commandsand/slack/actions.) No app re-creation needed. Env vars are unchanged (SLACK_ACCESS_TOKEN,SLACK_SIGNING_SECRET,PORT,SENTRY_DSN,ENVIRONMENT).Verify in staging (behavior deltas)
/inorout(modal) and/inoroutwith option lines.Recommended follow-ups (NOT done)
ModalMapis still an in-memoryMap(open modals are lost on restart / not multi-instance safe).