Skip to main content

README.md

# SlackSandbox

A [Swoosh](https://hexdocs.pm/swoosh)-style local mailbox, but for Slack.

Point your app's Slack client at `SlackSandbox` in dev/test instead of the
real Slack API. Every `post_message/2` and `send_dm/2` call is captured
in-memory and pushed live to `SlackSandbox.InboxLive`, so you can watch
outbound messages arrive without a Slack workspace, webhook tunnel, or bot
token.

## Installation

```elixir
def deps do
  [
    {:slack_sandbox, "~> 0.1.0"}
  ]
end
```

## Setup

**1. Add the inbox to your supervision tree**, pointed at a PubSub already
running in your app:

```elixir
children = [
  MyApp.PubSub,
  {SlackSandbox.Inbox, pubsub: MyApp.PubSub},
  MyAppWeb.Endpoint
]
```

**2. Define a Slack adapter behaviour** in your app (or reuse
`SlackSandbox.Adapter`) and point it at `SlackSandbox` in dev:

```elixir
# config/dev.exs
config :my_app, :slack_adapter, SlackSandbox

# config/prod.exs
config :my_app, :slack_adapter, MyApp.Slack.HttpAdapter
```

```elixir
# wherever your app sends Slack messages
adapter = Application.fetch_env!(:my_app, :slack_adapter)
adapter.post_message("Deploy finished", "#ops")
```

**3. Mount the inbox page** in your router:

```elixir
live "/dev/slack-inbox", SlackSandbox.InboxLive
```

Visit `/dev/slack-inbox` and every captured message shows up in real time,
pushed over PubSub — no refresh needed. The "Clear" button resets the
inbox for everyone watching.

## Why not just log it?

Logs scroll past. A live inbox gives you a running list you can leave open
in a second tab while you click through the flow that triggers Slack
messages — the same workflow `Swoosh.Adapters.Local` gives you for email.

## Multiple inboxes / testing

`SlackSandbox.Inbox` is a plain GenServer — pass `name: nil` to start an
unregistered instance (handy in tests where you don't want a single shared
process across async cases):

```elixir
{:ok, inbox} = SlackSandbox.Inbox.start_link(pubsub: MyApp.PubSub, name: nil)
SlackSandbox.Inbox.push(%{type: :message, text: "hi", channel: "C1"}, inbox)
SlackSandbox.Inbox.list(inbox)
```

## License

MIT