# `Chronicle`
[🔗](https://github.com/Cratis/Chronicle.Elixir/blob/main/lib/chronicle.ex#L4)

Idiomatic Elixir client for the Chronicle event-sourcing platform.

Chronicle is an event-sourcing kernel that stores domain events and projects
them into read models. This library provides an idiomatic Elixir interface
built on top of the Chronicle gRPC API.

## Quick Start

Add the dependency to your `mix.exs`:

    {:cratis_chronicle, "~> 3.5"}

Start `Chronicle.Client` in your application supervision tree:

    defmodule MyApp.Application do
      use Application

      def start(_type, _args) do
        children = [
          {Chronicle.Client,
            connection_string: "chronicle://localhost:35000",
            event_store: "my-app",
            event_types: [MyApp.Events.AccountOpened, MyApp.Events.FundsDeposited],
            migrations: [MyApp.Migrations.AccountOpenedV2Migration],
            reactors: [MyApp.Reactors.NotificationReactor],
            reducers: [MyApp.Reducers.AccountReducer],
            seeders: [MyApp.Seeders.InitialDataSeeder],
            event_store_subscriptions: [
              MyApp.EventStoreSubscriptions.DefaultAccountEvents
            ]}
        ]

        Supervisor.start_link(children, strategy: :one_for_one)
      end
    end

Or rely on artifact auto-discovery:

    {Chronicle.Client,
      connection_string: "chronicle://localhost:35000",
      event_store: "my-app",
      otp_app: :my_app}

## Defining Event Types

    defmodule MyApp.Events.AccountOpened do
      use Chronicle.Events.EventType, id: "account-opened-v1"
      defstruct account_id: "", owner_name: "", initial_balance: 0
    end

## Appending Events

    Chronicle.append("account-42", %MyApp.Events.AccountOpened{
      account_id: "account-42",
      owner_name: "Alice",
      initial_balance: 1000
    })

## Reading Read Models

    {:ok, account} = Chronicle.read_model(MyApp.ReadModels.Account, "account-42")

## Defining Reactors

    defmodule MyApp.Reactors.NotificationReactor do
      use Chronicle.Reactors.Reactor

      @handles MyApp.Events.AccountOpened

      @impl true
      def handle(%MyApp.Events.AccountOpened{} = event, _context) do
        MyApp.Mailer.welcome(event.owner_name)
        :ok
      end
    end

## Defining Reducers

    defmodule MyApp.Reducers.AccountReducer do
      use Chronicle.Reducers.Reducer, model: MyApp.ReadModels.Account

      @handles MyApp.Events.AccountOpened

      @impl true
      def reduce(%MyApp.Events.AccountOpened{} = event, _model, _context) do
        %MyApp.ReadModels.Account{
          account_id: event.account_id,
          owner_name: event.owner_name,
          balance: event.initial_balance
        }
      end
    end

## Defining Seeders

    defmodule MyApp.Seeders.InitialDataSeeder do
      use Chronicle.Seeding.Seeder

      @impl true
      def seed(builder) do
        builder
        |> Chronicle.Seeding.for(
          MyApp.Events.AccountOpened,
          "seed-account-1",
          [%MyApp.Events.AccountOpened{
            account_id: "seed-account-1",
            owner_name: "Initial User",
            initial_balance: 10_000
          }]
        )
      end
    end

## Modules

  * `Chronicle.Client` — the main supervisor; start it in your supervision tree
  * `Chronicle.Correlation.CorrelationId` / `Chronicle.Correlation.CorrelationIdManager` — correlate operations
  * `Chronicle.Identity` / `Chronicle.Identity.IdentityProvider` — track who caused state changes
  * `Chronicle.Auditing.CausationType`, `Chronicle.Auditing.CausationEntry`, `Chronicle.Auditing.CausationManager` — audit causation chains
  * `Chronicle.Events.EventType` — macro for defining event types
  * `Chronicle.Events.Migration` — macro for defining event migrations
  * `Chronicle.Events.MigrationBuilder` — fluent API for migration transforms
  * `Chronicle.Events.Migrators` — migration discovery and registration support
  * `Chronicle.Events.ConcurrencyScope` — scope optimistic concurrency checks for appends
  * `Chronicle.Reactors.Reactor` — behaviour for event reactors
  * `Chronicle.Reducers.Reducer` — behaviour for read model reducers
  * `Chronicle.Seeding.Seeder` — behaviour for event seeders
  * `Chronicle.EventStoreSubscriptions` — register event store subscriptions
  * `Chronicle.EventStoreSubscriptions.Subscription` — define discoverable event store subscriptions
  * `Chronicle.ReadModels.ReadModel` — macro for read model structs with embedded projection DSL
  * `Chronicle.EventSequences.EventLog` — append and query events
  * `Chronicle.EventSequences.EventSequence` — work with custom event sequences
  * `Chronicle.Transactions.UnitOfWork` — buffer and commit transactional appends
  * `Chronicle.EventStores` — list event stores and namespaces
  * `Chronicle.ReadModels` — query read model instances
  * `Chronicle.Jobs` — inspect and control Chronicle jobs
  * `Chronicle.WebHooks` — inspect and register webhooks
  * `Chronicle.Connections.ConnectionString` — parse and format connection strings
  * `Chronicle.Connections.Connection` — resilient gRPC channel management

# `all`

```elixir
@spec all(module(), keyword()) :: {:ok, [struct()]} | {:error, term()}
```

Returns all instances of the given read model.

Delegates to `Chronicle.ReadModels.all/2`.

# `append`

```elixir
@spec append(String.t(), struct(), keyword()) :: :ok | {:error, term()}
```

Appends a single event to the event log for the given event source.

Delegates to `Chronicle.EventSequences.EventLog.append/3`.

## Options

  * `:client` — the client name (default: `Chronicle.Client`)
  * `:namespace` — overrides the client's default namespace
  * `:event_sequence_id` — event sequence id (default: `"event-log"`)
  * `:tags` — list of tag strings
  * `:subject` — the identity subject string
  * `:correlation_id` — `Chronicle.Correlation.CorrelationId` (or id string) override
  * `:identity` — `Chronicle.Identity` override
  * `:causation` — list of `Chronicle.Auditing.CausationEntry` overrides
  * `:concurrency_scope` — `Chronicle.Events.ConcurrencyScope` or keyword options

# `append_many`

```elixir
@spec append_many(String.t(), [struct()], keyword()) :: :ok | {:error, term()}
```

Appends multiple events to the event log for the given event source.

Delegates to `Chronicle.EventSequences.EventLog.append_many/3`.
Accepts the same append options as `append/3`, including `:concurrency_scope`.

# `append_many_with_result`

```elixir
@spec append_many_with_result(String.t(), [struct()], keyword()) ::
  {:ok, Chronicle.EventSequences.AppendResult.t()}
  | {:error, Chronicle.EventSequences.AppendResult.t() | term()}
```

Appends events atomically and returns the detailed `Chronicle.EventSequences.AppendResult`.

Delegates to `Chronicle.EventSequences.EventLog.append_many_with_result/3`.

# `append_with_result`

```elixir
@spec append_with_result(String.t(), struct(), keyword()) ::
  {:ok, Chronicle.EventSequences.AppendResult.t()}
  | {:error, Chronicle.EventSequences.AppendResult.t() | term()}
```

Appends a single event and returns the detailed `Chronicle.EventSequences.AppendResult`
(assigned sequence number, structured constraint and concurrency violations).

Delegates to `Chronicle.EventSequences.EventLog.append_with_result/3`.

# `begin_unit_of_work`

```elixir
@spec begin_unit_of_work(keyword()) :: Chronicle.Transactions.UnitOfWork.t()
```

Begins a new unit of work for the calling process.

# `clear_correlation_id`

```elixir
@spec clear_correlation_id() :: Chronicle.Correlation.CorrelationId.t()
```

Clears the current process correlation id.

# `clear_identity`

```elixir
@spec clear_identity() :: :ok
```

Clears the current process identity.

# `current_correlation_id`

```elixir
@spec current_correlation_id() :: Chronicle.Correlation.CorrelationId.t()
```

Gets the current process correlation id.

# `current_identity`

```elixir
@spec current_identity() :: Chronicle.Identity.t()
```

Gets the current process identity.

# `current_unit_of_work`

```elixir
@spec current_unit_of_work() :: Chronicle.Transactions.UnitOfWork.t()
```

Returns the current unit of work for the calling process.

# `decide`

```elixir
@spec decide((Chronicle.Transactions.UnitOfWork.t() -&gt; result), keyword()) ::
  {:ok, result} | {:error, term()}
when result: any()
```

Runs a function inside a unit of work and commits it, returning `{:ok, result}` on success or
`{:error, %Chronicle.ReadModels.DecisionConflict{}}` when a decision read enrolled in it
(`Chronicle.ReadModels.DecisionReads.get/3`) conflicted with a concurrent append. See
`Chronicle.Transactions.UnitOfWork.decide/2`.

# `delete_job`

```elixir
@spec delete_job(String.t(), keyword()) :: :ok | {:error, term()}
```

Deletes a Chronicle job.

# `event_sequence`

```elixir
@spec event_sequence(String.t(), keyword()) ::
  Chronicle.EventSequences.EventSequence.t()
```

Creates an event sequence wrapper for the given event sequence id.

# `get_event_stores`

```elixir
@spec get_event_stores(keyword()) :: {:ok, [String.t()]} | {:error, term()}
```

Returns all event store names.

# `get_job`

```elixir
@spec get_job(String.t(), keyword()) ::
  {:ok, Chronicle.Jobs.Job.t() | nil} | {:error, term()}
```

Gets a single Chronicle job by identifier.

# `get_job_steps`

```elixir
@spec get_job_steps(String.t(), keyword()) ::
  {:ok, [Chronicle.Jobs.JobStep.t()]} | {:error, term()}
```

Gets all steps for a Chronicle job.

# `get_jobs`

```elixir
@spec get_jobs(keyword()) :: {:ok, [Chronicle.Jobs.Job.t()]} | {:error, term()}
```

Gets all jobs for the configured event store namespace.

# `get_namespaces`

```elixir
@spec get_namespaces(keyword()) :: {:ok, [String.t()]} | {:error, term()}
```

Returns all namespaces for an event store.

Uses the configured client event store by default.

# `get_tail_sequence_number`

```elixir
@spec get_tail_sequence_number(String.t() | nil, keyword()) ::
  {:ok, non_neg_integer()} | {:error, term()}
```

Gets the tail sequence number for an event sequence.

# `get_webhooks`

```elixir
@spec get_webhooks(keyword()) ::
  {:ok, [Chronicle.WebHooks.Definition.t()]} | {:error, term()}
```

Gets all registered webhooks.

# `has_events_for?`

```elixir
@spec has_events_for?(String.t(), keyword()) :: {:ok, boolean()} | {:error, term()}
```

Checks whether there are events for an event source id in an event sequence.

# `read_model`

```elixir
@spec read_model(module(), String.t(), keyword()) ::
  {:ok, struct() | nil} | {:error, term()}
```

Fetches a read model instance by its key (typically an event source ID).

Delegates to `Chronicle.ReadModels.get/3`.

Returns `{:ok, model_struct}` on success, or `{:ok, nil}` if not found.

# `register_discovered_event_store_subscriptions`

```elixir
@spec register_discovered_event_store_subscriptions(keyword()) ::
  :ok | {:error, term()}
```

Registers all discoverable event store subscriptions.

# `register_discovered_webhooks`

```elixir
@spec register_discovered_webhooks(keyword()) :: :ok | {:error, term()}
```

Registers all discoverable webhooks.

# `register_event_store_subscription`

```elixir
@spec register_event_store_subscription(module(), keyword()) :: :ok | {:error, term()}
```

Registers a discoverable event store subscription module.

# `register_webhook`

```elixir
@spec register_webhook(module(), keyword()) :: :ok | {:error, term()}
```

Registers a discoverable webhook module.

# `register_webhook`

```elixir
@spec register_webhook(
  String.t(),
  String.t(),
  (Chronicle.WebHooks.DefinitionBuilder.t() -&gt;
     Chronicle.WebHooks.DefinitionBuilder.t()),
  keyword()
) :: :ok | {:error, term()}
```

Registers a webhook imperatively.

# `remove_webhook`

```elixir
@spec remove_webhook(String.t(), keyword()) :: :ok | {:error, term()}
```

Removes a registered webhook by identifier.

# `resume_job`

```elixir
@spec resume_job(String.t(), keyword()) :: :ok | {:error, term()}
```

Resumes a Chronicle job.

# `set_correlation_id`

```elixir
@spec set_correlation_id(Chronicle.Correlation.CorrelationId.t() | String.t()) ::
  Chronicle.Correlation.CorrelationId.t()
```

Sets the current process correlation id.

# `set_identity`

```elixir
@spec set_identity(Chronicle.Identity.t()) :: Chronicle.Identity.t()
```

Sets the current process identity.

# `stop_job`

```elixir
@spec stop_job(String.t(), keyword()) :: :ok | {:error, term()}
```

Stops a Chronicle job.

# `subscribe_to_event_store`

```elixir
@spec subscribe_to_event_store(String.t(), String.t(), keyword()) ::
  :ok | {:error, term()}
```

Registers an event store subscription imperatively using all available event
types.

# `subscribe_to_event_store`

```elixir
@spec subscribe_to_event_store(
  String.t(),
  String.t(),
  (Chronicle.EventStoreSubscriptions.DefinitionBuilder.t() -&gt;
     Chronicle.EventStoreSubscriptions.DefinitionBuilder.t()),
  keyword()
) :: :ok | {:error, term()}
```

Registers an event store subscription imperatively.

# `unsubscribe_from_event_store`

```elixir
@spec unsubscribe_from_event_store(String.t(), keyword()) :: :ok | {:error, term()}
```

Removes an event store subscription by identifier.

# `with_unit_of_work`

```elixir
@spec with_unit_of_work((Chronicle.Transactions.UnitOfWork.t() -&gt; any()), keyword()) ::
  any()
```

Runs a function inside a unit of work and commits it if the function succeeds.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
