This guide is the canonical path from adding Chimeway as a dependency to your first explainable notification trace. Follow it when you want one credible vertical slice: install schema, configure the library, trigger a notification, and prove why it sent (or was suppressed) with Chimeway.Traces.explain_delivery/1.

For detailed install steps, see Installation. For inbox and channel depth after this slice, see Getting Started.

1. Add the dependency

Add Chimeway to your mix.exs:

def deps do
  [
    {:chimeway, "~> 1.1"}
  ]
end

Then fetch dependencies:

mix deps.get

2. Install database schema

Chimeway stores the durable lifecycle spine (eventnotificationdeliveryattempt) in your database. Generate and run migrations:

mix chimeway.gen.migrations
mix ecto.migrate

For more detail on migration generation, see Installation §2.

3. Configure Chimeway

You need two configuration pieces: one for the installer task and one for runtime queries.

Installer (migration generator):

config :chimeway,
  repo: MyApp.Repo

Replace MyApp.Repo with your host application's Ecto repo module. This tells mix chimeway.gen.migrations where to copy migration files.

Runtime (Chimeway.Repo):

config :chimeway, Chimeway.Repo,
  username: "postgres",
  password: "postgres",
  hostname: "localhost",
  database: "my_app_dev",
  pool_size: 10

At runtime, Chimeway queries through Chimeway.Repo. Configure it to use the same database where your host migrations created the chimeway_* tables — not a separate database unless you intentionally run Chimeway on its own Postgres instance.

Also choose the runtime storage prefix explicitly. New installs should use the new isolated Chimeway schema:

config :chimeway, prefix: "chimeway"

Use prefix: false only for an existing public-schema legacy install whose Chimeway tables already live in public:

config :chimeway, prefix: false

That legacy mode keeps using the existing unprefixed tables and does not move data.

For upgrade and troubleshooting notes, see the Storage Prefix Upgrade guide.

For supervisor setup, add {Chimeway.Application, []} to your application children per Installation §4. See Installation §3–§4 for the full application.ex pattern.

4. Define a minimal :in_app notifier

Create lib/my_app/notifiers/welcome_user.ex:

defmodule MyApp.Notifiers.WelcomeUser do
  use Chimeway.Notifier

  @impl true
  def notification_key, do: "welcome_user"

  @impl true
  def version, do: 1

  @impl true
  def recipients(params) do
    {:ok, [%{recipient_identity: params.user_id, recipient_type: "user"}]}
  end

  @impl true
  def build(params, _recipient) do
    name = Map.get(params, :name, "there")

    {:ok, %{
      subject: "Welcome, #{name}!",
      body: "Your account is ready."
    }}
  end
end

The :in_app channel is the default when you omit channels/2. Use recipients/1 with recipient_identity and recipient_type — the engine normalizes these keys when resolving deliveries.

5. Trigger your first notification

In IEx or your application code:

params = %{user_id: "user_12345", name: "Alice"}

{:ok, result} =
  Chimeway.trigger(
    MyApp.Notifiers.WelcomeUser,
    params,
    idempotency_key: "signup_user_12345",
    tenant_id: "default"
  )

Both :idempotency_key and :tenant_id are required. Omitting tenant_id returns {:error, :missing_tenant_id}.

After a successful trigger, inspect result.trace.event_id, result.trace.delivery_ids, and result.trace.correlation_id — these are your pointers into the durable trace.

6. Prove explainability

Listing inbox messages shows that a notification exists; explain_delivery/1 answers why it sent, failed, or was suppressed.

Using result from the trigger above:

[delivery_id | _] = result.trace.delivery_ids

{:ok, explanation} = Chimeway.Traces.explain_delivery(delivery_id)

explanation.status
#=> :succeeded

explanation.suppression_reason
#=> nil

Enum.map(explanation.timeline, & &1.event)

You can also load the full event trace:

{:ok, event} = Chimeway.Traces.get_trace(result.trace.event_id)
event.notifications |> Enum.flat_map(& &1.deliveries)

Optional: pass correlation_id: "my-correlation-id" on trigger, then Chimeway.Traces.find_traces_by_correlation_id/1 to find related events.

Validate in the demo host (no webhooks)

After your first explain_delivery/1 in your host app, the lowest-friction way to validate explainability end-to-end is the Chimeway demo host IEx walkthrough — no SendGrid, no provider webhooks.

Follow the Demo host trace walkthrough for a copy-paste IEx session using Chimeway.trigger/3 and explain_delivery/1.

Validate with operator UI (optional)

After you have trace rows in the database, the chimeway_admin package provides a browser UI for the same Support Operator lookup flow. See the demo host Operator trace UI (browser) section: start mix phx.server, visit /admin/chimeway, search by recipient or correlation ID, and inspect the delivery timeline. This complements IEx validation; it does not replace webhook E2E proof.

For webhook-driven workflow progression, use the webhook feedback loop appendix instead — the demo host README covers simple delivery explainability only.

7. What's next?

Next: webhook feedback loop

When inbound delivery feedback should drive workflow progression, Chimeway records webhook handling on the delivery timeline.

  • Progress path: a succeeded delivery signal resumes the workflow; the trace timeline includes :webhook_received entries you can inspect with Chimeway.Traces.explain_delivery/1.
  • Stop path: a bounced signal stops the workflow; the timeline still records the feedback event for explainability.

See the reference implementation in the repo:

Feedback appears as :webhook_received entries on Chimeway.Traces.explain_delivery/1 timelines — use that API to answer why progression advanced or stopped after inbound webhook data.