Requirements traceability diagram builder on top of Yog.
Choreo.Requirement models software requirements, the components that
satisfy them, the tests that verify them, and the stakeholders that own
them. It is aimed at software architects who need practical traceability
and risk analysis rather than strict SysML compliance.
When to use
Use Choreo.Requirement when you need to:
- document feature requirements alongside the services and tests that implement them
- find gaps in test coverage or implementation
- propagate risk from high-level requirements down to components
- perform impact analysis before a change
Node types
:requirement— a need, feature, or constraint:component— a service, module, or other implementation item:test— a test or verification activity:stakeholder— a person, team, or source of a requirement
Edge types
:satisfies— component fulfills a requirement:verifies— test proves a requirement:refines— child requirement elaborates a parent requirement:depends— requirement needs another requirement first:traces— generic traceability link:contains— parent requirement contains a child requirement:derives— requirement is derived from another
Quick start
model =
Choreo.Requirement.new("Auth v2")
|> Choreo.Requirement.add_requirement(:mfa,
id: "REQ-001",
text: "Users must authenticate with MFA",
risk: :high
)
|> Choreo.Requirement.add_component(:auth_service, label: "Auth Service")
|> Choreo.Requirement.add_test(:mfa_test, label: "MFA login test")
|> Choreo.Requirement.satisfies(:auth_service, :mfa)
|> Choreo.Requirement.verifies(:mfa_test, :mfa)
Choreo.Requirement.to_mermaid(model)
Choreo.Requirement.to_dot(model)Analysis
# Coverage gaps
Choreo.Requirement.Analysis.coverage(model)
# Risk propagation
Choreo.Requirement.Analysis.high_risk_gaps(model)
# Impact of changing a component
Choreo.Requirement.Analysis.impact_of(model, :auth_service)Diagram
Summary
Functions
Adds a component node.
Adds a requirement node.
Adds a stakeholder node.
Adds a test node.
Returns all component node IDs.
Creates a contains relationship: a parent requirement contains a child.
Creates a depends relationship: a requirement needs another requirement first.
Creates a derives relationship: a requirement is derived from another.
Returns all edges as {from, to, weight} tuples.
Returns all edges with their metadata as {from, to, weight, meta} tuples.
Returns the diagram name, or nil if not set.
Creates a new empty requirements diagram.
Returns the raw node data for a given node ID.
Returns all node IDs in the diagram.
Creates a refines relationship: a child requirement elaborates a parent.
Creates a custom relationship between two nodes.
Returns all requirement node IDs.
Creates a satisfies relationship: a component fulfills a requirement.
Returns all stakeholder node IDs.
Returns all test node IDs.
Returns a theme for Choreo.Requirement diagrams.
Renders the requirements diagram to DOT format.
Returns the raw Yog.Multi.Graph struct underpinning the diagram.
Renders the requirements diagram to Mermaid.js requirementDiagram syntax.
Creates a generic traces relationship.
Creates a verifies relationship: a test proves a requirement.
Types
@type t() :: %Choreo.Requirement{ edge_meta: %{optional(Yog.Multi.Graph.edge_id()) => map()}, graph: Yog.Multi.Graph.t(), name: String.t() | nil }
Functions
@spec add_component(t(), Yog.node_id(), keyword()) :: t()
Adds a component node.
Components are implementation items (services, modules, libraries) that satisfy requirements.
Options
:label(String.t/0) - Display label (defaults to the node id).:type(String.t/0) - Free-form type string for components/tests/stakeholders.:docref(String.t/0) - Optional documentation reference.
Examples
iex> req = Choreo.Requirement.new()
...> |> Choreo.Requirement.add_component(:auth, label: "Auth Service")
iex> Choreo.Requirement.components(req)
[:auth]
@spec add_requirement(t(), Yog.node_id(), keyword()) :: t()
Adds a requirement node.
Options
:id(String.t/0) - Required. Human-readable requirement identifier.:text(String.t/0) - Required. Requirement description.:risk- Risk level: :low, :medium, :high, or :critical. The default value is:medium.:verification- Verification method: :analysis, :inspection, :test, or :demonstration. The default value is:test.:kind- Requirement kind: :requirement, :functional, :interface, :performance, :physical, or :design_constraint. The default value is:requirement.
Examples
iex> req = Choreo.Requirement.new()
...> |> Choreo.Requirement.add_requirement(:mfa,
...> id: "REQ-001",
...> text: "Users must authenticate with MFA",
...> risk: :high
...> )
iex> Choreo.Requirement.node(req, :mfa).id
"REQ-001"
iex> Choreo.Requirement.node(req, :mfa).risk
:high
@spec add_stakeholder(t(), Yog.node_id(), keyword()) :: t()
Adds a stakeholder node.
Stakeholders are people, teams, or sources of requirements.
Options
:label(String.t/0) - Display label (defaults to the node id).:type(String.t/0) - Free-form type string for components/tests/stakeholders.:docref(String.t/0) - Optional documentation reference.
Examples
iex> req = Choreo.Requirement.new()
...> |> Choreo.Requirement.add_stakeholder(:security, label: "Security Team")
iex> Choreo.Requirement.stakeholders(req)
[:security]
@spec add_test(t(), Yog.node_id(), keyword()) :: t()
Adds a test node.
Tests verify requirements.
Options
:label(String.t/0) - Display label (defaults to the node id).:type(String.t/0) - Free-form type string for components/tests/stakeholders.:docref(String.t/0) - Optional documentation reference.
Examples
iex> req = Choreo.Requirement.new()
...> |> Choreo.Requirement.add_test(:t1, label: "Login test")
iex> Choreo.Requirement.tests(req)
[:t1]
@spec components(t()) :: [Yog.node_id()]
Returns all component node IDs.
@spec contains(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
Creates a contains relationship: a parent requirement contains a child.
@spec depends(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
Creates a depends relationship: a requirement needs another requirement first.
@spec derives(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
Creates a derives relationship: a requirement is derived from another.
@spec edges(t()) :: [{Yog.node_id(), Yog.node_id(), number()}]
Returns all edges as {from, to, weight} tuples.
@spec edges_with_meta(t()) :: [{Yog.node_id(), Yog.node_id(), number(), map()}]
Returns all edges with their metadata as {from, to, weight, meta} tuples.
Returns the diagram name, or nil if not set.
Creates a new empty requirements diagram.
Accepts an optional name string or keyword options.
Examples
iex> req = Choreo.Requirement.new("Auth v2")
iex> req.name
"Auth v2"
iex> req.graph.kind
:directed
@spec node(t(), Yog.node_id()) :: map() | nil
Returns the raw node data for a given node ID.
@spec nodes(t()) :: [Yog.node_id()]
Returns all node IDs in the diagram.
@spec refines(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
Creates a refines relationship: a child requirement elaborates a parent.
@spec relate(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
Creates a custom relationship between two nodes.
Options
:type(atom/0) - Relationship type. The default value is:traces.:label(String.t/0) - Optional edge label used in DOT rendering.
Examples
iex> req = Choreo.Requirement.new()
...> |> Choreo.Requirement.add_component(:auth)
...> |> Choreo.Requirement.add_requirement(:mfa, id: "REQ-001", text: "MFA")
...> |> Choreo.Requirement.relate(:auth, :mfa, type: :implements)
iex> meta = req.edge_meta |> Map.values() |> List.first()
iex> meta.type
:implements
@spec requirements(t()) :: [Yog.node_id()]
Returns all requirement node IDs.
@spec satisfies(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
Creates a satisfies relationship: a component fulfills a requirement.
Examples
iex> req = Choreo.Requirement.new()
...> |> Choreo.Requirement.add_component(:auth)
...> |> Choreo.Requirement.add_requirement(:mfa, id: "REQ-001", text: "MFA")
...> |> Choreo.Requirement.satisfies(:auth, :mfa)
iex> [{:auth, :mfa, _}] = Choreo.Requirement.edges(req)
@spec stakeholders(t()) :: [Yog.node_id()]
Returns all stakeholder node IDs.
@spec tests(t()) :: [Yog.node_id()]
Returns all test node IDs.
@spec theme( atom(), keyword() ) :: Choreo.Theme.t()
Returns a theme for Choreo.Requirement diagrams.
Renders the requirements diagram to DOT format.
Options
:theme—:default,:dark,:warm,:forest,:ocean, or aChoreo.Themestruct
Examples
iex> req = Choreo.Requirement.new() |> Choreo.Requirement.add_requirement(:a, id: "R1", text: "A")
iex> dot = Choreo.Requirement.to_dot(req)
iex> String.contains?(dot, "digraph")
true
@spec to_graph(t()) :: Yog.Multi.Graph.t()
Returns the raw Yog.Multi.Graph struct underpinning the diagram.
Renders the requirements diagram to Mermaid.js requirementDiagram syntax.
Options
:direction—:td(default),:lr,:rl,:bt:theme— used only for styling hints where supported
Examples
iex> req = Choreo.Requirement.new() |> Choreo.Requirement.add_requirement(:a, id: "R1", text: "A")
iex> mermaid = Choreo.Requirement.to_mermaid(req)
iex> String.contains?(mermaid, "requirementDiagram")
true
@spec traces(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
Creates a generic traces relationship.
@spec verifies(t(), Yog.node_id(), Yog.node_id(), keyword()) :: t()
Creates a verifies relationship: a test proves a requirement.