197 lines
11 KiB
Markdown
197 lines
11 KiB
Markdown
# Seahaven Slack Bot — Alex
|
|
|
|

|
|

|
|

|
|

|
|
|
|
Internal Slack assistant for Sea Haven Industries, powered by AWS Bedrock. Employees can DM Alex or @mention Alex in any channel to ask about vendors, payments, work orders, purchase orders, Amazon sites, company policies, and more.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Slack (WebSocket)
|
|
│
|
|
▼
|
|
ECS Fargate (Socket Mode) ← persistent WebSocket connection to Slack
|
|
│
|
|
├── DM (message.im) ──────────────────┐
|
|
├── @mention (app_mention) ────────────┤
|
|
│ async invoke
|
|
│ ▼
|
|
│ slack-processor Lambda ← calls Bedrock Agent, logs to DynamoDB, posts reply
|
|
│ │
|
|
│ ▼
|
|
│ Bedrock Agent — Alex (Claude Sonnet 4.5)
|
|
│ ├── Knowledge Base (AOSS + S3)
|
|
│ ├── QBO_Lookup action group ← QuickBooks vendor search (VPC, static IP)
|
|
│ ├── Google_Maps_Lookup action group ← fallback vendor search
|
|
│ └── WO_PO_Lookup action group ← WO, PO, site, and payment lookups (DynamoDB direct)
|
|
│
|
|
└── App Home opened ──────────────────→ app-home Lambda ← publishes Block Kit capabilities view
|
|
|
|
API Gateway (bot.seahaven.com)
|
|
│
|
|
└── GET /qbo/*
|
|
▼
|
|
qbo-oauth Lambda (VPC, static IP) ← OAuth 2.0 connect/callback/disconnect/launch
|
|
Outbound IP: 52.202.83.13 (NAT Gateway in seahaven-vpc)
|
|
|
|
EventBridge (daily 02:00 UTC)
|
|
│
|
|
├── notion-sync Lambda ← exports Office Operations Notion pages → S3 → KB ingestion
|
|
├── po-sync Lambda ← exports purchase-orders DynamoDB → S3 → KB ingestion
|
|
└── workorder-sync Lambda ← exports WorkOrders + Comments DynamoDB → S3 → KB ingestion
|
|
```
|
|
|
|
### What Alex Can Do
|
|
|
|
- **Vendor Lookup** — search QBO for existing vendors, KB for approved lists, Google Maps for new options
|
|
- **Payment & Invoice Status** — check if a vendor has been paid, if an invoice is scheduled, look up by check number
|
|
- **Work Order Lookups** — status, assignments, comments, and full history by WO number
|
|
- **Purchase Order Lookups** — status, line items, supplier, and ship-to details by PO number
|
|
- **Site Lookups** — Amazon facility address and details by site code, or list all sites in a state
|
|
- **Company Policies & SOPs** — employee handbook, SA8000 compliance, and operational procedures
|
|
|
|
### Vendor Query Priority
|
|
1. **QBO** — existing vetted vendors in QuickBooks Online
|
|
2. **Knowledge Base** — approved vendor lists in internal docs
|
|
3. **Google Maps** — fallback for net-new vendor discovery
|
|
|
|
## Stack
|
|
|
|
| Resource | Details |
|
|
|---|---|
|
|
| AWS Account | 328440206208, us-east-1 |
|
|
| CDK | TypeScript, v2 |
|
|
| LLM | Claude Sonnet 4.5 (`anthropic.claude-sonnet-4-5-20250929-v1:0`) |
|
|
| Embeddings | Amazon Titan Embed Text V2 (1024 dimensions) |
|
|
| Vector Store | OpenSearch Serverless (VECTORSEARCH) |
|
|
| Socket Mode | ECS Fargate (`seahaven-socket-mode`) — persistent WebSocket to Slack |
|
|
| Conversation Log | DynamoDB `seahaven-conversations` (90-day TTL) |
|
|
| Unanswered Questions | DynamoDB `seahaven-unanswered-questions` (180-day TTL) |
|
|
| Payment Data | DynamoDB `PaymentsDashboard` (via payments-dashboard) |
|
|
| PO Data Source | DynamoDB `purchase-orders` (read-only; owned by procurement-ingest / po-ingest) |
|
|
| Work Order Data Source | DynamoDB `WorkOrders` + `WorkOrderComments` (via workorder-ingest) |
|
|
| Site Assignments | DynamoDB `verified-sites` (auto-populated via po-ingest Streams pipeline) |
|
|
| VPC | `seahaven-vpc` (`vpc-0d3d4b67bd0cf8a68`) — QBO Lambdas + Socket Mode |
|
|
| Static Outbound IP | `52.202.83.13` (NAT Gateway for Intuit IP allowlist) |
|
|
| QBO OAuth URLs | `bot.seahaven.com/qbo/connect`, `/qbo/callback`, `/qbo/disconnect`, `/qbo/launch` |
|
|
|
|
### Shared Resources
|
|
|
|
This bot reads the `purchase-orders` DynamoDB table **read-only** (via the `po-sync` and `wo-po-lookup` Lambdas, both granted `grantReadData`). The table is owned by the `procurement-ingest` repo (`po-ingest` stack), which is the sole authoritative writer. Any change to the `purchase-orders` schema must be coordinated with `procurement-ingest` (owner) and `payments-dashboard` (the other read-only consumer).
|
|
|
|
## Prerequisites
|
|
|
|
- Node.js 22+
|
|
- AWS CDK (`npm install -g aws-cdk`)
|
|
- Docker Desktop (required for Lambda bundling and Socket Mode container build)
|
|
- AWS credentials configured locally
|
|
|
|
## Secrets Manager
|
|
|
|
These secrets must exist before deploying. The Slack, QBO, Maps, and app-level token secrets must be created manually before first deploy. The Notion secret is created automatically by CDK with a placeholder.
|
|
|
|
| Secret Name | Created | Structure |
|
|
|---|---|---|
|
|
| `seahaven/slack/credentials` | Manual (pre-deploy) | `{ "botToken": "xoxb-...", "signingSecret": "..." }` |
|
|
| `seahaven/slack/app-level-token` | Manual (pre-deploy) | Plaintext `xapp-...` token with `connections:write` scope |
|
|
| `seahaven/qbo/oauth` | Manual (pre-deploy) | `{ "clientId": "", "clientSecret": "", "refreshToken": "", "realmId": "" }` |
|
|
| `seahaven/google/maps-api-key` | Manual (pre-deploy) | `{ "apiKey": "" }` |
|
|
| `seahaven/notion/api-key` | Auto (CDK) | `{ "apiKey": "secret_..." }` |
|
|
|
|
## Deployment
|
|
|
|
```bash
|
|
npm install
|
|
npx cdk bootstrap aws://328440206208/us-east-1 # first time only
|
|
npx cdk deploy
|
|
```
|
|
|
|
The deploy takes ~15 minutes on first run. The AOSS collection, vector index creation, and Docker image build are the slow steps.
|
|
|
|
Stack outputs after deploy:
|
|
- `KBDocsBucketName` — S3 bucket to upload knowledge base documents
|
|
- `AgentId` — Bedrock Agent ID (Alex)
|
|
|
|
## Post-Deployment Setup
|
|
|
|
### 1. Upload knowledge base documents
|
|
|
|
Upload SA8000 compliance docs, SOPs, and the employee handbook to the S3 bucket printed in stack outputs.
|
|
|
|
```bash
|
|
aws s3 cp ./your-docs/ s3://<KBDocsBucketName>/ --recursive
|
|
```
|
|
|
|
### 2. Trigger KB sync
|
|
|
|
```bash
|
|
aws bedrock-agent start-ingestion-job \
|
|
--knowledge-base-id <from Bedrock console> \
|
|
--data-source-id <DataSourceId> \
|
|
--region us-east-1
|
|
```
|
|
|
|
### 3. Configure Notion sync
|
|
|
|
1. Create a Notion internal integration at **Settings → Connections → Develop or manage integrations**
|
|
2. Name it `seahaven-office-ops` and associate it with the **Office Operations** teamspace
|
|
3. Copy the integration token and update: **Secrets Manager → `seahaven/notion/api-key` → Edit**
|
|
|
|
### 4. Configure Slack app
|
|
|
|
In the [Slack API dashboard](https://api.slack.com/apps):
|
|
|
|
1. **Basic Information** → update Display Name to "Alex", upload avatar
|
|
2. **Socket Mode** → enable, generate app-level token with `connections:write` scope
|
|
3. Store the app-level token in Secrets Manager as `seahaven/slack/app-level-token`
|
|
4. **Event Subscriptions** → enable (no Request URL needed with Socket Mode)
|
|
5. Subscribe to bot events: `message.im`, `app_mention`, `app_home_opened`
|
|
6. **OAuth & Permissions** → Bot Token Scopes: `chat:write`, `im:history`, `app_mentions:read`, `channels:history`, `groups:history`
|
|
7. **App Home** → enable Home Tab and Messages Tab
|
|
8. Reinstall app to workspace
|
|
9. Invite Alex to channels: `/invite @Alex`
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
bin/
|
|
seahaven-slack-bot.ts CDK app entry point
|
|
lib/
|
|
seahaven-slack-bot-stack.ts Main stack
|
|
constructs/
|
|
knowledge-base.ts Bedrock KB + AOSS + S3 (via @cdklabs L2 construct)
|
|
bedrock-agent.ts Alex — Bedrock Agent + QBO/Maps/WO-PO-Site-Payment action groups
|
|
slack-handler.ts Processor Lambda + App Home Lambda + QBO OAuth + API Gateway
|
|
socket-mode.ts ECS Fargate service running Slack Socket Mode client
|
|
conversation-log.ts DynamoDB conversation + unanswered questions tables
|
|
notion-sync.ts EventBridge daily cron + notion-sync Lambda
|
|
po-sync.ts EventBridge daily cron + po-sync Lambda
|
|
workorder-sync.ts EventBridge daily cron + workorder-sync Lambda
|
|
services/
|
|
socket-mode/ Socket Mode ECS service (Dockerfile, TypeScript, @slack/socket-mode)
|
|
lambda/
|
|
slack-processor/ Calls agent, writes DynamoDB, posts Slack reply
|
|
app-home/ Publishes Block Kit capabilities view to App Home tab
|
|
qbo-oauth/ OAuth 2.0 connect/callback/disconnect/launch for QuickBooks
|
|
qbo-lookup/ Bedrock action group — QuickBooks vendor search
|
|
maps-lookup/ Bedrock action group — Google Maps Places search
|
|
wo-po-lookup/ Bedrock action group — WO, PO, site, and payment lookups (DynamoDB direct)
|
|
notion-sync/ Daily Notion → S3 export, triggers KB ingestion
|
|
po-sync/ Daily purchase-orders DynamoDB → S3 export, triggers KB ingestion
|
|
workorder-sync/ Daily WorkOrders DynamoDB → S3 export, triggers KB ingestion
|
|
scripts/
|
|
create-aoss-index.ts Manual fallback for AOSS index creation (not needed in normal deploy)
|
|
```
|
|
|
|
## Known Maintenance Items
|
|
|
|
- **QBO OAuth** — the refresh token auto-rotates on every API call (persisted back to Secrets Manager). If the token ever expires (100 days of inactivity), reconnect via `https://bot.seahaven.com/qbo/connect`.
|
|
- **Notion sync** runs daily at 02:00 UTC automatically. Manual trigger: invoke `seahaven-notion-sync`.
|
|
- **PO sync** runs daily at 02:00 UTC. Scans `purchase-orders` DynamoDB table (from [po-ingest](https://github.com/Sea-Haven-Industries/po-ingest)). Manual trigger: invoke `seahaven-po-sync`.
|
|
- **Work order sync** runs daily at 02:00 UTC. Scans `WorkOrders` and `WorkOrderComments` (from [workorder-ingest](https://github.com/Sea-Haven-Industries/workorder-ingest)). Manual trigger: invoke `seahaven-workorder-sync`.
|
|
- **Site assignments** are auto-populated from the `verified-sites` DynamoDB table, maintained by the po-ingest DynamoDB Streams pipeline. No manual seeding required.
|
|
- **Unanswered questions** are logged to `seahaven-unanswered-questions` when Alex detects it couldn't answer a question. Review via DynamoDB console — records have `status: "pending"` and 180-day TTL.
|
|
- **Socket Mode** — the ECS Fargate task maintains a persistent WebSocket connection to Slack. Monitor via CloudWatch Logs (`socket-mode` log stream). The service auto-restarts on failure.
|