Slack bot that turns messages in help channels into tracked tickets. Built with Slack Bolt (Socket Mode) and PostgreSQL.
When someone posts in a configured help channel, the bot:
- Adds a thinking face reaction to the message
- Posts a thread reply letting them know someone will help
- Sends them an ephemeral message (visible only to them) asking for a short title
- Creates a ticket in a private ticket channel once the title is submitted (or after 3 minutes if they skip)
Helpers can claim tickets, mark them as resolved, and reopen them. When a ticket is resolved, the bot posts a notice in the original thread with a Reopen button.
- Node.js 18+
- A PostgreSQL database (tested with Neon)
- A Slack app with Socket Mode enabled
Create a new app at api.slack.com/apps.
OAuth scopes (Bot Token):
channels:historychannels:readchat:writecommandsgroups:historygroups:readreactions:addreactions:removeusers:read
Event subscriptions:
Enable Socket Mode, then subscribe to:
message.channelsmessage.groups
Slash commands to create:
/camper-addhelper/camper-removehelper/camper-helpers/camper-helpstats
After installing the app to your workspace, copy the Bot Token (xoxb-...), App-Level Token (xapp-...), and Signing Secret from the app settings.
git clone https://github.com/your-org/camper
cd camper
npm install
cp .env.example .envnvFill in the .env file (see below), then run:
node index.js| Variable | Description |
|---|---|
SLACK_BOT_TOKEN |
Bot token from OAuth settings (xoxb-...) |
SLACK_SIGNING_SECRET |
Signing secret from Basic Information |
SLACK_APP_TOKEN |
App-level token with connections:write scope (xapp-...) |
SLACK_HELP_CHANNEL |
Channel ID(s) to monitor, comma-separated (e.g. C123,C456) |
SLACK_TICKET_CHANNEL |
Channel ID where tickets are posted |
SLACK_ADMIN_USER_IDS |
Comma-separated user IDs who can manage helpers |
FAQ_URL |
Optional URL sent when a helper uses ?faq |
DATABASE_URL |
PostgreSQL connection string |
DASHBOARD_PORT |
Port for the web dashboard (default: 3001) |
SESSION_SECRET |
Secret for Express session cookies |
SLACK_CLIENT_ID |
OAuth client ID (for dashboard login) |
SLACK_CLIENT_SECRET |
OAuth client secret |
SLACK_DASHBOARD_REDIRECT_URI |
OAuth callback URL (e.g. https://yourdomain.com/auth/callback) |
Channel and user IDs can be found by right-clicking a channel or user in Slack and selecting "Copy link" or "Copy member ID".
These can only be used by users listed in SLACK_ADMIN_USER_IDS.
| Command | Description |
|---|---|
/camper-addhelper @user |
Add a user as a helper |
/camper-removehelper @user |
Remove a helper |
/camper-helpers |
List current helpers |
/camper-helpstats |
Show ticket counts (total, open, resolved) |
Helpers can type these in any ticket thread:
| Macro | Action |
|---|---|
?resolve or ?close |
Mark the ticket as resolved |
?reopen |
Reopen a resolved ticket |
?faq |
Send the FAQ URL and resolve the ticket |
The dashboard is a separate Express server. Start it with:
node dashboard.jsIt uses Slack OAuth for login. Only helpers and admins can access it.
Set SLACK_DASHBOARD_REDIRECT_URI to the callback URL of wherever you host the dashboard, and add that URL to the allowed redirect URIs in your Slack app's OAuth settings.
The bot initializes the database automatically on startup. No migrations needed.
Tables created:
tickets- one row per help message, tracks status, who opened/claimed/closed it, ticket number, and a permalink to the original messagehelpers- list of helper user IDs
The bot uses Socket Mode, so it does not need a public URL. Any Node.js host works (Railway, Fly.io, a VPS, etc.).
Set all environment variables on the host. The dashboard needs to be deployed separately if you want it accessible publicly.