2026-04-03 18:32:32 -04:00
# After-Hours Shift Manager
2026-05-12 16:23:24 -04:00
Slack bot for managing after-hours on-call shifts at Sea Haven Industries. Employees can pick up, drop, and swap shifts directly from Slack. Changes automatically update 3CX queue routing via the integrated ring scheduler.
2026-04-03 18:32:32 -04:00
## How It Works
2026-05-12 16:23:24 -04:00
A recurring weekly schedule assigns employees to after-hours phone duty. Weekend shifts are split into Day (8am-5pm) and Night (5pm-8am). Any unassigned shift shows as **Available** in Slack with a pickup button. When someone picks up or drops a shift for today, the 3CX queue is updated immediately. Future changes take effect when the ring scheduler runs at 8am daily and 5pm on weekends.
2026-05-12 15:51:21 -04:00
The weekly schedule post is updated live when shifts change, and the previous week's post is automatically deleted when the new one goes out.
2026-04-03 18:32:32 -04:00
## Slack Commands
| Command | Description |
|---|---|
| `/oncall` | Show this week's schedule |
| `/oncall next` | Show next week's schedule |
| `/oncall pick <date>` | Pick up an available shift |
| `/oncall drop <date>` | Drop your shift (marks it available) |
| `/oncall swap <date> @person` | Hand your shift to someone else |
| `/oncall register <ext>` | Link your Slack account to your phone extension |
| `/oncall roster` | Show all employees and their link status |
2026-05-01 16:32:50 -04:00
| `/oncall pay` | Show last week's bonus pay summary |
| `/oncall rate` | Show current shift pay rates |
| `/oncall rate default <amount>` | Set the default per-shift rate |
| `/oncall rate <ext> <amount>` | Set a per-person shift rate |
2026-04-03 18:32:32 -04:00
| `/oncall help` | Show help |
2026-05-12 15:51:21 -04:00
### Admin Commands
Available to users listed in `admin_users` in the CONFIG record:
| Command | Description |
|---|---|
| `/oncall admin override <date> <ext>` | Assign a shift to an extension |
| `/oncall admin open <date>` | Mark a shift as open |
| `/oncall admin clear <date>` | Remove override (revert to weekly) |
| `/oncall admin roster add <ext> <name>` | Add an employee to the roster |
| `/oncall admin roster remove <ext>` | Remove an employee |
| `/oncall admin roster rename <ext> <name>` | Rename an employee |
2026-04-03 18:32:32 -04:00
Dates accept: `today` , `tomorrow` , `monday` -`sunday` , `4/5` , `2026-04-05`
## Architecture
2026-05-12 15:51:21 -04:00
- **Runtime**: Python 3.12 on AWS Lambda (arm64)
2026-04-03 18:32:32 -04:00
- **Data**: DynamoDB single-table (`afterhours-shifts` )
2026-05-12 15:51:21 -04:00
- **IaC**: AWS SAM (`template.yaml` ) with shared Lambda Layer
2026-04-03 18:32:32 -04:00
- **Slack**: Slack Bolt framework with `/oncall` slash command
2026-05-12 16:23:24 -04:00
- **3CX Integration**: Queue routing updated directly via 3CX Queue XAPI
2026-05-12 15:51:21 -04:00
- **Secrets**: AWS Secrets Manager (`afterhours-shift-manager/*` )
### Lambda Functions
| Function | Trigger | Purpose |
|---|---|---|
| `afterhours-shift-manager` | API Gateway (POST /slack/events) | Slack bot — handles `/oncall` commands and interactive buttons |
| `afterhours-weekly-post` | EventBridge (Monday 7am ET) | Posts weekly schedule to Slack, sends pay report email |
| `afterhours-roster-sync` | EventBridge (daily 6am ET) | Syncs employee roster from 3CX |
2026-05-12 16:23:24 -04:00
| `afterhours-ring-scheduler` | EventBridge (daily 8am ET + weekend 5pm ET) | Updates 3CX queue routing based on who's on shift |
2026-05-12 15:51:21 -04:00
### Project Layout
```
src/
slack-bot/ Slack Bolt Lambda (handler + app)
weekly-post/ Monday schedule + pay post
roster-sync/ Daily 3CX roster sync
2026-05-12 16:23:24 -04:00
ring-scheduler/ 3CX queue routing updates
2026-05-12 15:51:21 -04:00
shared/ Lambda Layer (schedule, blocks, 3CX client, secrets)
```
2026-04-03 18:32:32 -04:00
### DynamoDB Schema
Single table with `PK` / `SK` keys:
| PK | SK | Description |
|---|---|---|
| `ROSTER` | `<extension>` | Employee: name, extension, slack_user_id |
| `WEEKLY` | `<DayName>` | Default weekly schedule: extension, name |
| `OVERRIDE` | `<YYYY-MM-DD>` | Date override from pickup/drop (or `OPEN` ) |
2026-05-12 15:51:21 -04:00
| `SCHEDULE_POST` | `<channel_id>` | Current schedule message timestamp |
2026-05-01 16:32:50 -04:00
| `PAY` | `<YYYY-MM-DD>` | Weekly pay record (Monday date key) |
2026-05-12 15:51:21 -04:00
| `CONFIG` | `CONFIG` | Settings: shift_rate, fallback_extension, admin_users |
### Secrets Manager
| Secret | Description |
|---|---|
| `afterhours-shift-manager/slack-bot-token` | Slack bot OAuth token (`xoxb-...` ) |
| `afterhours-shift-manager/slack-signing-secret` | Slack app signing secret |
| `afterhours-shift-manager/3cx-domain` | 3CX FQDN (e.g. `company.3cx.us` ) |
| `afterhours-shift-manager/3cx-client-id` | 3CX OAuth2 client ID |
| `afterhours-shift-manager/3cx-client-secret` | 3CX OAuth2 client secret |
2026-04-03 18:32:32 -04:00
## Deployment
2026-05-12 15:51:21 -04:00
Merges to `main` are automatically deployed via **GitHub Actions** using reusable SAM workflows from the Sea Haven org.
2026-04-03 18:32:32 -04:00
2026-05-01 16:32:50 -04:00
For manual deploys:
2026-04-03 18:32:32 -04:00
```bash
sam build
2026-05-01 16:32:50 -04:00
sam deploy
2026-04-03 18:32:32 -04:00
```
2026-05-01 16:32:50 -04:00
See [SETUP.md ](SETUP.md ) for full deployment and Slack app creation instructions.