# After-Hours Shift Manager — Setup Guide ## 1. Create a Slack App 1. Go to [api.slack.com/apps](https://api.slack.com/apps) → **Create New App** → **From scratch** 2. Name: `After-Hours Shift Manager`, pick your workspace 3. Under **OAuth & Permissions**, add these **Bot Token Scopes**: - `chat:write` — post messages to channels - `commands` — register slash commands - `chat:write.public` — post to channels the bot isn't in 4. Under **Slash Commands**, create a new command: - Command: `/oncall` - Request URL: `(fill in after deploy — see step 4)` - Short Description: `Manage after-hours on-call shifts` - Usage Hint: `[schedule | pick | drop | swap @person | register | roster | help]` 5. Under **Interactivity & Shortcuts**, toggle **ON**: - Request URL: same URL as the slash command (the `/slack/events` endpoint) 6. **Install to Workspace** — approve the permissions 7. Copy the **Bot User OAuth Token** (`xoxb-...`) and **Signing Secret** (under Basic Information) ## 2. Store Secrets in AWS Secrets Manager The stack reads these from Secrets Manager (the IAM roles grant `secretsmanager:GetSecretValue` on `afterhours-shift-manager/*`): ```bash # Slack aws secretsmanager create-secret \ --name afterhours-shift-manager/slack-bot-token \ --secret-string "xoxb-YOUR-BOT-TOKEN" aws secretsmanager create-secret \ --name afterhours-shift-manager/slack-signing-secret \ --secret-string "YOUR-SIGNING-SECRET" # 3CX Queue XAPI (used by roster-sync and ring-scheduler) aws secretsmanager create-secret \ --name afterhours-shift-manager/3cx-domain \ --secret-string "yourcompany.3cx.us" aws secretsmanager create-secret \ --name afterhours-shift-manager/3cx-client-id \ --secret-string "YOUR-3CX-CLIENT-ID" aws secretsmanager create-secret \ --name afterhours-shift-manager/3cx-client-secret \ --secret-string "YOUR-3CX-CLIENT-SECRET" # Roster HTTP API bearer token (plain string). Duplicate the same value into # seahaven-prod as paychex-integrations/afterhours-roster-token. Generate the # token into a temp file, pass --secret-string file://..., then delete the file. # Never paste the value into chat, Terraform, or a PR. aws secretsmanager create-secret \ --name afterhours-shift-manager/roster-api-token \ --secret-string file://./roster-api-token.tmp ``` Create `afterhours-shift-manager/roster-api-token` **before** the first deploy that includes `afterhours-roster-api`, or live PUT/DELETE calls return 503. Rotation is coordinated: write the new value to both the mgmt secret and the prod copy, then recycle `afterhours-roster-api` so cached execution environments pick it up. Updating only one copy causes 401s. The identity processor `AFTERHOURS_BASE_URL` is the stack output `AfterhoursApiBaseUrl` (origin only, no `/mgmt` or `/roster` suffix). Leave that URL empty until the API is live and smoke-tested. Daily roster-sync still removes DynamoDB rows that are not in the 3CX `DEFAULT` group. Hire stays safe because 3CX create lands the extension in that group before the identity processor PUTs `/roster`. > The Slack **channel ID** is not a secret — it's passed as the `ShiftChannel` > deploy parameter in step 3, not stored in Secrets Manager or SSM. ## 3. Deploy the Stack ```bash # Build and deploy. ShiftChannel is the Slack channel ID for schedule posts # (right-click the channel in Slack → Copy link → the ID is the last segment). sam build sam deploy --guided \ --stack-name afterhours-shift-manager \ --region us-east-1 \ --parameter-overrides ShiftChannel=C0XXXXXXX QueueNumber=801 # Note SlackBotApiUrl (Slack Request URL) and AfterhoursApiBaseUrl # (paychex AFTERHOURS_BASE_URL origin). ``` ## 4. Set the Slack Request URL After deploy, copy the `SlackBotApiUrl` from the SAM output. Go back to your Slack app settings: - **Slash Commands** → edit `/oncall` → set **Request URL** to the output URL - **Interactivity & Shortcuts** → set **Request URL** to the same URL ## 5. Seed the Schedule ```bash python scripts/seed_schedule.py ``` This populates the DynamoDB table with the employee roster and default weekly schedule. ## 6. Invite the Bot & Register Users 1. Create a channel (e.g. `#after-hours-shifts`) and invite the bot: `/invite @After-Hours Shift Manager` 2. Each employee links their Slack account by running: ``` /oncall register 114 ``` (using their own extension number) ## 7. Update the 3CX Scheduler (optional) To have the 3CX scheduler read overrides from DynamoDB (so Slack-driven changes apply to future dates automatically), deploy the updated 3CX scheduler from the `feature/dynamodb-shift-integration` branch. See that branch's changes for details. Without this step, the Slack bot still works — it invokes the 3CX scheduler Lambda directly for same-day changes. Future-date overrides would only take effect if the scheduler reads DynamoDB. ## Commands Reference | Command | Description | |---|---| | `/oncall` | Show this week's schedule | | `/oncall next` | Show next week's schedule | | `/oncall pick ` | Pick up a shift | | `/oncall drop ` | Drop your shift (marks it open) | | `/oncall swap @person` | Hand your shift to someone else | | `/oncall register ` | Link your Slack to your extension | | `/oncall roster` | Show all employees and their link status | | `/oncall help` | Show help | Dates can be: `today`, `tomorrow`, `monday`–`sunday`, `4/5`, `2026-04-05`