Host @dsgt Slack bot on Firebase App Hosting - #356
Conversation
Restore apps/dsgt-slack and serve Slack Events API, slash commands, and interactivity at /api/webhooks/slack on sites/mainweb. Production uses HTTP (not Socket Mode) with SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET from Secret Manager.
Dependency ReviewThe following issues were found:
|
|
Visit the preview URL for this PR (updated for commit bdb0052): https://hacklytics2027--pr-356-2g1stjc2.web.app (expires Mon, 24 Aug 2026 16:53:05 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: c48ba34db61581e25fe2978355160b5eefe0e83f |
|
Visit the preview URL for this PR (updated for commit ef0d6df): https://hacklytics2027--pr-356-2g1stjc2.web.app (expires Mon, 24 Aug 2026 17:01:51 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: c48ba34db61581e25fe2978355160b5eefe0e83f |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit bdb0052. Configure here.
| if (event) { | ||
| await handleEvent(event, client); | ||
| } | ||
| return Response.json({ ok: true }); |
There was a problem hiding this comment.
Events ACK waits on reply
Medium Severity
event_callback handling awaits chat.postMessage before returning HTTP 200. Slack’s Events API requires an ACK within about 3 seconds and retries on timeout; with App Hosting minInstances: 0, cold starts plus the API call can overrun that window, so Slack retries and the bot posts the same reply again. There is also no event_id / retry dedupe.
Reviewed by Cursor Bugbot for commit bdb0052. Configure here.
|
| Filename | Overview |
|---|---|
| apps/dsgt-slack/src/http.ts | Implements signature verification and Slack request routing, but event acknowledgements remain coupled to outbound reply delivery. |
| sites/mainweb/app/(portal)/api/webhooks/slack/route.ts | Connects the Next.js endpoint directly to the Slack handler without asynchronous processing or event deduplication. |
| apps/dsgt-slack/src/http.test.ts | Covers signatures, challenges, mentions, DMs, and slash commands using immediately successful message-delivery mocks. |
| apphosting.yaml | Adds the Slack bot token, signing secret, and production HTTP-mode configuration to App Hosting. |
Sequence Diagram
sequenceDiagram
participant Slack
participant Route as Next.js webhook route
participant Handler as Slack HTTP handler
participant API as Slack Web API
Slack->>Route: Signed event_callback
Route->>Handler: handleSlackWebhook(request)
Handler->>API: await chat.postMessage(...)
Note over Slack,API: HTTP acknowledgement remains pending
API-->>Handler: Success or rejection
alt Success
Handler-->>Slack: "200 {ok:true}"
else Rejection
Handler-->>Slack: 400 Invalid JSON body
Slack->>Route: Retry same event
end
Reviews (3): Last reviewed commit: "Fix Slack app manifest so Create from ma..." | Re-trigger Greptile
| if (payload.type === "event_callback") { | ||
| const event = parseMessageEvent(payload.event); | ||
| if (event) { | ||
| await handleEvent(event, client); | ||
| } | ||
| return Response.json({ ok: true }); |
There was a problem hiding this comment.
Webhook acknowledgement waits on replies
When chat.postMessage is slow or rejects, event processing delays the webhook acknowledgement or returns 400 Invalid JSON body, causing Slack to retry the event. Because this path has no retry or event deduplication handling, the retried event can post duplicate bot replies.
The Firebase @dsgt app only answers help, ping, and join. Google Slides, Forms, and other MCP tools belong on the Grok Bot teammate installed into the DS@GT Slack workspace.
Replace the polynomial <@[^>]+> matcher with a linear indexOf scan so a flood of incomplete <@ prefixes cannot backtrack on event text.
Slack rejects Event Subscriptions, Interactivity, and /dsgt when Socket Mode is off and no Request URL is set. Keep the @dsgt bot user and scopes so the app can be installed; add those HTTP features in the Slack UI after the webhook is live.


Restores the
@dsgtSlack bot and serves Slack over HTTP on the existing Firebase App Hosting backend. There is no second Cloud Run service and no Socket Mode in production.Slack manifest (Create from manifest)
Slack rejects Event Subscriptions, Interactivity, and
/dsgtwhen Socket Mode is off and no Request URL is set (invalid_manifest).apps/dsgt-slack/manifest.yamlnow creates the@dsgtbot user and scopes only. After{AUTH_URL}/api/webhooks/slackis live, add those HTTP features in the Slack app settings.Grok Bot vs this PR
This PR is a small FAQ webhook (help, ping, join). It is not Grok Bot.
Google Slides, Forms, Drive, Gmail, and other MCP tools belong on your Grok Bot teammate, the same way
@Yodoworks in Campus Leads Slack. Install that teammate into the DS@GT club workspace, connect Slack + Google there, and name the Slack bot userdsgt. Do not put those connectors in Firebase. Do not run this FAQ app and Grok Bot on the same bot tokens.The Cursor Slack connector always posts as Cursor. Posting as
@dsgtrequires this Slack app installed in that workspace.Why this shape (FAQ fallback)
sites/mainwebalready has an HTTP webhook at/api/webhooks/stripe.proxy.tsalready excludes/api/webhooks/*. App Hosting deploys that Next.js app to Cloud Run.Request URL if you install this FAQ app (Event Subscriptions, Slash Commands
/dsgt, Interactivity):AUTH_URL/NEXTAUTH_URLinapphosting.yamlis the App Hosting origin (club hostdatasciencegt.org). Slack must hit that Cloud Run surface, not the static Firebase Hosting sitedsgt-website(sites/mainweb/out/).What the FAQ bot does
@dsgtmentions (app_mention)message.im)/dsgt(help,ping,join)Copy stays in
apps/dsgt-slack(replies.ts). No LLM backend in this package.stripBotMentionno longer uses/<@[^>]+>/(CodeQLjs/polynomial-redoson PR alert #810). Mentions are removed with a linearindexOfscan.Before merging — Secret Manager (FAQ app only)
apphosting.yamlnow referencesSLACK_BOT_TOKENandSLACK_SIGNING_SECRET. Create those secrets and grant the App Hosting backend access before this lands, or the next App Hosting deploy cannot start. Skip this if you are only using Grok Bot in Slack and will not deploy this webhook. Steps:apps/dsgt-slack/README.md.Tests
pnpm --filter @query/dsgt-slack test— join FAQ, slash routing, mention stripping, HTTP signature / challenge / mention / DM //dsgt join.weblint and typecheck still fail on pre-existing files this PR does not touch.