# `DocShell.Presentation.Source`
[🔗](https://github.com/futhr/doc_shell/blob/v2.0.0/lib/doc_shell/presentation/source.ex#L1)

Producer contract for source-independent documentation presentation data.

A producer answers `project/1` with a `t:presentation/0`, whatever it reads
from — authored entries, a knowledge graph, or anything else. The renderer
never learns which.

Presentation structs provide a common set of fields and defaults for all
producers. Their `Jason.Encoder` implementations emit the string-keyed JSON
contract, including null facets. `DocShell.Presentation.GraphProjector`
validates field types, recursive AST content, and JSON metadata at runtime.

Optional backlinks are available in the in-memory result. The build writes
navigation, search, and content artifacts; it does not serialize backlinks.

# `presentation`

```elixir
@type presentation() :: %{
  :schema_version =&gt; String.t(),
  :navigation =&gt; [DocShell.Presentation.NavigationItem.t()],
  :search =&gt; [DocShell.Presentation.SearchEntry.t()],
  :content =&gt; %{optional(String.t()) =&gt; [DocShell.Ast.ast_node()]},
  optional(:backlinks) =&gt; %{
    optional(String.t()) =&gt; [DocShell.Presentation.Backlink.t()]
  },
  optional(:publication) =&gt; DocShell.Presentation.HostedPair.binding()
}
```

A renderer-neutral documentation artifact.

`content` maps an entry id to its AST nodes; `backlinks` maps an entry id to
the entries that reference it.

# `project`

```elixir
@callback project(keyword()) :: {:ok, presentation()} | {:error, term()}
```

# `validate_ids`

```elixir
@spec validate_ids([map()]) :: :ok | {:error, term()}
```

Rejects duplicate document IDs, retaining source locations in the error.

---

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