Architecture & Design Modeling

Copy Markdown View Source

Choreo provides powerful tools for modeling, analyzing, and rendering system architectures, database designs, security boundaries, and code structures.


Choreo — System Architecture

Model systems with typed infrastructure nodes: databases, caches, services, queues, load balancers, networks, users, storage, compute, and managed databases. Use this for general service-level and system architecture diagrams.

alias Choreo

system =
  Choreo.new()
  |> Choreo.add_database(:db, label: "Postgres", kind: :postgres)
  |> Choreo.add_cache(:cache, label: "Redis")
  |> Choreo.add_service(:api, label: "API Gateway")
  |> Choreo.connect(:api, :cache, cost: 5)
  |> Choreo.connect(:api, :db, cost: 10)

# Analysis
{:ok, mst} = Choreo.Analysis.mst(system)
{:ok, order} = Choreo.Analysis.topological_sort(system)

# Render
dot = Choreo.to_dot(system, theme: :dark)
mermaid = Choreo.to_mermaid(system)

Features: clusters with nesting (including typed VPC/subnet boundaries), dataflow edges, cost-weighted edges, MST, topological sort, SCC, theming, cross-diagram embedding and tracing.

graph TD
  classDef default color:white
  cache{{"Redis"}}
  db[("Postgres")]
  api[["API Gateway"]]
  style cache fill:#f59e0b,stroke:#d78000
  style db fill:#3b82f6,stroke:#1d64d8
  style api fill:#10b981,stroke:#009b63
  api --> cache
  api --> db
  linkStyle 0 stroke-width:2px,stroke:#64748b
  linkStyle 1 stroke-width:2px,stroke:#64748b

Choreo.Infrastructure — Cloud Network Topology

A domain-specific vocabulary layer on top of Choreo for modeling cloud network topologies with VPCs, subnets, compute instances, managed databases, and load balancers. It shares the same rendering pipeline and data model as Choreo but adds security-aware analysis rules.

Use Choreo.Infrastructure when you need:

  • Typed cluster boundaries — VPCs, public subnets, and private subnets with security semantics
  • Security audits — automatic checks for direct internet-to-private links, misplaced databases, and exposed storage
  • Cloud vocabularyadd_vpc/3, add_compute/3, add_managed_db/3, add_subnet_public/3, etc.
alias Choreo.Infrastructure

infra =
  Infrastructure.new()
  |> Infrastructure.add_vpc("vpc_main", label: "Production VPC")
  |> Infrastructure.add_subnet_public("dmz", label: "Public DMZ", parent: "vpc_main")
  |> Infrastructure.add_subnet_private("app", label: "App Tier", parent: "vpc_main")
  |> Infrastructure.add_load_balancer(:alb, label: "ALB", cluster: "dmz")
  |> Infrastructure.add_compute(:api, label: "API", cluster: "app")
  |> Infrastructure.add_managed_db(:db, label: "Postgres RDS", cluster: "app")
  |> Infrastructure.connect(:alb, :api)
  |> Infrastructure.connect(:api, :db)

# Security audit
Choreo.Infrastructure.Analysis.validate(infra)
# => []  (or [{:error, ...}, {:warning, ...}] if violations found)

Note: Choreo.Infrastructure is a thin wrapper over Choreo — it uses the same struct fields, rendering pipeline, and theming system. You can embed an Infrastructure diagram into a top-level Choreo diagram and it will render seamlessly.


Choreo.C4 — C4 Model Architecture

Model software architecture at multiple zoom levels — from system context down to components — in a single unified graph.

alias Choreo.C4
alias Choreo.C4.Analysis

c4 =
  C4.new()
  |> C4.add_person(:customer, label: "Customer")
  |> C4.add_software_system(:banking,
    label: "Internet Banking",
    scope: :in,
    description: "Allows customers to view balances and make payments"
  )
  |> C4.add_software_system(:mainframe,
    label: "Mainframe Banking",
    description: "Stores all core banking information"
  )
  |> C4.add_container(:web_app,
    label: "Web Application",
    technology: "JavaScript",
    parent: :banking
  )
  |> C4.add_container(:api,
    label: "API Application",
    technology: "Elixir/Phoenix",
    parent: :banking
  )
  |> C4.add_component(:accounts_ctx,
    label: "Accounts Context",
    technology: "Elixir",
    parent: :api
  )
  |> C4.relationship(:customer, :banking, label: "Views account balances")
  |> C4.relationship(:banking, :mainframe, label: "Gets account info")

# Zoom to a specific C4 level
C4.to_mermaid(Choreo.View.zoom(c4, level: 0)) # System Context
C4.to_mermaid(Choreo.View.zoom(c4, level: 1)) # Container diagram
C4.to_mermaid(Choreo.View.zoom(c4, level: 2)) # Component diagram

# Analysis
Analysis.missing_descriptions(c4)
Analysis.isolated_nodes(c4)
Analysis.validate(c4)

Features: L1–L3 C4 modeling (System Context, Containers, Components), zoom-aware rendering, parent/child clustering, missing metadata detection, isolated node detection.

graph TD
  classDef default color:white
  banking["Internet Banking"]
  customer(("Customer"))
  mainframe["Mainframe Banking"]
  style banking fill:#3b82f6,stroke:#1d64d8,stroke-width:3px
  style customer fill:#f59e0b,stroke:#d78000
  style mainframe fill:#64748b,stroke:#46566d
  banking --> mainframe
  customer --> banking
  linkStyle 0 stroke-width:2px,stroke:#64748b
  linkStyle 1 stroke-width:2px,stroke:#64748b

Choreo.ThreatModel — STRIDE Threat Modeling

Extend dataflow diagrams with security semantics. Auto-generate STRIDE threats based on element types, trust boundaries, and encryption status.

alias Choreo.ThreatModel
alias Choreo.ThreatModel.Analysis

model =
  ThreatModel.new()
  |> ThreatModel.add_trust_boundary("internet", level: 0)
  |> ThreatModel.add_trust_boundary("app", level: 2)
  |> ThreatModel.add_external_entity(:user, boundary: "internet", label: "User")
  |> ThreatModel.add_process(:api, boundary: "app", privilege: :admin, label: "API")
  |> ThreatModel.add_data_store(:db, boundary: "app", sensitivity: :confidential, label: "DB")
  |> ThreatModel.data_flow(:user, :api)
  |> ThreatModel.data_flow(:api, :db, encrypted: true)

# Auto-generated threats
threats = Analysis.stride_threats(model)

# Security analysis
Analysis.exposed_data_stores(model)
Analysis.high_risk_processes(model)
Analysis.unencrypted_boundary_flows(model)

# Sequence diagram
ThreatModel.to_sequence(model)  #=> Mermaid sequenceDiagram string

Features: automated STRIDE threat generation with severity scoring, trust-boundary crossing detection, exposed-data-store identification, high-risk process detection, encrypted-flow detection, sequence diagram generation.

graph LR
  classDef default color:white
  user["User"]
  api(("API"))
  db[("DB")]
  style user fill:#64748b,stroke:#46566d,stroke-width:3px
  style api fill:#3b82f6,stroke:#1d64d8
  style db fill:#f59e0b,stroke:#d78000
  subgraph app ["app"]
    api
    db
  end
  subgraph internet ["internet"]
    user
  end
  user --> api
  api --> db
  linkStyle 0 stroke-width:2px,stroke:#64748b,stroke-dasharray:5 5
  linkStyle 1 stroke-width:2px,stroke:#64748b

Choreo.Domain — DDD & Event Storming Domain Modeling

Model complex domains using Event Storming syntax and Strategic Context Mapping. Declare bounded contexts, aggregates, commands, events, sagas/policies, and Scott Wlaschin-style algebraic data types (ADTs) and workflows.

alias Choreo.Domain
alias Choreo.Domain.Analysis

model =
  Domain.new()
  |> Domain.add_context_boundary("ordering", label: "Ordering Bounded Context")
  |> Domain.add_aggregate(:order_agg, label: "Order Aggregate", parent: "ordering")
  |> Domain.add_command(:place_order, label: "Place Order")
  |> Domain.add_event(:order_placed, label: "Order Placed")
  |> Domain.connect(:place_order, :order_agg, label: "handles")
  |> Domain.connect(:order_agg, :order_placed, label: "publishes")

# Strategic Context Mapping
context_map =
  Domain.new()
  |> Domain.add_context(:ordering, label: "Ordering Service")
  |> Domain.add_context(:billing, label: "Billing Service")
  |> Domain.connect_contexts(:ordering, :billing, type: :acl, label: "Upstream -> Downstream")

# Render
mermaid = Domain.to_mermaid(model)

Features: bounded contexts, aggregates, command-event separation, anti-corruption layers (ACL), algebraic data type tables (ADTs), workflows, strategic context maps, validation.


Choreo.ERD — Database Entity-Relationship Modeling

Model database schemas, validate data integrity constraints, render beautiful HTML-like tables or native Mermaid erDiagram syntaxes, and run advanced topological analysis.

alias Choreo.ERD
alias Choreo.ERD.Analysis

erd =
  ERD.new()
  |> ERD.add_table(:users, columns: [
    %{name: :id, type: :integer, key: :pk},
    %{name: :email, type: :varchar, comment: "unique email"}
  ])
  |> ERD.add_table(:posts, columns: [
    %{name: :id, type: :integer, key: :pk},
    %{name: :user_id, type: :integer, key: :fk},
    %{name: :title, type: :varchar}
  ])
  |> ERD.add_table(:comments, columns: [
    %{name: :id, type: :integer, key: :pk},
    %{name: :post_id, type: :integer, key: :fk},
    %{name: :body, type: :text}
  ])
  |> ERD.add_relationship(:users, :posts, cardinality: :one_to_many, label: "writes")
  |> ERD.add_relationship(:posts, :comments, cardinality: :one_to_many, label: "has")

# Topological Analysis
Analysis.shortest_join_path(erd, :users, :comments) #=> {:ok, [:users, :posts, :comments]}
Analysis.cycles(erd)                              #=> [] (no circular foreign keys!)
Analysis.orphans(erd)                             #=> []
Analysis.table_degrees(erd)                       #=> %{users: %{in: 0, out: 1, total: 1}, ...}

Features: strict columns and relationship validation, customizable themed HTML record labels in DOT output, native Mermaid erDiagram generation, undirected BFS join path solver, DFS circular foreign key cycle detection, orphan and coupling metrics.

erDiagram
  users {
    integer id PK
    varchar email "unique email"
  }
  posts {
    integer id PK
    integer user_id FK
    varchar title
  }
  comments {
    integer id PK
    integer post_id FK
    text body
  }
  users ||--o{ posts : "writes"
  posts ||--o{ comments : "has"

Choreo.UML — Class & Struct Diagrams

Model software module contracts, behaviors, protocols, structs, their fields, arities, and visibilities, and declare exact structural relations with visual parity.

alias Choreo.UML

uml =
  UML.new()
  |> UML.add_class(:user,
    type: :struct,
    label: "User Model",
    fields: [
      %{name: :id, type: :integer, visibility: :public},
      %{name: :email, type: :string, visibility: :private}
    ],
    functions: [
      %{name: "authenticate", arity: 2, return: :boolean, visibility: :public}
    ]
  )
  |> UML.add_class(:auth_provider, type: :behavior)
  |> UML.add_relationship(:user, :auth_provider, type: :realizes, label: "implements")

# Render to native Mermaid class diagram
UML.to_mermaid(uml, syntax: :class_diagram)

Features: multi-compartment record tables, standard visibility markers (+, -, #), functional contracts, protocol realization, behavior adoption, lens focusing via Choreo.View.

classDiagram
  direction TD
  class user["User Model"] {
    <<struct>>
    +id integer
    -email string
    +authenticate(2) boolean
  }
  class auth_provider["auth_provider"] {
    <<behavior>>
  }
  user ..|> auth_provider : implements