# OpenSpec Change: enterprise-slack-client - **Change ID**: enterprise-slack-client - **Package**: `@suaveplan/slack-client` - **Category**: universal - **Target path**: `universal/social/slack-client` - **Status**: IN PROGRESS - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/slack-client.md` --- ## Summary Deliver `@suaveplan/slack-client` on the genesis branch from scratch at enterprise quality. The package provides a generic Slack API client: Web API method wrappers for messaging (`chat.postMessage`, `chat.update`, `chat.delete`), channel management (`conversations.*`), user info (`users.*`), file uploads, Block Kit message builder, Incoming Webhooks, Event subscription parsing with signature verification, slash-command payload parsing, interactive component payload handling, and a `SlackClient` facade. Injectable fetch and crypto; no Slack SDK dependency. Genesis adds structured errors, Zod schemas, OTel instrumentation, retry with circuit breaker, and `AbortSignal` cancellation. --- ## Current-state audit (genesis) The package does not exist on genesis yet — this is a fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | `SlackError`; `SLACK.*` error codes | | `@suaveplan/types` (`workspace:^`) | `LoggerLike`, `Clock` | | `@suaveplan/retry` (`workspace:^`) | Retry + circuit breaker for API calls | | `@suaveplan/crypto` (`workspace:^`) | HMAC-SHA256 request signature verification | | `zod` (`catalog:forms`) | Schema validation | | `@opentelemetry/api` (`catalog:observability`) | Spans + counters | Dev deps: `vitest`, `@vitest/coverage-istanbul`, `fast-check` (all `catalog:testing`). --- ## Public API surface ### `SlackClient` ```ts class SlackClient { constructor(options: SlackClientOptions) // Messaging postMessage(options: PostMessageOptions): Promise updateMessage(options: UpdateMessageOptions): Promise deleteMessage(channel: string, ts: string): Promise // Channels listConversations(options?: ListConversationsOptions): AsyncGenerator getConversationInfo(channel: string): Promise // Users getUserInfo(userId: string): Promise getUserByEmail(email: string): Promise // Files uploadFile(options: FileUploadOptions): Promise // Webhooks postToWebhook(url: string, payload: WebhookPayload): Promise } interface SlackClientOptions { token: string signingSecret?: string // for event verification retryOptions?: RetryOptions fetch?: typeof globalThis.fetch clock?: Clock logger?: LoggerLike } ``` ### Block Kit builder ```ts function createMessage(text: string): MessageBuilder interface MessageBuilder { section(text: string): MessageBuilder divider(): MessageBuilder image(url: string, altText: string): MessageBuilder actions(...elements: ActionElement[]): MessageBuilder context(...elements: ContextElement[]): MessageBuilder build(): SlackBlocks } ``` ### Event handling ```ts function verifySlackSignature( body: string, timestamp: string, signature: string, signingSecret: string, options?: { maxAgeSeconds?: number; clock?: Clock } ): boolean function parseSlackEvent(body: unknown): SlackEvent function parseSlashCommand(body: unknown): SlashCommand function parseInteractivePayload(body: unknown): InteractivePayload ``` ### Error codes ```ts type SlackErrorCode = | 'SLACK_AUTH_FAILED' | 'SLACK_API_ERROR' | 'SLACK_RATE_LIMITED' | 'SLACK_SIGNATURE_INVALID' | 'SLACK_CHANNEL_NOT_FOUND' | 'SLACK_USER_NOT_FOUND' | 'SLACK_ABORTED' ``` --- ## Genesis additions 1. **`SlackError`** extends `SuaveplanError` with seven stable codes. 2. **Zod schemas** for `PostMessageOptions`, `SlackEvent`, `SlashCommand`, `InteractivePayload`, `SlackChannel`, `SlackUser`, `SlackFile`. 3. **Rate-limit handling** — respects `Retry-After` header from Slack 429 responses; integrates with `@suaveplan/retry`. 4. **Circuit breaker** — wraps all API calls via `@suaveplan/retry` circuit breaker; opens after 5 consecutive failures. 5. **OTel instrumentation** — span `slack.api_call` with attribute `slack.method`; counter `slack.api_total`; histogram `slack.api_duration_ms`. 6. **Property-based tests** — Block Kit builder produces valid JSON structures for arbitrary sequences of builder calls. --- ## File layout ```text universal/social/slack-client/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts constants/ index.ts types/ common.ts common.md core/ slack-client/ slack-client.ts slack-client.md slack-client.types.ts slack-client.test.ts index.ts api-caller/ api-caller.ts api-caller.md api-caller.test.ts index.ts blocks/ message-builder/ message-builder.ts message-builder.md message-builder.test.ts index.ts events/ event-parser/ event-parser.ts event-parser.md event-parser.test.ts index.ts signature-verifier/ signature-verifier.ts signature-verifier.md signature-verifier.test.ts index.ts __benchmarks__/ slack-client.bench.ts tests/ integration.test.ts property.test.ts ``` --- ## Impact **Downstream consumers**: `@suaveplan/message-bridge`, `@suaveplan/notification-channel`. **Workspace dep prerequisites**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/retry`, `@suaveplan/crypto`.