id_effect 3.0.0

Effect<A, E, R> (sync + async), capability DI, pipe — interpreter-style, no bundled executor
Documentation
# Async messaging (production)

Platform async messaging stacks on **sqlx `PgPool`** ([`PgPoolKey`](../../../id_effect_sql_pg)), with production adapters in [`id_effect_jobs`](../../../id_effect_jobs) and [`id_effect_events`](../../../id_effect_events).

## SQL platform

[`id_effect_sql_pg`](../../../id_effect_sql_pg) replaces the deadpool era with sqlx:

- [`PgSqlClient`]../../../id_effect_sql_pg/struct.PgSqlClient.html implements [`SqlClient`]../../../id_effect_sql/trait.SqlClient.html
- [`provide_pg_sql_client`]../../../id_effect_sql_pg/fn.provide_pg_sql_client.html registers `PgPoolKey` + `SqlClientKey`
- Set `DATABASE_URL` (devenv provides `postgresql://postgres@127.0.0.1:5432/id_effect`)

## Jobs — Apalis (pull workers)

[`ApalisJobQueue`](../../../id_effect_jobs/struct.ApalisJobQueue.html) is **enqueue-only**. Workers pull tasks via Apalis `WorkerBuilder` + `PostgresStorage::poll` — there is no FIFO `dequeue` on the storage side.

```rust,ignore
use id_effect_jobs::{ApalisJobQueue, JobSpec};
use id_effect::run_async;

ApalisJobQueue::setup(&pool).await?;
let queue = ApalisJobQueue::new(&pool, "app_jobs");
run_async(queue.enqueue(JobSpec::new("notify", b"payload")), ()).await?;
```

Enable: `id_effect_jobs` features `apalis` (+ `postgres`).

## Transactional outbox — obix

[`ObixOutbox`](../../../id_effect_jobs/struct.ObixOutbox.html) persists [`OutboxRecord`](../../../id_effect_jobs/struct.OutboxRecord.html) rows through [obix](https://docs.rs/obix) on the shared pool. Relay progress uses a sequence cursor (obix has no `published` flag).

For unit tests only: `memory` feature + [`MemoryOutbox`](../../../id_effect_jobs/struct.MemoryOutbox.html) + [`relay_outbox`](../../../id_effect_jobs/fn.relay_outbox.html).

## Idempotent inbox — obix + job

[`ObixInbox`](../../../id_effect_jobs/struct.ObixInbox.html) wires obix [`Inbox`](https://docs.rs/obix/latest/obix/struct.Inbox.html) to the [`job`](https://docs.rs/job) poller for idempotent consumers.

## Kafka — rdkafka

[`RdKafkaBroker`](../../../id_effect_jobs/struct.RdKafkaBroker.html) implements [`MessageBroker`](../../../id_effect_jobs/trait.MessageBroker.html) with [rdkafka](https://docs.rs/rdkafka). [`KafkaBrokerStub`](../../../id_effect_jobs/struct.KafkaBrokerStub.html) remains **memory-only** (`memory` feature) for tests.

## SQL event journal

[`EsEntityPgBackend`](../../../id_effect_events/struct.EsEntityPgBackend.html) (`id_effect_events` feature `es-entity`) implements [`SqlJournalBackend`](../../../id_effect_events/trait.SqlJournalBackend.html) on the same `PgPool`.

Apply [`ES_ENTITY_EVENT_JOURNAL_DDL`](../../../id_effect_events/constant.ES_ENTITY_EVENT_JOURNAL_DDL.html) via [`apply_es_entity_journal_ddl`](../../../id_effect_events/fn.apply_es_entity_journal_ddl.html).

## Feature matrix

| Crate | Feature | Adapter |
|-------|---------|---------|
| `id_effect_jobs` | `memory` (default) | in-process stubs |
| `id_effect_jobs` | `apalis` | Apalis PostgreSQL queue |
| `id_effect_jobs` | `obix` | obix outbox + inbox |
| `id_effect_jobs` | `kafka` | rdkafka broker |
| `id_effect_events` | `postgres` | `EsEntityPgBackend` |

## See also

- ADR: `docs/platform/adrs/adr-sql-driver-choice.md`
- Plan: `.cursor/plans/platform_messaging_production.plan.md`