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

Analysis functions for `Choreo.C4` architecture models.

Provides validation and insight functions that answer practical questions
about your C4 model:

  * Are there orphaned nodes with no relationships?
  * Are there containers or components without parents?
  * Which elements are missing descriptions or technology labels?
  * Is the model structurally consistent?

## Further reading

  * [C4 Model](https://c4model.com/)
  * [Software Architecture for Developers (Simon Brown)](https://softwarearchitecturefordevelopers.com/)

# `isolated_nodes`

```elixir
@spec isolated_nodes(Choreo.C4.t()) :: [Yog.node_id()]
```

Returns nodes with no connections (zero in-degree and out-degree).

Isolated elements in a C4 diagram are usually a mistake — either a
missing relationship or an element that should be removed.

## Examples

    iex> c4 = Choreo.C4.new()
    ...>   |> Choreo.C4.add_person(:a)
    ...>   |> Choreo.C4.add_software_system(:b)
    iex> Choreo.C4.Analysis.isolated_nodes(c4)
    [:a, :b]

    iex> c4 = Choreo.C4.new()
    ...>   |> Choreo.C4.add_person(:a)
    ...>   |> Choreo.C4.add_software_system(:b)
    ...>   |> Choreo.C4.add_relationship(:a, :b)
    iex> Choreo.C4.Analysis.isolated_nodes(c4)
    []

This analysis answers the question: "Which elements have no relationships?"

# `missing_descriptions`

```elixir
@spec missing_descriptions(Choreo.C4.t()) :: [Yog.node_id()]
```

Returns nodes that are missing a description.

In C4, every element should have a meaningful description.

## Examples

    iex> c4 = Choreo.C4.new()
    ...>   |> Choreo.C4.add_person(:a, label: "A", description: "User A")
    ...>   |> Choreo.C4.add_software_system(:b, label: "B")
    iex> Choreo.C4.Analysis.missing_descriptions(c4)
    [:b]

This analysis answers the question: "Which elements lack descriptions?"

# `missing_parents`

```elixir
@spec missing_parents(Choreo.C4.t()) :: [Yog.node_id()]
```

Returns containers or components that have no parent.

In the C4 model every container should belong to a software system,
and every component should belong to a container.

## Examples

    iex> c4 = Choreo.C4.new()
    ...>   |> Choreo.C4.add_container(:api, label: "API")
    iex> Choreo.C4.Analysis.missing_parents(c4)
    [:api]

    iex> c4 = Choreo.C4.new()
    ...>   |> Choreo.C4.add_software_system(:banking)
    ...>   |> Choreo.C4.add_container(:api, parent: :banking)
    iex> Choreo.C4.Analysis.missing_parents(c4)
    []

This analysis answers the question: "Which containers or components are missing a parent?"

# `missing_relationship_labels`

```elixir
@spec missing_relationship_labels(Choreo.C4.t()) :: [Yog.Multi.Graph.edge_id()]
```

Returns relationships that are missing a description label.

In C4, every relationship should describe *how* or *what* one element
does with another.

## Examples

    iex> c4 = Choreo.C4.new()
    ...>   |> Choreo.C4.add_person(:a)
    ...>   |> Choreo.C4.add_software_system(:b)
    ...>   |> Choreo.C4.add_relationship(:a, :b, label: "Uses")
    iex> Choreo.C4.Analysis.missing_relationship_labels(c4)
    []

This analysis answers the question: "Which relationships lack descriptions?"

# `missing_technology`

```elixir
@spec missing_technology(Choreo.C4.t()) :: [Yog.node_id()]
```

Returns containers and components that are missing a technology label.

In C4, containers and components should indicate the technology used.

## Examples

    iex> c4 = Choreo.C4.new()
    ...>   |> Choreo.C4.add_software_system(:banking)
    ...>   |> Choreo.C4.add_container(:api, technology: "Phoenix", parent: :banking)
    ...>   |> Choreo.C4.add_container(:db, parent: :banking)
    iex> Choreo.C4.Analysis.missing_technology(c4)
    [:db]

This analysis answers the question: "Which containers or components lack technology labels?"

# `parents_without_relationships`

```elixir
@spec parents_without_relationships(Choreo.C4.t()) :: [Yog.node_id()]
```

Returns nodes that have children but no explicit relationships to/from them.

A parent node (e.g. a software system) that has containers but no
relationships to those containers may indicate an incomplete model.

## Examples

    iex> c4 = Choreo.C4.new()
    ...>   |> Choreo.C4.add_software_system(:banking)
    ...>   |> Choreo.C4.add_container(:api, parent: :banking)
    iex> Choreo.C4.Analysis.parents_without_relationships(c4)
    [:banking]

This analysis answers the question: "Which parent nodes have no relationships?"

# `validate`

```elixir
@spec validate(Choreo.C4.t()) :: [{:error | :warning, String.t()}]
```

Validates a C4 model and returns a list of issues.

Checks for:
  * isolated nodes (no relationships)
  * containers or components without parents
  * missing descriptions on any node
  * missing technology labels on containers and components
  * relationships without labels
  * orphaned parent nodes

Returns a list of `{severity, message}` tuples.

## Examples

    iex> c4 = Choreo.C4.new()
    ...>   |> Choreo.C4.add_person(:a, description: "User")
    ...>   |> Choreo.C4.add_software_system(:b, description: "System")
    ...>   |> Choreo.C4.add_relationship(:a, :b, label: "Uses")
    iex> Choreo.C4.Analysis.validate(c4)
    []

    iex> c4 = Choreo.C4.new()
    ...>   |> Choreo.C4.add_container(:api)
    iex> issues = Choreo.C4.Analysis.validate(c4)
    iex> Enum.any?(issues, fn {_sev, msg} -> String.contains?(msg, "parent") end)
    true

---

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