mirror of
https://github.com/Sea-Haven-Industries/expense-approval-bot.git
synced 2026-05-18 20:20:14 +00:00
63 lines
2.6 KiB
Markdown
63 lines
2.6 KiB
Markdown
# Expense Approval Bot
|
|
|
|
Slack reaction-driven expense approval router. Replaces the Pipedream `expenses_pipeline` workflow.
|
|
|
|
## Flow
|
|
|
|
A user reacts ✅ to a message in an expense channel. The bot:
|
|
|
|
1. Maps the source channel to the next stage's channel.
|
|
2. Copies the message text (stripped of any prior "react to advance" hint) into the next channel, with a permalink back to the original on the first advance.
|
|
3. Replies in-thread on the original message with `➡️ Advanced to {Stage}`.
|
|
|
|
Channel chain: Submitted → Processed → Authorized → Matched.
|
|
|
|
## Architecture
|
|
|
|
- **Receiver Lambda** (`src/receiver/`) — fronted by API Gateway HTTP API. Verifies the Slack request signature, handles the URL-verification handshake, and async-invokes the processor. Returns 200 within Slack's 3-second window to prevent retries.
|
|
- **Processor Lambda** (`src/processor/`) — does the 5-step sequence of Slack API calls. No inbound HTTP; invoked only by the receiver.
|
|
- **Secrets** — Slack bot token and signing secret each stored as separate AWS Secrets Manager secrets. Each Lambda only has IAM access to the secret it needs.
|
|
|
|
Runtime: Python 3.12 on arm64, no third-party dependencies (stdlib `urllib` for HTTP, `boto3` from the Lambda runtime).
|
|
|
|
## Setup
|
|
|
|
1. Store the two Slack credentials in Secrets Manager:
|
|
```bash
|
|
aws secretsmanager create-secret \
|
|
--name expense-bot-slack-token \
|
|
--secret-string "xoxb-..."
|
|
|
|
aws secretsmanager create-secret \
|
|
--name expense-bot-slack-signing-secret \
|
|
--secret-string "..."
|
|
```
|
|
|
|
2. Copy the sample SAM config and fill in real values:
|
|
```bash
|
|
cp samconfig.toml.example samconfig.toml
|
|
```
|
|
- `SlackBotTokenSecretArn` — ARN of the bot-token secret
|
|
- `SlackSigningSecretArn` — ARN of the signing-secret secret
|
|
|
|
3. Build and deploy:
|
|
```bash
|
|
sam build && sam deploy
|
|
```
|
|
|
|
4. After the first deploy, take the `SlackEventsUrl` output and paste it into the Slack app's **Event Subscriptions → Request URL**. Subscribe the bot to the `reaction_added` event.
|
|
|
|
## Configuration
|
|
|
|
The channel → stage mapping lives in `src/processor/app.py` (`STAGES`). Update there if channels change. The "on first advance, include a permalink" check is keyed on the Processed-stage channel ID — update that too if the first-stage channel changes.
|
|
|
|
## Manual testing
|
|
|
|
Invoke the processor directly with a synthetic Slack reaction event:
|
|
|
|
```bash
|
|
aws lambda invoke \
|
|
--function-name expense-approval-processor \
|
|
--payload '{"reaction":"white_check_mark","item":{"channel":"C0AQ2AWLNEN","ts":"1700000000.000000"}}' \
|
|
/dev/stdout
|
|
```
|