Slack app scaffold that runs entirely in Socket Mode, opens a modal from a global shortcut, and forwards the submission to an external HTTP endpoint.
- Node.js 18+
- Slack workspace where you can create/manage apps
- External API endpoint that accepts JSON POST requests
-
Install dependencies:
npm install
-
Copy
.env.exampleto.envand populate the values:cp .env.example .env
Variable Description SLACK_SIGNING_SECRETRequired. Found on your app's Basic Information page. SLACK_BOT_TOKENRequired. Bot token with commandsandchat:writescopes.SLACK_APP_TOKENRequired. App-level token with the connections:writescope for Socket Mode.API_ENDPOINTRequired. URL that receives the form data. API_AUTH_TOKENOptional bearer token added to the outbound request. SHORTCUT_CALLBACK_IDOptional. Defaults to manage_uplogd. Must match your global shortcut callback ID.
| ASSETS_ENDPOINT | Required. URL returning a list of assets used to populate the modal dropdown. |
| ASSETS_AUTH_TOKEN | Optional bearer token used when fetching assets. |
| UPLOGD_UPDATES_CHANNEL | Optional channel ID (e.g. C01234567). When set, the bot posts submission updates there instead of DMing the user. |
| UPLOGD_DM_RECIPIENT | Optional user ID (e.g. U0123ABCD). When set, the bot sends DM summaries to this user instead of the requester. |
-
Create the Slack app (or open your existing one):
- Enable Socket Mode and generate an app-level token with the
connections:writescope. - Enable Interactivity & Shortcuts (no public URL needed when using Socket Mode).
- Add a Global Shortcut whose callback ID matches
SHORTCUT_CALLBACK_ID(defaultmanage_uplogd). - Add the following bot scopes:
commands,chat:write, and any additional scopes you need. Includechat:write.publicif you plan to post into public channels the bot hasn't joined yet. - Install the app to your workspace and copy the credentials into your
.envfile.
- Enable Socket Mode and generate an app-level token with the
npm run devThis starts the Bolt app in Socket Mode—no public URL or tunneling tool is required.
The project includes a PM2 script that keeps the bot running on a server:
-
Install dependencies and configure
.envon the host as described above. -
Start the background process with:
npm run deploy
This launches PM2 with a process named
uplogd-botthat watches thesrcdirectory for changes. -
Check the process anytime with
pm2 status uplogd-bot. -
Stream logs when needed with
pm2 logs uplogd-bot. -
Stop or remove the process via
pm2 stop uplogd-botorpm2 delete uplogd-bot.
- The global shortcut fires
src/app.js, which fetches assets fromASSETS_ENDPOINT, then opens the modal defined insrc/modal.js. - When the user submits the modal,
src/services/submitForm.jsserializes the selected asset, which targets (imx8/crystal) were checked, and the chosen action (start,stop,restart), then sends them toAPI_ENDPOINTviaaxios. - The bot DMs the requester immediately, then edits that DM with the SSH response once the external API call returns. When
UPLOGD_UPDATES_CHANNELis set, it also posts a one-line announcement with a status button to that channel; status checks there reply via ephemeral messages so the public post stays clean. - A bearer token header is added when
API_AUTH_TOKENis provided.
You can extend the modal blocks or adjust the payload transformation inside submitFormPayload to match your API contract.
ASSETS_ENDPOINT should respond with either:
- An array of strings; each string becomes both the option label and value.
- An array of objects containing at least an identifier (
asset,id,uuid,slug,code, orkey) and a display name (name,title,label, ordisplay_name). Optionaldescriptionfields are truncated and shown as helper text in the select menu.
If the endpoint responds with an object, the adapter falls back to data.items.
The dropdown currently filters assets to those whose name starts with sg, by, or cr. Primary/secondary flags from the payload determine which options appear under the "Which Machine?" checkbox group (imx8 for primary, crystal for secondary), and unavailable machines are noted inline. The selected action (start, stop, restart) and any checked targets are included in the submission payload, and each selected machine results in a POST to API_ENDPOINT/uplog/{boat}/{action} (with boat taken from the asset ID) carrying the machine and metadata.