-
Notifications
You must be signed in to change notification settings - Fork 2
Architecture overview: CoffeeTime
There are two key libraries that we are using:
-
Slack API: https://api.slack.com/ — this is the API that lets us have a Slack bot at all.
- NOTE: We're using the Events API, so ignore anything about the "Real Time Messaging API." I believe this is legacy and not recommended anymore (even though it doesn't say so on the RTM API page) and at any rate, we're not using it, and anything referring to it is irrelevant to us.
- We are also using the Block API and not Message Attachments, which are legacy and actively discouraged
-
Bot Kit: https://botkit.ai/docs/readme-slack.html — this is the node library that we're using to make the Slack API easier to use
- Note: It doesn't have great support for the Block API: https://botkit.ai/docs/readme-slack.html#interactive-messages So we have more custom code around that, esp in the block_actions/shared directory.
- Note: Luckily Bot Kit doesn't prevent us from interacting with just the Slack API when we need to, and provides some helper libraries to get a little lower-level
Here's a quick tour of the code base!
This traces roughly what code is invoked after a user types /coffeetime.
User types /coffeetime
which first gets forwarded to Slack's servers, then sends that message as a POST request to coffeetime.glitch.me/slack/receive (because we added a /coffeetime Slack command via https://api.slack.com/apps and in that configuration, set the request URL to /slack/receive).
- Check out incoming_webhooks.js: https://glitch.com/edit/#!/coffeetime?path=components/routes/incoming_webhooks.js:1:0
-
onSlackRecieve
handles POST requests to /slack/receive - There's an if statement that separately "handles" app uninstall, because this event is not handled by default in Botkit
- Note that it used to wipe the database on uninstall, but I'm not sure if that's what we want to do, so I commented it out for now (we could delete all that dead code if you want)
- The call to
req.controller.handleWebhookPayload(req, res);
is what forwards this request to Botkit to handle - So then, check out skills/coffeetime.js: https://glitch.com/edit/#!/coffeetime?path=skills/coffeetime.js:1
-
controller.on('slash_command')
is the Botkit handler for slash commands: https://botkit.ai/docs/readme-slack.html#slash-commands, and you can see how the default action isbot.replyPrivate(message, sharedConvo.getHelpMenuBlocks(message.user_id));
-
- Then check out https://glitch.com/edit/#!/coffeetime?path=skills/block_actions/shared/convo.js:1:0 which returns the menu, which is formatted using the format specified by the Block API
-
After typing /coffeetime
, the user will see a menu with interactive buttons that allow the user to navigate through various options. Because we are using the Block API, clicking these buttons invoke Block Actions.
So after a user clicks "What's CoffeeTime?":
- The button has an
action_id
(Slack API; shared/util.js) that we set to be able to identify what button the user has selected. To help ensure these values are unique, all the actions we use are defined as constants in shared/util.js and are informally namespaced. - When a user clicks a button, Slack will send a message to the CoffeeTime server, and BotKit will process it as a block_actions event.
- For code organizational purposes, there are multiple block_actions listeners in the code base: one in setup.js, admin.js, and help.js. These all refer to the menus shown in the setup menu (displayed on installation), admin menu (displayed on
/coffeetime
admin), and help menu (displayed with/coffeetime
or by DMing CoffeeTime with help). There's no technical requirement to have multiple block_actions listeners; this is done purely to help organize the code better.
- For code organizational purposes, there are multiple block_actions listeners in the code base: one in setup.js, admin.js, and help.js. These all refer to the menus shown in the setup menu (displayed on installation), admin menu (displayed on
- The "What's Coffeetime?" button has an
action_id
ofhelp.WHAT_IS_THIS_VALUE
, andblock_actions
listener in the help.js handles thisaction_id
: https://glitch.com/edit/#!/coffeetime?path=skills/block_actions/help.js:17:10
BotKit handles a lot of the magic around OAuth and Installation. See https://glitch.com/edit/#!/coffeetime?path=components/routes/oauth.js:1:0 - a lot of this was taken from the BotKit starter kit and not really thought about too deeply.
See dev docs for how to trigger the initial installation flow.
There's a cron job to automatically run the scheduling of the CoffeeTime pairs at a given point in time.
The cron job functions are here: https://glitch.com/edit/#!/coffeetime?path=components/coffee_cron.js:1:0
Keep-alive In order for the cron job to run, the app must be awake. Currently, we are using two free 3rd-party services to ping the app:
- UptimeRobot pings the site every 45 minutes
- Cron-Job.org pings the site every day at 9:10 AM CT/10:10 AM ET
CoffeeTime has two type of storage:
-
.data/coffee.json
: This is our own json file that we created to keep track of people registered to CoffeeTime and previous pairs. (As of this writing, data in this file is currently structured in a way that assumes only one Slack instance and does not support multiple workspaces.) -
.data/db
: This is a database that BotKit creates upon installation and uses under-the-hood to help with routing. (docs) (This is currently a json file, but can be configured to point to e.g. a mongo instance.) We also query the database explicitly when messaging all users via cron job.- See https://glitch.com/edit/#!/coffeetime?path=components/routes/oauth.js:1:0 and controller.storage.teams.save for an example of where we're explicitly saving to this database
- See https://glitch.com/edit/#!/coffeetime?path=components/coffee_cron.js:1:0 for an example of where we are querying this database in order to access the credentials needed to message users.