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

Macro for defining Chronicle event types.

Use `Chronicle.Events.EventType` in an event struct module to annotate it with a
stable event type identifier and generation number. Chronicle uses these to
register the event schema and route events to the correct observers.

You can also declare model-bound constraints directly on the event type
through attributes:

    defmodule MyApp.Events.UserRegistered do
      use Chronicle.Events.EventType, id: "user-registered-v1"
      defstruct [:email]

      @unique :email
      unique_event_type()
    end

    defmodule MyApp.Events.UserDeleted do
      use Chronicle.Events.EventType, id: "user-deleted-v1"
      defstruct [:email]

      @remove_constraint "email"
    end

## Usage

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

With an explicit generation:

    defmodule MyApp.Events.FundsDeposited do
      use Chronicle.Events.EventType, id: "funds-deposited", generation: 2
      defstruct account_id: "", amount: 0, currency: ""
    end

## Introspection

Modules that `use Chronicle.Events.EventType` expose metadata via
`__chronicle_event_type__/1`:

    MyApp.Events.AccountOpened.__chronicle_event_type__(:id)
    #=> "account-opened-v1"

    MyApp.Events.AccountOpened.__chronicle_event_type__(:generation)
    #=> 1

## Options

  * `:id` — the stable event type identifier (required, unless `:generation_for` is given)
  * `:generation` — the generation number (default `1`; required when `:generation_for` is
    given)
  * `:generation_for` — marks this module as a **previous generation** of the event type
    module it names, instead of giving it its own `:id`. The event type id is resolved from
    the target module, so the two generations can never drift apart by a hand-typed,
    mismatched id string. Cannot be combined with `:id`; the target module must itself `use
    Chronicle.Events.EventType`.

        defmodule MyApp.Events.AccountOpenedV1 do
          use Chronicle.Events.EventType, generation_for: MyApp.Events.AccountOpened, generation: 1
          defstruct account_id: "", owner_name: ""
        end
  * `:subject` — the field holding the event's data subject, the person whose PII the event
    carries (`subject: :customer_id`). It is resolved on append unless an explicit `:subject`
    option is given, and decides whose erasure key protects the event's PII. Without it the
    kernel falls back to the event source id.
  * `:tags` — tags every append of this event type carries, merged with per-append `:tags`
  * `:tombstone` — marks the event type as a tombstone (the last event of an event source's life)
    (mirrors .NET's `[Tombstone]`)
  * `:public` — makes the event type visible to other event stores, e.g. through event store
    subscriptions (mirrors `[Public]`)
  * `:compensation_for` — the event type module this event compensates for
    (mirrors `[CompensationFor<T>]`)
  * `:types` — type hints for nested fields; see `Chronicle.Serialization`

When you append an event, the client encodes its fields as camelCase JSON:
`owner_name` is stored as `ownerName`. Give every field a typed default, such
as `initial_balance: 0`; the JSON schema Chronicle validates appends against is
generated from the defaults, and a `nil` default registers the field as a
string.

# `__chronicle_event_type__`

```elixir
@callback __chronicle_event_type__(
  key ::
    :id
    | :generation
    | :generation_for
    | :constraints
    | :pii
    | :encrypted
    | :subject
    | :tags
    | :tombstone
    | :public
    | :compensation_for
) :: term()
```

Returns metadata for this event type module.

Accepts `:id`, `:generation`, or `:constraints` as the key.

# `closes_stream`
*macro* 

Declares that appending this event **closes a stream scope** (a *closing event*).

The kernel writes the event and the closure together; every later event inside the closed
scope is refused with a stream-closed violation, while events elsewhere are unaffected. Use it
when a domain fact ends something: a delivered report, closed books, a superseded version.
Mirrors .NET's `[ClosesStream]`. Supported `opts`:

  * `:dimensions` - the participating dimensions, a list of `:event_source_id`,
    `:event_source_type`, `:event_stream_type` and `:event_stream_id`. Defaults to
    `[:event_source_id, :event_stream_type, :event_stream_id]`.
  * `:event_stream_id_from` - the event field supplying the stream id instead of the append
    (implies the `:event_stream_id` dimension)
  * `:reopened_by` - event type modules that lift the closure of exactly this scope
  * `:name` - the owning constraint name (defaults to the event type id); declarations that
    share a name merge, and must use the same dimensions and stream id field
  * `:event_sequences` - restrict the declaration to specific event sequences (default: all)

Registering a declaration closes nothing in history; only later appends close scopes.

    defmodule MyApp.Events.PeriodClosed do
      use Chronicle.Events.EventType, id: "period-closed"
      defstruct period: ""

      closes_stream event_stream_id_from: :period, reopened_by: [MyApp.Events.PeriodReopened]
    end

# `declared_subject`

```elixir
@spec declared_subject(struct()) :: String.t() | nil
```

Resolves the data subject of an event from its declared `:subject` field, if it has one.

An event type declares the field holding the subject (the person whose PII it carries)
with `use Chronicle.Events.EventType, id: "...", subject: :customer_id`. A `Chronicle.Concept`
value is unwrapped. Returns `nil` when no subject is declared or the field is empty.

# `declared_tags`

```elixir
@spec declared_tags(struct()) :: [String.t()]
```

The tags every append of this event type carries (declared with `tags:`).

# `event_type?`

```elixir
@spec event_type?(module()) :: boolean()
```

Returns whether `module` is a Chronicle event type (`use Chronicle.Events.EventType`).

Every append path checks this before building a request, so an event struct that never
registered an event type fails with a structured `{:error, {:unknown_event_type, module}}`
instead of raising deep inside request building.

# `remove_constraint`
*macro* 

Declares that appending this event removes a named constraint.

This is equivalent to setting `@remove_constraint`.

# `remove_constraint`
*macro* 

Declares that appending this event removes a named constraint, carrying the value to
release.

`:properties` names the constrained properties, in the same order as the `unique/2`
declaration, that this event carries the value of (empty or omitted releases every value for
the event source, same as `remove_constraint/1`). Only meaningful for a `:per_value` unique
constraint — a unique event type constraint has no constrained value to carry.

    defmodule MyApp.Events.MappingVersionRemoved do
      use Chronicle.Events.EventType, id: "mapping-version-removed"
      defstruct [:version_id]

      remove_constraint("UniqueMappingVersionId", properties: [:version_id])
    end

# `unique`
*macro* 

Declares a unique constraint for one or more event fields.

This is equivalent to setting `@unique`. Supported `opts`:

  * `:name` — explicit constraint name (defaults to the first field name)
  * `:mode` — `:per_event_source` (default) keeps one value per event source and releases the
    previous value when it is replaced; `:per_value` keeps every value until a removal event
    (`remove_constraint/1`) releases it
  * `:ignore_casing` — compare values case-insensitively
  * `:message` — human-readable message to use when the constraint is
    violated
  * `:scope` — narrows uniqueness checking to values observed at append
    time along one or more dimensions, mirroring the C# client's
    `IConstraintBuilder.PerEventSourceType()`/`PerEventStreamType()`/
    `PerEventStreamId()`. An atom (`:per_event_source_type`,
    `:per_event_stream_type`, or `:per_event_stream_id`) or a list of them.
    Defaults to unscoped (globally unique across the whole event store).
  * `:event_sequences` — restrict the declaration to specific event
    sequences (default: all)

`:message` also accepts a `{Module, :function}` callback invoked with the violation to
compute one; see `Chronicle.Events.ConstraintViolation.details/1`.

An unknown option, an invalid `:mode`, or an invalid `:scope` value emits a compile warning
(the declaration still compiles; an unknown `:mode` then raises `ArgumentError` when the
constraint definition is built, as in earlier releases).

## Scoping example

    # Unique only within events for the same event source type — the same
    # value may repeat across different event source types.
    unique(:email, scope: :per_event_source_type)

# `unique_event_type`
*macro* 

Declares a unique constraint for the whole event type.

This is equivalent to setting `@unique_event_type`. Supported `opts`:

  * `:name` — explicit constraint name (defaults to the event type id)
  * `:message` — human-readable message to use when the constraint is
    violated, or a `{Module, :function}` callback; see `unique/2`
  * `:scope` — see `unique/2`
  * `:event_sequences` — see `unique/2`

An unknown option or an invalid `:scope` value emits a compile warning.

---

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