nversary congratulates people on their work anniversary in Slack.
Anniversary messages are sent on working days only, with a maximum of 3 messages per day. If there are more than 3 anniversaries on nearby dates, they are spread out so that people with longer tenure get the message closest to their actual anniversary day.
How to set up and configure nversary
Build and package the Lambda artifact as a local zip file for Terraform to deploy.
The artifact is created by Task at:
build/dev/nversary.zipbuild/prod/nversary.zip
An AWS Account is required. If you don't have one, create it at https://aws.amazon.com/
People data is read from s3://$PEOPLE_S3_BUCKET/$PEOPLE_S3_KEY.
Expected shape:
{
"people": [
{
"fullName": "Example Person",
"email": "example.person@example.com",
"presence": [{ "start": "2018-02-01" }],
"position": "Senior Consultant",
"businessUnit": "Technology",
"profileImageUrl": "https://example.com/image.jpg",
"slackId": "U0123456789"
}
]
}Notes:
slackIdis optional but recommended; when present, nversary mentions that Slack user directly.- If
slackIdis missing, nversary falls back to matching Slack users byemail. profileImageUrlis optional.
- Go to https://api.slack.com/apps and click Create New App, give your app a name and attach it to a workspace.
- In OAuth & Permissions, add bot token scopes:
chat:writeusers:readusers:read.email
- Install the app to the workspace and save the Bot User OAuth Token.
- Invite bot to the target channel:
/invite @botname - Store credentials to AWS SSM Parameter Store as
SecureString.
The JSON in SSM Parameter Store looks similar to this:
{
"slack": {
"webhookUrl": "",
"appToken": "xoxb-32896343824-849329924324243-lkjrewrwXKhgkDkfobo4dore",
"channelId": "JO3KFSO5"
}
}webhookUrlis currently unused by the runtime (kept for backward compatibility with the existing config model).appTokenis Bot User OAuth Token from Features/OAuth & Permissions.channelIdis the identifier for channel where messages are sent. You can obtain this from Slack UI/Chat app.
nversary uses Terraform for deployment.
Terraform layout:
terraform/modules/nversary_notifierreusable moduleterraform/infra/envs/devdevelopment environment rootterraform/infra/envs/prodproduction environment rootterraform/remote-statebootstrap for Terraform backend state bucket
Both environments use an S3 backend (backend "s3" {}) configured in:
terraform/infra/envs/dev/backend.tfterraform/infra/envs/prod/backend.tf
Deployment values come from Terraform input variables and static values in terraform/infra/envs/*/main.tf:
nameandenvironmentruntimeandtimeoutpeople_s3_bucketandpeople_s3_key(pass at apply/plan time)ssm_parameter_name(pass at apply/plan time)artifact_file(local path to the Lambda zip)log_retention_days
Current environment scheduling:
dev: disabled schedule (cron(0 0 31 2 ? *))prod: daily at03:50 UTC(cron(50 3 * * ? *))
Slack send behavior is controlled by the Lambda environment variable SLACK_DRY_RUN.
dev: configurable at deploy time viaSLACK_DRY_RUN, defaults totrueprod: alwaysfalse(messages are always sent)
Examples:
# dev default (dry-run enabled)
task deploy:dev
# dev override (send real Slack messages)
SLACK_DRY_RUN=false task deploy:dev
# prod (always dry-run=false)
task deploy:prodInstall:
- Task
- Terraform (
>= 1.14.0) - Node.js + npm
Set required environment variables:
export PEOPLE_S3_BUCKET=your-people-bucket
export PEOPLE_S3_KEY=path/to/people.json
export SSM_PARAMETER_NAME=/path/to/slack-configPlan/apply for development:
task deploy:plan:dev
task deploy:devPlan/apply for production:
task deploy:plan:prod
task deploy:prodTask workflow does all of the following:
- validates required environment variables
- bootstraps Terraform remote state from
terraform/remote-state/main.tfif needed - packages Lambda artifact zip for the selected environment
- runs Terraform
init,plan, andapplyin the matching environment root
npm run testYou can test the Lambda function from AWS Lambda console by creating a test event with a dateString attribute.
The date string should be in yyyy-MM-dd format.
Setting sendNow to true, will send messages immediately. An example of test event:
{
"dateString": "2022-04-25",
"sendNow": true
}