Slack Bolt Middleware Pipeline Design Prompt
Architect a clean, testable middleware chain for a Bolt app — auth context, tenant resolution, rate limiting, error boundaries, and structured logging — so handlers stay thin and reusable.
- Target user
- Engineers structuring a growing Slack Bolt application
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT
The prompt
You are a backend engineer who has refactored a sprawling Slack Bolt app into a clean, layered middleware pipeline that new contributors can extend without fear. I will provide: - Our current Bolt app structure (or that we're greenfield) - The runtime (Bolt for JS or Python) and how it's deployed - The cross-cutting concerns we keep copy-pasting into handlers Your job: 1. **Middleware order** — define a canonical chain and explain why order matters: request logging → idempotency/dedup → signature verification (if not Bolt-native) → tenant/team resolution → user authorization → rate limiting → handler → error boundary. Show what `await next()` placement does at each stage. 2. **Global vs listener middleware** — when to register `app.use()` global middleware vs per-listener middleware, and how to short-circuit cleanly (ack + ephemeral "not authorized") without invoking the handler. 3. **Context enrichment** — populate `context` with resolved team config, user role, feature flags, and a request-scoped logger so handlers read `context.user.role` instead of re-fetching. 4. **Idempotency** — Slack retries on slow acks (the `X-Slack-Retry-Num` header). Add middleware that no-ops on duplicate event ids using a short-TTL store, and acks within 3 seconds before doing slow work. 5. **Error boundary** — a global error handler that classifies errors (user error → ephemeral message; platform error → log + generic apology; bug → alert channel), never leaking stack traces to users. 6. **Testability** — show how to unit-test a single middleware in isolation with a faked `next`, and how to assert short-circuit behavior. 7. **Observability** — structured logs with team id, user id, event type, latency, and outcome; one log line per request that a dashboard can aggregate. Output: (a) the ordered middleware diagram, (b) each middleware as a separate module with types, (c) the app wiring that registers them, (d) a unit test for the authorization middleware, (e) a thin example handler that relies entirely on enriched context. Bias toward: thin handlers, composable single-purpose middleware, fail-closed authorization, and acking fast.