# `PhoenixKitOG.Assignments`
[🔗](https://github.com/BeamLabEU/phoenix_kit_og/blob/0.4.0/lib/phoenix_kit_og/assignments.ex#L1)

Context for binding templates to scopes inside a consumer module's
hierarchy.

## Hierarchy resolution

A consumer module's `refine_og/4` walks an ordered list of
`{scope_type, scope_uuid}` tuples (most specific first) — the first
scope with an assignment wins.

    Assignments.resolve_template("publishing", [
      {"post", post_uuid},
      {"group", group_uuid},
      {"default", nil}
    ])

Returns `{:ok, template}` or `:none`.

# `clear`

```elixir
@spec clear(String.t(), String.t(), binary() | nil, keyword()) ::
  {:ok, PhoenixKitOG.Schemas.Assignment.t()} | {:error, :not_found}
```

# `count_by_template`

```elixir
@spec count_by_template() :: %{required(binary()) =&gt; pos_integer()}
```

`%{template_uuid => assignment count}` for the templates that have any.

# `create`

```elixir
@spec create(String.t(), String.t(), binary() | nil, binary(), map(), keyword()) ::
  {:ok, PhoenixKitOG.Schemas.Assignment.t()} | {:error, Ecto.Changeset.t()}
```

Creates the assignment for a scope, slot mapping included, as one write
and one activity row. A scope that already has an assignment is an
`{:error, changeset}` (the unique indexes), never a silent overwrite —
`set/5` is the upsert.

# `delete_for_template`

```elixir
@spec delete_for_template(binary()) :: [PhoenixKitOG.Schemas.Assignment.t()]
```

Deletes every assignment bound to a template and returns the rows it
actually removed (`DELETE … RETURNING`). A row that was moved to another
template, or removed, by a concurrent transaction is not in the result.

# `get`

```elixir
@spec get(String.t(), String.t(), binary() | nil) ::
  PhoenixKitOG.Schemas.Assignment.t() | nil
```

# `get_by_uuid`

```elixir
@spec get_by_uuid(binary()) :: PhoenixKitOG.Schemas.Assignment.t() | nil
```

Returns `nil` when no assignment has that uuid.

# `list_for_module`

```elixir
@spec list_for_module(String.t()) :: [PhoenixKitOG.Schemas.Assignment.t()]
```

All assignments owned by `module_key`, preloaded with their template
for display in the assignments admin UI.

# `list_for_template`

```elixir
@spec list_for_template(binary()) :: [PhoenixKitOG.Schemas.Assignment.t()]
```

The assignments bound to one template, any consumer module.

# `resolve_template`

```elixir
@spec resolve_template(String.t(), [{String.t(), binary() | nil}]) ::
  {:ok, PhoenixKitOG.Schemas.Template.t()} | :none
```

Walks the hierarchy, returns the first template that wins.

Skips tuples whose `scope_uuid` is `nil` for any scope other than
`"default"` — those represent "no id resolvable" (e.g. a post without
a group) and should pass through to the next tier.

# `resolve_template_with_mapping`

```elixir
@spec resolve_template_with_mapping(String.t(), [{String.t(), binary() | nil}]) ::
  {:ok, PhoenixKitOG.Schemas.Template.t(), map()} | :none
```

Same walk as `resolve_template/2` but also returns the winning
assignment's `slot_mapping` so callers can substitute template slots
in one pass.

# `set`

```elixir
@spec set(String.t(), String.t(), binary() | nil, binary(), keyword()) ::
  {:ok, PhoenixKitOG.Schemas.Assignment.t()} | {:error, Ecto.Changeset.t()}
```

Upserts an assignment. Pass `scope_uuid: nil` for the module-wide
default tier.

# `update`

```elixir
@spec update(PhoenixKitOG.Schemas.Assignment.t(), binary(), map(), keyword()) ::
  {:ok, PhoenixKitOG.Schemas.Assignment.t()} | {:error, Ecto.Changeset.t()}
```

Changes the template and slot mapping of THIS assignment row — its scope
is not an input, so an edit can never land on another scope's row. One
write, one activity row.

# `update_slot_mapping`

```elixir
@spec update_slot_mapping(PhoenixKitOG.Schemas.Assignment.t(), map(), keyword()) ::
  {:ok, PhoenixKitOG.Schemas.Assignment.t()} | {:error, Ecto.Changeset.t()}
```

Updates just the `slot_mapping` on an existing assignment. The
wiring UI writes here every time a slot dropdown changes.

---

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