apm-wo-analysis/slack/manifest.yaml
Adam Moussa c3a2c936d1 Add Slack post + interactions Lambdas with drill-down modals (Phase 4)
Two push surfaces (no App Home) + interactive drill-down, per CLAUDE.md.

Block Kit (blockkit.py, pure/offline): build_daily_summary (header, vs-yesterday
deltas, escalation breakdown with 3rd highlighted, action/routine, top sites,
mismatch callout, category drill buttons + 📊 Open dashboard link, footer),
build_escalation_alert (one @here, returns None on zero-3rd — suppression), and
build_wo_modal (views.open payload, capped under Slack's 100-block limit).

Lambdas: slack_post/handler.py (classifier-invoked: read today/yesterday
summary.json, post daily summary, conditionally post the batched alert from
details.json) and slack_post/interactions.py (API Gateway: verify Slack
signature, filter details.json, views.open the WO modal within the 3s trigger_id
window). slackio.py centralizes Secrets Manager creds, the SSM dashboard URL,
signature verification, and analytics/ reads — keeping blockkit pure.

Classifier: emit analytics/dt=*/details.json (per-WO index for the modals) and
async-invoke slack-post after the snapshot write (best-effort; a Slack failure
never fails classification).

CDK: slack-post + interactions Lambdas (Docker-bundled slack_sdk), HTTP API on
apm-wo.seahaven.com (wildcard ACM cert + Route53 alias; signature-verified, so
the route is unauthenticated by design), SSM /apm-wo-analysis/grafana-base-url,
and scoped IAM (read analytics/, read the Slack secret + dashboard param;
classifier granted lambda:InvokeFunction on slack-post). Slack creds live in one
Secrets Manager secret apm-wo-analysis/slack-credentials {botToken, signingSecret,
channelId}; cdk.json gains cert/zone/domain context.

WO drill-downs link to Grafana only — no APM deep-links (per decision).

Deliverables for test time: slack/manifest.yaml (app manifest, interactivity
request_url = apm-wo.seahaven.com).

Tests: tests/test_blockkit.py (30 offline cases — deltas, zero-3rd None, <100
blocks under large inputs, modal truncation/overflow, dashboard URL) and Phase 4
assertions in test_pipeline_synth.py (both Lambdas, the API route/domain/alias,
and no broad/write IAM on the Slack roles). 49/49 tests pass; cdk synth green.
2026-05-28 17:48:51 -04:00

41 lines
1.3 KiB
YAML

# Slack app manifest for "APM Work Orders".
#
# IMPORTANT: The request_url host (apm-wo.seahaven.com) must match the deployed
# API Gateway custom domain. If the domain changes, update interactivity.request_url
# here and redeploy the app via the Slack API or the App Configuration page.
#
# The bot user must be invited to the WO channel before it can post:
# /invite @APM Work Orders
#
# To apply this manifest: Slack App Configuration -> "App Manifest" tab -> paste.
_metadata:
major_version: 1
minor_version: 1
display_information:
name: APM Work Orders
description: Daily APM work-order analysis — escalation alerts and summary posts for Sea Haven facility ops.
background_color: "#1a1a2e"
features:
bot_user:
display_name: APM Work Orders
always_online: true
oauth_config:
scopes:
bot:
- chat:write
# chat:write.public allows posting to public channels without an explicit
# /invite. Remove if the WO channel is private and an invite is preferred.
- chat:write.public
settings:
interactivity:
is_enabled: true
# Handler for drill-category buttons and modal opens.
request_url: https://apm-wo.seahaven.com/slack/interactions
org_deploy_enabled: false
socket_mode_enabled: false
token_rotation_enabled: false