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
Summary
Functions
Returns nodes with no connections (zero in-degree and out-degree).
Returns nodes that are missing a description.
Returns containers or components that have no parent.
Returns relationships that are missing a description label.
Returns containers and components that are missing a technology label.
Returns nodes that have children but no explicit relationships to/from them.
Validates a C4 model and returns a list of issues.
Functions
@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?"
@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?"
@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?"
@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?"
@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?"
@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?"
@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