# `Choreo.Domain`
[🔗](https://github.com/code-shoily/choreo/blob/v0.14.1/lib/choreo/domain.ex#L1)

Domain-Driven Design (DDD) and Event Storming domain-modeling preset for Choreo.

`Choreo.Domain` is a domain-specific vocabulary layer that adds DDD concepts —
Bounded Contexts, Aggregates, Commands, Domain Events, Policies, and Workflows —
on top of Choreo's underlying graph and rendering engine.

It draws inspiration from Scott Wlaschin's *Domain Modeling Made Functional*
and classic tactical/strategic DDD patterns.

## Tactical Node Types (Event Storming & Workflows)
* `:actor` - The user or external trigger initiating a command.
* `:command` - An action requested (blue sticky note).
* `:aggregate` - Consistency boundary / entity (yellow sticky note).
* `:event` - Business domain event (orange sticky note).
* `:read_model` - Projection / dashboard (green sticky note).
* `:policy` - Saga or reaction policy (purple/lilac sticky note).
* `:external_system` - Third-party system boundary (red/rose).
* `:type` - Algebraic data type (Slate table card displaying field names and types).
* `:workflow` - Wlaschin-style pipeline action (Teal rounded box).
* `:acl` - Anti-Corruption Layer translation gateway.

## Strategic Modeling (Context Mapping)
* `add_context/3` - Adds a Bounded Context node for high-level mapping.
* `add_context_boundary/3` - Adds a Bounded Context cluster boundary for tactical grouping.
* `connect_contexts/4` - Connects Bounded Context nodes with relationship labels (e.g. ACL, Shared Kernel).

# `t`

```elixir
@type t() :: %Choreo.Domain{
  clusters: %{required(String.t()) =&gt; map()},
  edge_meta: %{optional(Yog.Multi.Graph.edge_id()) =&gt; map()},
  graph: Yog.Multi.Graph.t(),
  highlighted_edges: [
    Yog.Multi.Graph.edge_id() | {Yog.node_id(), Yog.node_id()}
  ],
  highlighted_nodes: [Yog.node_id()],
  scenarios: %{required(atom()) =&gt; map()}
}
```

# `add_acl`

```elixir
@spec add_acl(t(), Yog.node_id(), keyword()) :: t()
```

Adds an Anti-Corruption Layer translation gateway component.

# `add_actor`

```elixir
@spec add_actor(t(), Yog.node_id(), keyword()) :: t()
```

Adds a user or actor initiating a command.

# `add_aggregate`

```elixir
@spec add_aggregate(t(), Yog.node_id(), keyword()) :: t()
```

Adds an Aggregate/Entity boundary node.

# `add_command`

```elixir
@spec add_command(t(), Yog.node_id(), keyword()) :: t()
```

Adds a Command node (actions requested).

# `add_context`

```elixir
@spec add_context(t(), Yog.node_id(), keyword()) :: t()
```

Adds a Bounded Context node for high-level Strategic Context Maps.

# `add_context_boundary`

```elixir
@spec add_context_boundary(t(), String.t(), keyword()) :: t()
```

Adds a Bounded Context cluster boundary for Tactical design layouts.

# `add_event`

```elixir
@spec add_event(t(), Yog.node_id(), keyword()) :: t()
```

Adds a Domain Event node.

# `add_external_system`

```elixir
@spec add_external_system(t(), Yog.node_id(), keyword()) :: t()
```

Adds an External System node.

# `add_policy`

```elixir
@spec add_policy(t(), Yog.node_id(), keyword()) :: t()
```

Adds a Policy / Saga handler node.

# `add_read_model`

```elixir
@spec add_read_model(t(), Yog.node_id(), keyword()) :: t()
```

Adds a Read Model / Projection node.

# `add_scenario`

```elixir
@spec add_scenario(t(), atom(), keyword()) :: t()
```

Adds a named business scenario as an ordered domain path.

Scenarios are useful for documenting use cases and rendering a selected path
as a Mermaid `eventmodeling` timeline.

# `add_type`

```elixir
@spec add_type(t(), Yog.node_id(), keyword()) :: t()
```

Adds an Algebraic Data Type node.

# `add_workflow`

```elixir
@spec add_workflow(t(), Yog.node_id(), keyword()) :: t()
```

Adds a Workflow pipeline function node.

# `causes`

```elixir
@spec causes(t(), Yog.node_id()) :: [Yog.node_id()]
```

Returns all ancestor causes of a target node.

This is a **set**, not an ordered path — for branching cause graphs
(DAGs with multiple parents), all ancestors are returned collapsed into
one list with no path structure.

## Examples

    iex> domain = Choreo.Domain.new()
    ...>   |> Choreo.Domain.add_actor(:customer)
    ...>   |> Choreo.Domain.add_command(:place_order)
    ...>   |> Choreo.Domain.add_aggregate(:order_agg)
    ...>   |> Choreo.Domain.add_event(:order_placed)
    ...>   |> Choreo.Domain.connect(:customer, :place_order)
    ...>   |> Choreo.Domain.connect(:place_order, :order_agg)
    ...>   |> Choreo.Domain.connect(:order_agg, :order_placed)
    iex> ancestors = Choreo.Domain.causes(domain, :order_placed)
    iex> :customer in ancestors
    true
    iex> :order_agg in ancestors
    true

# `clear_focus`

```elixir
@spec clear_focus(t()) :: t()
```

Clears the current scenario highlight.

## Examples

    iex> domain = Choreo.Domain.new()
    ...>   |> Choreo.Domain.add_actor(:customer)
    ...>   |> Choreo.Domain.add_command(:place_order)
    ...>   |> Choreo.Domain.focus_path([:customer, :place_order])
    ...>   |> Choreo.Domain.clear_focus()
    iex> domain.highlighted_nodes
    []
    iex> domain.highlighted_edges
    []

# `connect`

```elixir
@spec connect(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
```

Connects two domain nodes.

Prefer the semantic helpers (`initiates/4`, `handles/4`, `emits/4`,
`triggers/4`, `projects_to/4`, `notifies/4`, and `translates_via/4`) when
the edge has DDD/Event Modeling meaning. Use `connect/4` as the generic
escape hatch.

# `connect_contexts`

```elixir
@spec connect_contexts(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
```

Connects two strategic Bounded Context nodes with DDD relationship semantics.

# `downstream`

```elixir
@spec downstream(t(), Yog.node_id()) :: [Yog.node_id()]
```

Returns all downstream effects reachable from a source node.

This is a **set**, not an ordered path — for branching graphs, all reachable
descendants are returned collapsed into one list with no path structure.

## Examples

    iex> domain = Choreo.Domain.new()
    ...>   |> Choreo.Domain.add_actor(:customer)
    ...>   |> Choreo.Domain.add_command(:place_order)
    ...>   |> Choreo.Domain.add_aggregate(:order_agg)
    ...>   |> Choreo.Domain.connect(:customer, :place_order)
    ...>   |> Choreo.Domain.connect(:place_order, :order_agg)
    iex> descendants = Choreo.Domain.downstream(domain, :customer)
    iex> :place_order in descendants
    true
    iex> :order_agg in descendants
    true

# `edges`

```elixir
@spec edges(t()) :: [{Yog.node_id(), Yog.node_id(), number()}]
```

Returns all edges in the domain model.

# `emits`

```elixir
@spec emits(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
```

Connects an aggregate, workflow, or external system to an emitted domain event.

# `focus_path`

```elixir
@spec focus_path(t(), [Yog.node_id()]) :: t()
```

Focuses the diagram on a specific execution path scenario, highlighting it
while leaving the rest of the diagram visible.

# `focus_scenario`

```elixir
@spec focus_scenario(t(), atom()) :: t()
```

Focuses the diagram on a named scenario path.

# `handles`

```elixir
@spec handles(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
```

Connects a command to the aggregate or workflow that handles it.

# `initiates`

```elixir
@spec initiates(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
```

Connects an actor, UI, or external trigger to a command.

# `new`

```elixir
@spec new(keyword()) :: t()
```

Initializes a new empty domain model.

# `nodes`

```elixir
@spec nodes(t()) :: %{required(Yog.node_id()) =&gt; map()}
```

Returns all node definitions in the domain model.

# `notifies`

```elixir
@spec notifies(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
```

Connects an event to an actor/user notification.

# `projects_to`

```elixir
@spec projects_to(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
```

Connects an event to a read model/projection that it updates.

# `scenario`

```elixir
@spec scenario(t(), atom()) :: map() | nil
```

Returns a named scenario, or `nil` when it is not present.

# `scenarios`

```elixir
@spec scenarios(t()) :: %{required(atom()) =&gt; map()}
```

Returns all named scenarios.

# `theme`

```elixir
@spec theme(atom(), keyword()) :: Choreo.Theme.t()
```

Returns a theme for `Choreo.Domain`.

## Examples

    iex> theme = Choreo.Domain.theme(:default, graph_rankdir: :lr)
    iex> theme.graph_rankdir
    :lr

# `to_dot`

```elixir
@spec to_dot(t(), keyword()) :: String.t()
```

Renders the domain model to DOT format.

# `to_mermaid`

```elixir
@spec to_mermaid(t(), keyword()) :: String.t()
```

Renders the domain model to Mermaid.js native syntax.

## Options
  * `:syntax` - `:flowchart` (default), `:class_diagram`, `:erd`, or
    `:event_modeling`
  * `:path` - ordered node IDs for `:event_modeling` timeline rendering
  * `:scenario` - named scenario to render with `:event_modeling`
  * Other options matching the selected syntax engine

# `translates_via`

```elixir
@spec translates_via(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
```

Connects an upstream model/system to a downstream model/system through an ACL
or translation gateway.

# `triggers`

```elixir
@spec triggers(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
```

Connects an event or policy to a command, policy, workflow, or other reaction.

---

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