AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Description: After-Hours Shift Manager — Slack bot for managing on-call shifts with 3CX integration Parameters: Timezone: Type: String Default: "America/New_York" SchedulerFunctionName: Type: String Default: "3cx-ring-group-scheduler" Description: Name of the existing 3CX ring group scheduler Lambda Globals: Function: Runtime: python3.12 Timeout: 30 MemorySize: 1024 Resources: # --- DynamoDB --- ShiftTable: Type: AWS::DynamoDB::Table Properties: TableName: afterhours-shifts BillingMode: PAY_PER_REQUEST AttributeDefinitions: - AttributeName: PK AttributeType: S - AttributeName: SK AttributeType: S KeySchema: - AttributeName: PK KeyType: HASH - AttributeName: SK KeyType: RANGE # --- Slack Bot Lambda --- SlackBotFunction: Type: AWS::Serverless::Function Properties: FunctionName: afterhours-shift-manager Handler: src/handler.handler CodeUri: . Environment: Variables: SHIFT_TABLE: !Ref ShiftTable SLACK_BOT_TOKEN_PARAM: /afterhours-shift-manager/slack-bot-token SLACK_SIGNING_SECRET_PARAM: /afterhours-shift-manager/slack-signing-secret SCHEDULER_FUNCTION_NAME: !Ref SchedulerFunctionName TZ: !Ref Timezone Policies: - DynamoDBCrudPolicy: TableName: !Ref ShiftTable - Statement: - Effect: Allow Action: - ssm:GetParameter Resource: - !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/afterhours-shift-manager/*" - Effect: Allow Action: - kms:Decrypt Resource: "*" Condition: StringEquals: "kms:ViaService": !Sub "ssm.${AWS::Region}.amazonaws.com" - Effect: Allow Action: - lambda:InvokeFunction Resource: - !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${SchedulerFunctionName}" Events: SlackEvents: Type: HttpApi Properties: Path: /slack/events Method: POST # --- Weekly Schedule Post (Monday 7am ET) --- WeeklyPostFunction: Type: AWS::Serverless::Function Properties: FunctionName: afterhours-weekly-post Handler: src/weekly_post.handler CodeUri: . Environment: Variables: SHIFT_TABLE: !Ref ShiftTable SLACK_BOT_TOKEN_PARAM: /afterhours-shift-manager/slack-bot-token SHIFT_CHANNEL_PARAM: /afterhours-shift-manager/channel-id TZ: !Ref Timezone Policies: - DynamoDBReadPolicy: TableName: !Ref ShiftTable - Statement: - Effect: Allow Action: - ssm:GetParameter Resource: - !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/afterhours-shift-manager/*" - Effect: Allow Action: - kms:Decrypt Resource: "*" Condition: StringEquals: "kms:ViaService": !Sub "ssm.${AWS::Region}.amazonaws.com" Events: # EST: 7am ET = 12:00 UTC (Nov-Mar) WeeklyPostEST: Type: Schedule Properties: Schedule: cron(0 12 ? * MON *) Description: "Post weekly schedule Monday 7am EST" Enabled: true # EDT: 7am ET = 11:00 UTC (Mar-Nov) WeeklyPostEDT: Type: Schedule Properties: Schedule: cron(0 11 ? * MON *) Description: "Post weekly schedule Monday 7am EDT" Enabled: true Outputs: SlackBotApiUrl: Description: URL for Slack app Request URL configuration Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/slack/events" ShiftTableName: Value: !Ref ShiftTable SlackBotFunctionArn: Value: !GetAtt SlackBotFunction.Arn