* feat(roster): add Bearer PUT/DELETE roster API
Identity hire needs to write Slack IDs onto roster rows without a stale
daily 3CX sync clearing them, using the existing HTTP client contract.
* fix(roster): strip Secrets Manager token whitespace
A file:// secret commonly includes a trailing newline, so compare_digest
must strip the cached value the same way it strips the Bearer header.
SETUP.md step 2 told operators to store the Slack token/signing secret in
SSM Parameter Store, which (a) violates the secrets-and-config handbook
(API tokens/signing values must live in Secrets Manager) and (b) contradicts
the IaC — the stack reads Secrets Manager and the IAM roles only grant
secretsmanager:GetSecretValue on afterhours-shift-manager/*, so following the
old instructions would break the deploy.
- Section 2 now uses `aws secretsmanager create-secret` for all five secrets
(slack-bot-token, slack-signing-secret, 3cx-domain/client-id/client-secret) —
the 3CX secrets were also previously undocumented.
- The Slack channel ID is not a secret; documented as the `ShiftChannel` deploy
parameter (--parameter-overrides) instead of an SSM SecureString.
Addresses violation 2 of #68.
Slack Bolt app on Lambda for managing on-call shifts. Employees can
pick up, drop, and swap shifts via /oncall commands. Changes update
3CX ring group 800 routing in real time for same-day shifts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>