Skip to content

steve-c-thompson/standup-bot-serverless

Repository files navigation

Standup Slack App

Version License: ISC

This is a Slack app to post daily standup status, for teams that wish to hold offline standups. It launches a modal, prompting users for Yesterday, Today, Parking Lot Items, Parking Lot Participants, and Pull Requests for Review.

Users can schedule standup statuses to post at a specific time, or post immediately. They can edit their standup messages on the App's Home Tab.

In this offline standup process, "Parking Lot" is a face-to-face meeting scheduled at a regular time, which allows a subset of team members to meet and discuss issues. Prior to this meeting, a user can post the Parking Lot items to notify team members that their presence is required.

Standup Modal

The app launches a modal for data entry.

Help command and launching modal

Details of the modal are shown below.

Part 1/2 Part 2/2
Standup Modal Standup Modal

While standup messages appear to come from the user, they are actually created by the app, using the user's avatar and name.

Parking Lot

Any user can post the day's parking lot items for a channel. This will @ all users who were tagged for parking lot discussion.

Parking Lot

Home Tab

Users can edit statuses from the App's Home tab.

The Home tab is drawn from the user's status entries in the App's database. Status entries exist in the database for one day. Upon posting a status, the Home tab is redrawn with available statues, so statuses from earlier days will no longer display.

Home Tab

Installation

Add the app to channels where you wish to use it.

Slack Integration

Or invite the bot to the channel with @Standup.

Usage - Slack

/standup help
/standup [parking-lot | parking_lot | parkinglot | -p]- display ephemeral parking lot items
/standup post [parking-lot | parking_lot | parkinglot | -p] - post parking lot items to chat

Slack Configuration

The app must be configured on the Slack website. Slack has a tutorial for creating apps at https://api.slack.com/start/quickstart.

  1. Create an App
  2. The easiest way to configure this app is to update URLs in this project's slack_manifest.yml and import the file.

Steps below are listed for informational reference.

This bot uses a Slash Command, Home Tab, and enabled Interactivity. Slash Commands

Note: this slash command is connected to the lambda function in app.ts

app.command("/standup",...

Interactivity

  • Slash Commands and Interactivity use the same Request URL, which ends in /slack/events
  • For local testing, set these to the URL generated by ngrok. See Local Development below for details.
  • When the app is live, set these to the lambda URL

The app needs permissions to interact with the Slack workspace. Enable OAuth scopes in Slack.

Slack Scopes

  • chat:write
  • chat:write.customize
  • commands
  • groups:read
  • users.profile:read
  • users:read
  • channels:read

Once scopes exist, Install to Workspace.

Oauth

The Home Tab must be enabled in App Home.

Home Tab

Deployment

SLS makes it easy to deploy to AWS

Install with the command

npm install -g serverless
sls deploy --stage (prod | dev) [--aws-profile profile-name] [--region us-east-2]

To inspect the size and content of the deployment without deploying anything to AWS

sls package --stage (prod | dev) [--aws-profile profile-name]

You can also check configuration substitutions. This is useful for checking things like the target region.

sls print --stage (prod | dev)

Secrets

Create a secret in SecretsManager named SlackStandup_secret_dev or SlackStandup_secret_prod, depending on the target environment, with the values

  • SLACK_STANDUP_BOT_TOKEN
  • SLACK_STANDUP_SIGNING_SECRET

These can be found on the Slack website, at https://api.slack.com. Copy-paste the following values.

SLACK_STANDUP_BOT_TOKEN

In the app's OAuth & Permissions:

Oauth

SLACK_STANDUP_SIGNING_SECRET

In the app's Basic Settings copy the value for Signing Secret:

Signing secret

Local Development

Testing locally requires Docker, and setting the following environment variables in a .env file. These are the same values found in the Secrets section of this document.

  • SLACK_STANDUP_BOT_TOKEN
  • SLACK_STANDUP_SIGNING_SECRET

Deploy to Docker with the following command:

npm run serverless-localstack

This retrieves the local environment variables and creates secrets and a DynamoDB table in the Localstack instance.

Localstack runs on port 4566.

Script Permissions

Localstack is loaded with scripts in src/test/scripts. These may need updated permissions to execute.

chmod 755 src/test/scripts/*

Slack -> Locally running Lambda

To connect Slack to this running instance, start ngrok with either of these commands. This assumes ngrok is installed, and is a command in the user's path.

npm run ngrok

ngrok http 5000

This will create a URL to enter into Slack's Slash Command and Interactivity & Shortcuts interfaces for this app.

Querying DynamoDB

The context.ts file sets up some fake credentials, and we need these to query the DynamoDB instance using the aws cli.

This command will scan the local DynamoDB instance for all items the table local_STANDUP_STATUS.

AWS_ACCESS_KEY_ID=not-a-real-access-key-id AWS_SECRET_ACCESS_KEY=not-a-real-access-key aws dynamodb scan --table-name local_STANDUP_STATUS --region us-east-2 --endpoint-url http://localhost:4566

Costs

DynamoDB storage is within the free tier.

Secret storage is under $1, as is provisioned concurrency. Even with a warmer lambda, the amount of lambda calls doesn't exceed the free tier.

In practice, running this for a team is like $2 per month.

Known Issues

Scheduling a message after a Daylight Savings Time boundary will say it's scheduled at the time you selected, but show a different (correct) time on the home screen. It is scheduled at the time you selected, so it's just a formatting issue when the message is scheduled.

Lambda startup is slow and not within the 3 second Slack requirement. A warmer or provisioned concurrency can help with this.

Provisioned concurrency has unpredictable issues with fetching secrets during the init phase. (This is possibly related to this post: https://barker.tech/aws-lambda-nodejs-async-init-88b5c24af567) If the first request to the handler is > 5 minutes after the request for a secret, the lambda will be in a zombie state, able to accept requests but not handle them.

The last two issues above could be solved by running this on an EC2 instance, but that would require refactoring, a build pipeline for deployment, and would bring cost to maybe $8 per month.

Author

👤 Steve Thompson

Show your support

Give a ⭐️ if this project helped you!


This README was generated with ❤️ by readme-md-generator