ISD Architecture
2025-10-15
Alleged benefits:
Cast your minds back



The C4 model was created as a way to help software development teams describe and communicate software architecture, both during up-front design sessions and when retrospectively documenting an existing codebase.


Not good for communicating architectureworkspace "ARC Services Portal" "Models the architecture of a research services web portal" {
!identifiers hierarchical
model {
properties {
"structurizr.groupSeparator" "/"
}
user = person "Researcher" "Uses the platform to manage their research profile and data."
admin = person "Admin" "Portal user with elevated permissions to edit data or review submissions."
entra = softwareSystem "Microsoft Entra" "Identity provider (SSO)" "Existing System"
tre = softwareSystem "TRE" "Secure processing environment for sensitive research data" "Existing System"
ghcr = softwareSystem "GitHub Container Registry" "Stores container images" "Existing System"
uclSystem = softwareSystem "..." "Other UCL consumer of portal data" "Existing System"
portal = softwareSystem "ARC Services Portal" "Enables management of Studies, Projects, user training and information governance" {
group "K8S cluster" {
api = container "API" "API backend with /web/api and /tre/api (and other) endpoints" "Go" {
group "Shared Services" {
projectService = component "Project Service" "Handles project workflows" "Go"
userService = component "User Service" "Handles user workflows" "Go"
otherService = component "..." "Other backend services" "Go"
}
group "Web API" {
webhttpHandlers = component "HTTP Handlers for web frontend" "Handles REST endpoints" "Go"
webhttpHandlers -> userService "Calls"
webhttpHandlers -> projectService "Calls"
webhttpHandlers -> otherService "Calls"
}
group "TRE API" {
trehttpHandlers = component "HTTP Handlers for UCL TREs" "Handles REST endpoints" "Go"
trehttpHandlers -> userService "Calls"
trehttpHandlers -> projectService "Calls"
trehttpHandlers -> otherService "Calls"
}
group "Other API" {
otherhttpHandlers = component "HTTP Handlers for other UCL systems" "Handles REST endpoints" "Go"
otherhttpHandlers -> otherService "Calls"
}
}
webFrontend = container "Web Frontend" "User-facing web app" "React, TypeScript" {
pages = component "Pages" "UCL Design System-styled pages for profile, studies, projects" "React"
apiClient = component "API Client" "Generated from OpenAPI spec" "TypeScript"
pages -> apiClient "Calls"
}
oauth2Proxy = container "OAuth2 Proxy" "Proxy providing OAuth2 authentication" "quay.io/oauth2-proxy/oauth2-proxy"
nginx = container "Reverse Proxy" "Routes requests to frontend and backend" "nginx"
postgres = container "Database" "Stores user, project, portal etc. data" "PostgreSQL"
api.projectService -> postgres "Reads/writes data"
api.userService -> postgres "Reads/writes data"
api.otherService -> postgres "Read/writes data"
nginx -> api.trehttpHandlers "Proxies /tre/api requests"
nginx -> api.otherhttpHandlers "Proxies other api requests"
nginx -> webFrontend.pages "Serves"
webFrontend.apiClient -> oauth2Proxy "Forwards /web/api requests for authentication"
oauth2Proxy -> api.webhttpHandlers "Forwards authenticated /web/api requests to backend"
}
deploy = container "CI/CD Pipeline" "Builds and deploys infrastructure and app" "GitHub Actions + Terraform" {
group "Portal App Repository" {
gha_portal = component "GitHub Actions (Portal Repo)" "Builds & pushes container images" "GitHub Actions"
}
group "Infrastructure Repository" {
gha_infra = component "GitHub Actions (Infra Repo)" "Applies Terraform in AWS" "GitHub Actions"
tf = component "Terraform Code" "Defines and provisions cloud infra" "Terraform"
gha_infra -> tf "Runs"
}
}
portal.deploy.tf -> ghcr "Pulls images for deployment"
portal.deploy.gha_portal -> ghcr "Pushes container images"
}
user -> portal.webFrontend.pages "Accesses via browser"
admin -> portal.webFrontend.pages "Administers via browser"
portal.oauth2Proxy -> entra "Authenticates requests against" "SSO"
tre -> portal.nginx "Accesses /tre/api for data retrieval" "REST/JSON"
uclSystem -> portal.nginx "Accesses api for data retrieval" "REST/JSON"
}
views {
systemContext portal "C1-Portal_Context" {
include *
description "Context diagram showing how the Research Platform fits within the broader environment."
}
container portal "C2-Portal_Containers" {
include *
description "Container view showing major services running in Kubernetes, including API, frontend, proxy, and DB."
}
component portal.api "C3-Web_API_Internals" {
include *
description "Component view showing key service components inside the API backend."
}
component portal.webFrontend "C3-Web_Frontend_Internals" {
include *
description "Component view showing the UI modules and OpenAPI client."
}
component portal.deploy "C3-Deployment_Workflow" {
include *
description "Component view showing how CI/CD is managed using GitHub Actions and Terraform."
}
styles {
element "Person" {
shape person
background #08427b
color #ffffff
}
element "Software System" {
background #1168bd
color #ffffff
}
element "Container" {
background #438dd5
color #ffffff
}
element "Component" {
background #85bbf0
color #000000
}
element "Existing System" {
background #999999
}
element "Group:K8S cluster" {
color #d86613
icon https://static.structurizr.com/themes/amazon-web-services-2020.04.30/amazon-elastic-kubernetes-service.png
}
}
}
}workspace "ARC Services Portal" "Models the architecture of a research services web portal" {
!identifiers hierarchical
model {
properties {
"structurizr.groupSeparator" "/"
}
user = person "Researcher" "Uses the platform to manage their research profile and data."
admin = person "Admin" "Portal user with elevated permissions to edit data or review submissions."
entra = softwareSystem "Microsoft Entra" "Identity provider (SSO)" "Existing System"
tre = softwareSystem "TRE" "Secure processing environment for sensitive research data" "Existing System"
ghcr = softwareSystem "GitHub Container Registry" "Stores container images" "Existing System"
uclSystem = softwareSystem "..." "Other UCL consumer of portal data" "Existing System"
portal = softwareSystem "ARC Services Portal" "Enables management of Studies, Projects, user training and information governance" {
group "K8S cluster" {
api = container "API" "API backend with /web/api and /tre/api (and other) endpoints" "Go" {
group "Shared Services" {
projectService = component "Project Service" "Handles project workflows" "Go"
userService = component "User Service" "Handles user workflows" "Go"
otherService = component "..." "Other backend services" "Go"
}
group "Web API" {
webhttpHandlers = component "HTTP Handlers for web frontend" "Handles REST endpoints" "Go"
webhttpHandlers -> userService "Calls"
webhttpHandlers -> projectService "Calls"
webhttpHandlers -> otherService "Calls"
}
group "TRE API" {
trehttpHandlers = component "HTTP Handlers for UCL TREs" "Handles REST endpoints" "Go"
trehttpHandlers -> userService "Calls"
trehttpHandlers -> projectService "Calls"
trehttpHandlers -> otherService "Calls"
}
group "Other API" {
otherhttpHandlers = component "HTTP Handlers for other UCL systems" "Handles REST endpoints" "Go"
otherhttpHandlers -> otherService "Calls"
}
}
webFrontend = container "Web Frontend" "User-facing web app" "React, TypeScript" {
pages = component "Pages" "UCL Design System-styled pages for profile, studies, projects" "React"
apiClient = component "API Client" "Generated from OpenAPI spec" "TypeScript"
pages -> apiClient "Calls"
}
oauth2Proxy = container "OAuth2 Proxy" "Proxy providing OAuth2 authentication" "quay.io/oauth2-proxy/oauth2-proxy"
nginx = container "Reverse Proxy" "Routes requests to frontend and backend" "nginx"
postgres = container "Database" "Stores user, project, portal etc. data" "PostgreSQL"
api.projectService -> postgres "Reads/writes data"
api.userService -> postgres "Reads/writes data"
api.otherService -> postgres "Read/writes data"
nginx -> api.trehttpHandlers "Proxies /tre/api requests"
nginx -> api.otherhttpHandlers "Proxies other api requests"
nginx -> webFrontend.pages "Serves"
webFrontend.apiClient -> oauth2Proxy "Forwards /web/api requests for authentication"
oauth2Proxy -> api.webhttpHandlers "Forwards authenticated /web/api requests to backend"
}
deploy = container "CI/CD Pipeline" "Builds and deploys infrastructure and app" "GitHub Actions + Terraform" {
group "Portal App Repository" {
gha_portal = component "GitHub Actions (Portal Repo)" "Builds & pushes container images" "GitHub Actions"
}
group "Infrastructure Repository" {
gha_infra = component "GitHub Actions (Infra Repo)" "Applies Terraform in AWS" "GitHub Actions"
tf = component "Terraform Code" "Defines and provisions cloud infra" "Terraform"
gha_infra -> tf "Runs"
}
}
portal.deploy.tf -> ghcr "Pulls images for deployment"
portal.deploy.gha_portal -> ghcr "Pushes container images"
}
user -> portal.webFrontend.pages "Accesses via browser"
admin -> portal.webFrontend.pages "Administers via browser"
portal.oauth2Proxy -> entra "Authenticates requests against" "SSO"
tre -> portal.nginx "Accesses /tre/api for data retrieval" "REST/JSON"
uclSystem -> portal.nginx "Accesses api for data retrieval" "REST/JSON"
}
views {
systemContext portal "C1-Portal_Context" {
include *
description "Context diagram showing how the Research Platform fits within the broader environment."
}
container portal "C2-Portal_Containers" {
include *
description "Container view showing major services running in Kubernetes, including API, frontend, proxy, and DB."
}
component portal.api "C3-Web_API_Internals" {
include *
description "Component view showing key service components inside the API backend."
}
component portal.webFrontend "C3-Web_Frontend_Internals" {
include *
description "Component view showing the UI modules and OpenAPI client."
}
component portal.deploy "C3-Deployment_Workflow" {
include *
description "Component view showing how CI/CD is managed using GitHub Actions and Terraform."
}
styles {
element "Person" {
shape person
background #08427b
color #ffffff
}
element "Software System" {
background #1168bd
color #ffffff
}
element "Container" {
background #438dd5
color #ffffff
}
element "Component" {
background #85bbf0
color #000000
}
element "Existing System" {
background #999999
}
element "Group:K8S cluster" {
color #d86613
icon https://static.structurizr.com/themes/amazon-web-services-2020.04.30/amazon-elastic-kubernetes-service.png
}
}
}
}workspace "ARC Services Portal" "Models the architecture of a research services web portal" {
!identifiers hierarchical
model {
properties {
"structurizr.groupSeparator" "/"
}
user = person "Researcher" "Uses the platform to manage their research profile and data."
admin = person "Admin" "Portal user with elevated permissions to edit data or review submissions."
entra = softwareSystem "Microsoft Entra" "Identity provider (SSO)" "Existing System"
tre = softwareSystem "TRE" "Secure processing environment for sensitive research data" "Existing System"
ghcr = softwareSystem "GitHub Container Registry" "Stores container images" "Existing System"
uclSystem = softwareSystem "..." "Other UCL consumer of portal data" "Existing System"
portal = softwareSystem "ARC Services Portal" "Enables management of Studies, Projects, user training and information governance" {
group "K8S cluster" {
api = container "API" "API backend with /web/api and /tre/api (and other) endpoints" "Go" {
group "Shared Services" {
projectService = component "Project Service" "Handles project workflows" "Go"
userService = component "User Service" "Handles user workflows" "Go"
otherService = component "..." "Other backend services" "Go"
}
group "Web API" {
webhttpHandlers = component "HTTP Handlers for web frontend" "Handles REST endpoints" "Go"
webhttpHandlers -> userService "Calls"
webhttpHandlers -> projectService "Calls"
webhttpHandlers -> otherService "Calls"
}
group "TRE API" {
trehttpHandlers = component "HTTP Handlers for UCL TREs" "Handles REST endpoints" "Go"
trehttpHandlers -> userService "Calls"
trehttpHandlers -> projectService "Calls"
trehttpHandlers -> otherService "Calls"
}
group "Other API" {
otherhttpHandlers = component "HTTP Handlers for other UCL systems" "Handles REST endpoints" "Go"
otherhttpHandlers -> otherService "Calls"
}
}
webFrontend = container "Web Frontend" "User-facing web app" "React, TypeScript" {
pages = component "Pages" "UCL Design System-styled pages for profile, studies, projects" "React"
apiClient = component "API Client" "Generated from OpenAPI spec" "TypeScript"
pages -> apiClient "Calls"
}
oauth2Proxy = container "OAuth2 Proxy" "Proxy providing OAuth2 authentication" "quay.io/oauth2-proxy/oauth2-proxy"
nginx = container "Reverse Proxy" "Routes requests to frontend and backend" "nginx"
postgres = container "Database" "Stores user, project, portal etc. data" "PostgreSQL"
api.projectService -> postgres "Reads/writes data"
api.userService -> postgres "Reads/writes data"
api.otherService -> postgres "Read/writes data"
nginx -> api.trehttpHandlers "Proxies /tre/api requests"
nginx -> api.otherhttpHandlers "Proxies other api requests"
nginx -> webFrontend.pages "Serves"
webFrontend.apiClient -> oauth2Proxy "Forwards /web/api requests for authentication"
oauth2Proxy -> api.webhttpHandlers "Forwards authenticated /web/api requests to backend"
}
deploy = container "CI/CD Pipeline" "Builds and deploys infrastructure and app" "GitHub Actions + Terraform" {
group "Portal App Repository" {
gha_portal = component "GitHub Actions (Portal Repo)" "Builds & pushes container images" "GitHub Actions"
}
group "Infrastructure Repository" {
gha_infra = component "GitHub Actions (Infra Repo)" "Applies Terraform in AWS" "GitHub Actions"
tf = component "Terraform Code" "Defines and provisions cloud infra" "Terraform"
gha_infra -> tf "Runs"
}
}
portal.deploy.tf -> ghcr "Pulls images for deployment"
portal.deploy.gha_portal -> ghcr "Pushes container images"
}
user -> portal.webFrontend.pages "Accesses via browser"
admin -> portal.webFrontend.pages "Administers via browser"
portal.oauth2Proxy -> entra "Authenticates requests against" "SSO"
tre -> portal.nginx "Accesses /tre/api for data retrieval" "REST/JSON"
uclSystem -> portal.nginx "Accesses api for data retrieval" "REST/JSON"
}
views {
systemContext portal "C1-Portal_Context" {
include *
description "Context diagram showing how the Research Platform fits within the broader environment."
}
container portal "C2-Portal_Containers" {
include *
description "Container view showing major services running in Kubernetes, including API, frontend, proxy, and DB."
}
component portal.api "C3-Web_API_Internals" {
include *
description "Component view showing key service components inside the API backend."
}
component portal.webFrontend "C3-Web_Frontend_Internals" {
include *
description "Component view showing the UI modules and OpenAPI client."
}
component portal.deploy "C3-Deployment_Workflow" {
include *
description "Component view showing how CI/CD is managed using GitHub Actions and Terraform."
}
styles {
element "Person" {
shape person
background #08427b
color #ffffff
}
element "Software System" {
background #1168bd
color #ffffff
}
element "Container" {
background #438dd5
color #ffffff
}
element "Component" {
background #85bbf0
color #000000
}
element "Existing System" {
background #999999
}
element "Group:K8S cluster" {
color #d86613
icon https://static.structurizr.com/themes/amazon-web-services-2020.04.30/amazon-elastic-kubernetes-service.png
}
}
}
}
The Common Architecture Language Model
https://calm.finos.org/
C4 Model
CALM
notation and tooling C4 is agnostic about… are gross
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://calm.finos.org/release/1.0/meta/core.json",
"title": "Common Architecture Language Model (CALM) Vocab",
"type" : "object",
"properties": {
"nodes": {
"type": "array",
"items": {
"$ref": "#/defs/node"
}
},
"relationships": {
"type": "array",
"items": {
"$ref": "#/defs/relationship"
}
},
"metadata": {
"$ref": "#/defs/metadata"
},
"controls": {
"$ref": "control.json#/defs/controls"
},
"flows": {
"type": "array",
"items": {
"$ref": "flow.json#/defs/flow"
}
},
"adrs": {
"type": "array",
"items": {
"type": "string"
},
"description": "External links to ADRs (Architecture Decision Records) or similar documents that provide context or decisions related to the architecture. These can be URLs or references to internal documentation."
},
"additionalProperties": false
},
"defs": {
"node": {
"type": "object",
"properties": {
"unique-id": {
"type": "string"
},
"node-type": {
"$ref": "#/defs/node-type-definition"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"details": {
"type": "object",
"properties": {
"detailed-architecture": {
"type": "string"
},
"required-pattern": {
"type": "string"
}
},
"additionalProperties": false
},
"interfaces": {
"type": "array",
"items": {
"anyOf": [
{ "$ref": "interface.json#/defs/interface-definition" },
{ "$ref": "interface.json#/defs/interface-type" }
]
}
},
"controls": {
"$ref": "control.json#/defs/controls"
},
"metadata": {
"$ref": "#/defs/metadata"
}
},
"required": [
"unique-id",
"node-type",
"name",
"description"
],
"additionalProperties": true
},
"relationship": {
"type": "object",
"properties": {
"unique-id": {
"type": "string"
},
"description": {
"type": "string"
},
"relationship-type": {
"type": "object",
"properties": {
"interacts": {
"$ref": "#/defs/interacts-type"
},
"connects": {
"$ref": "#/defs/connects-type"
},
"deployed-in": {
"$ref": "#/defs/deployed-in-type"
},
"composed-of": {
"$ref": "#/defs/composed-of-type"
},
"options": {
"$ref": "#/defs/option-type"
}
},
"oneOf": [
{
"required": [
"deployed-in"
]
},
{
"required": [
"composed-of"
]
},
{
"required": [
"interacts"
]
},
{
"required": [
"connects"
]
},
{
"required": [
"options"
]
}
]
},
"protocol": {
"$ref": "#/defs/protocol"
},
"metadata": {
"$ref": "#/defs/metadata"
},
"controls": {
"$ref": "control.json#/defs/controls"
}
},
"required": [
"unique-id",
"relationship-type"
],
"additionalProperties": true
},
"protocol": {
"enum": [
"HTTP",
"HTTPS",
"FTP",
"SFTP",
"JDBC",
"WebSocket",
"SocketIO",
"LDAP",
"AMQP",
"TLS",
"mTLS",
"TCP"
]
},
"node-type-definition": {
"anyOf": [
{
"enum": [
"actor",
"ecosystem",
"system",
"service",
"database",
"network",
"ldap",
"webclient",
"data-asset"
]
},
{
"type": "string"
}
]
},
"interacts-type": {
"type": "object",
"properties": {
"actor": {
"type": "string"
},
"nodes": {
"type": "array",
"minItems": 1,
"items": {
"type": "string"
}
}
},
"required": [
"actor",
"nodes"
]
},
"connects-type": {
"type": "object",
"properties": {
"source": {
"$ref": "interface.json#/defs/node-interface"
},
"destination": {
"$ref": "interface.json#/defs/node-interface"
}
},
"required": [
"source",
"destination"
]
},
"deployed-in-type": {
"type": "object",
"properties": {
"container": {
"type": "string"
},
"nodes": {
"type": "array",
"minItems": 1,
"items": {
"type": "string"
}
}
},
"required": [
"container",
"nodes"
]
},
"composed-of-type": {
"type": "object",
"properties": {
"container": {
"type": "string"
},
"nodes": {
"type": "array",
"minItems": 1,
"items": {
"type": "string"
}
}
},
"required": [
"container",
"nodes"
]
},
"option-type": {
"type": "array",
"items": {
"$ref": "#/defs/decision"
}
},
"decision": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"nodes": {
"type": "array",
"items": {
"type": "string"
}
},
"relationships": {
"type": "array",
"items": {
"type": "string"
}
},
"controls": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"description",
"nodes",
"relationships"
]
},
"metadata": {
"oneOf": [
{
"type": "array",
"items": {
"type": "object"
}
},
{
"type": "object",
"additionalProperties": true
}
]
}
}
}Patterns! Through the use of the CALM CLI:
Usage: calm [options] [command]
A set of tools for interacting with the Common Architecture Language Model (CALM)
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
generate [options] Generate an architecture from a CALM pattern file.
validate [options] Validate that an architecture conforms to a given CALM pattern.
docify [options] Generate a documentation website off your CALM model
help [command] display help for commandIn CALM, patterns are custom JSON schemas which adhere to the core CALM Meta Schema
{
"$schema": "https://calm.finos.org/release/1.0/meta/calm.json",
"title": "Consumer Pattern 3",
"type": "object",
"$defs": {
"node-base": {
"$ref": "https://calm.finos.org/release/1.0/meta/core.json#/defs/node"
},
"relationship-base": {
"$ref": "https://calm.finos.org/release/1.0/meta/core.json#/defs/relationship"
}
},
"properties": {
"nodes": {
"type": "array",
"minItems": 5,
"prefixItems": [
{
"$ref": "#/$defs/node-base",
"properties": {
"description": { "const": "Molecule that triggers a Scheduled Event" },
"node-type": { "const": "system" },
"name": { "const": "Trigger" },
"unique-id": { "const": "trigger" }
}
},
{
"$ref": "#/$defs/node-base",
"properties": {
"description": { "const": "Molecule that sends request to the Enterprise API when it is triggered" },
"node-type": { "const": "system" },
"name": { "const": "'Fetch from System' Connector" },
"unique-id": { "const": "fetch-from-system-connector" }
}
},
{
"$ref": "#/$defs/node-base",
"properties": {
"description": { "const": "Molecule that converts payload to System Data Model" },
"node-type": { "const": "system" },
"name": { "const": "Processing" },
"unique-id": { "const": "processing" }
}
},
{
"$ref": "#/$defs/node-base",
"properties": {
"description": { "const": "Molecule that initiates connection to System and sends payload over it" },
"node-type": { "const": "system" },
"name": { "const": "'Send to System' Connector" },
"unique-id": { "const": "send-to-system-connector" }
}
},
{
"$ref": "#/$defs/node-base",
"properties": {
"description": { "const": "Target System" },
"node-type": { "const": "system" },
"name": { "const": "Target System" },
"unique-id": { "const": "target-system" }
}
}
]
},
"relationships": {
"type": "array",
"minItems": 4,
"prefixItems": [
{
"$ref": "#/$defs/relationship-base",
"properties": {
"unique-id": { "const": "event-trigger" },
"description": { "const": "Scheduled event triggers API request" },
"relationship-type": {
"const": {
"connects": {
"source": { "node": "trigger" },
"destination": { "node": "fetch-from-system-connector" }
}
}
},
"protocol": { "const": "HTTPS" },
"authentication": { "const": "OAuth2" },
"controls": {
"$ref": "https://calm.finos.org/release/1.0/meta/control.json#/defs/controls",
"properties": {
"encryption": {
"type": "object",
"properties": {
"description": {
"const": "Encryption controls for data in transit"
},
"requirements": {
"type": "array",
"minItems": 1,
"prefixItems": [
{
"$ref": "https://calm.finos.org/release/1.0/meta/control.json#/defs/control-detail",
"properties": {
"requirement-url": {
"const": "/home/fbacon/CALM/demo/requirements/encryption-in-transit-requirement.json"
},
"config-url": {
"const": "/home/fbacon/CALM/demo/configs/encryption-in-transit-config.json"
}
}
}
]
}
}
}
}
}
},
"required": ["controls"]
},
{
"$ref": "#/$defs/relationship-base",
"properties": {
"unique-id": { "const": "publish-response" },
"description": { "const": "Publishes response payload for processing" },
"relationship-type": {
"const": {
"connects": {
"source": { "node": "fetch-from-system-connector" },
"destination": { "node": "processing" }
}
}
},
"protocol": { "const": "HTTPS" }
}
},
{
"$ref": "#/$defs/relationship-base",
"properties": {
"unique-id": { "const": "processing complete" },
"description": { "const": "Publishes transformed payload to 'Send to System' Connector" },
"relationship-type": {
"const": {
"connects": {
"source": { "node": "processing" },
"destination": { "node": "send-to-system-connector" }
}
}
},
"protocol": { "const": "HTTPS" }
}
},
{
"$ref": "#/$defs/relationship-base",
"properties": {
"unique-id": { "const": "payload-to-system" },
"description": { "const": "Initiates connection to System and sends payload over it" },
"relationship-type": {
"const": {
"connects": {
"source": { "node": "send-to-system-connector" },
"destination": { "node": "target-system" }
}
}
},
"protocol": { "const": "HTTPS" }
}
}
]
}
},
"required": ["nodes", "relationships"]
}You can include a control requirement-url and a control config-url
{
"$schema": "https://calm.finos.org/release/1.0/meta/calm.json",
"title": "Consumer Pattern 3",
"type": "object",
"$defs": {
"node-base": {
"$ref": "https://calm.finos.org/release/1.0/meta/core.json#/defs/node"
},
"relationship-base": {
"$ref": "https://calm.finos.org/release/1.0/meta/core.json#/defs/relationship"
}
},
"properties": {
"nodes": {
"type": "array",
"minItems": 5,
"prefixItems": [
{
"$ref": "#/$defs/node-base",
"properties": {
"description": { "const": "Molecule that triggers a Scheduled Event" },
"node-type": { "const": "system" },
"name": { "const": "Trigger" },
"unique-id": { "const": "trigger" }
}
},
{
"$ref": "#/$defs/node-base",
"properties": {
"description": { "const": "Molecule that sends request to the Enterprise API when it is triggered" },
"node-type": { "const": "system" },
"name": { "const": "'Fetch from System' Connector" },
"unique-id": { "const": "fetch-from-system-connector" }
}
},
{
"$ref": "#/$defs/node-base",
"properties": {
"description": { "const": "Molecule that converts payload to System Data Model" },
"node-type": { "const": "system" },
"name": { "const": "Processing" },
"unique-id": { "const": "processing" }
}
},
{
"$ref": "#/$defs/node-base",
"properties": {
"description": { "const": "Molecule that initiates connection to System and sends payload over it" },
"node-type": { "const": "system" },
"name": { "const": "'Send to System' Connector" },
"unique-id": { "const": "send-to-system-connector" }
}
},
{
"$ref": "#/$defs/node-base",
"properties": {
"description": { "const": "Target System" },
"node-type": { "const": "system" },
"name": { "const": "Target System" },
"unique-id": { "const": "target-system" }
}
}
]
},
"relationships": {
"type": "array",
"minItems": 4,
"prefixItems": [
{
"$ref": "#/$defs/relationship-base",
"properties": {
"unique-id": { "const": "event-trigger" },
"description": { "const": "Scheduled event triggers API request" },
"relationship-type": {
"const": {
"connects": {
"source": { "node": "trigger" },
"destination": { "node": "fetch-from-system-connector" }
}
}
},
"protocol": { "const": "HTTPS" },
"authentication": { "const": "OAuth2" },
"controls": {
"$ref": "https://calm.finos.org/release/1.0/meta/control.json#/defs/controls",
"properties": {
"encryption": {
"type": "object",
"properties": {
"description": {
"const": "Encryption controls for data in transit"
},
"requirements": {
"type": "array",
"minItems": 1,
"prefixItems": [
{
"$ref": "https://calm.finos.org/release/1.0/meta/control.json#/defs/control-detail",
"properties": {
"requirement-url": {
"const": "/home/fbacon/CALM/demo/requirements/encryption-in-transit-requirement.json"
},
"config-url": {
"const": "/home/fbacon/CALM/demo/configs/encryption-in-transit-config.json"
}
}
}
]
}
}
}
}
}
},
"required": ["controls"]
},
{
"$ref": "#/$defs/relationship-base",
"properties": {
"unique-id": { "const": "publish-response" },
"description": { "const": "Publishes response payload for processing" },
"relationship-type": {
"const": {
"connects": {
"source": { "node": "fetch-from-system-connector" },
"destination": { "node": "processing" }
}
}
},
"protocol": { "const": "HTTPS" }
}
},
{
"$ref": "#/$defs/relationship-base",
"properties": {
"unique-id": { "const": "processing complete" },
"description": { "const": "Publishes transformed payload to 'Send to System' Connector" },
"relationship-type": {
"const": {
"connects": {
"source": { "node": "processing" },
"destination": { "node": "send-to-system-connector" }
}
}
},
"protocol": { "const": "HTTPS" }
}
},
{
"$ref": "#/$defs/relationship-base",
"properties": {
"unique-id": { "const": "payload-to-system" },
"description": { "const": "Initiates connection to System and sends payload over it" },
"relationship-type": {
"const": {
"connects": {
"source": { "node": "send-to-system-connector" },
"destination": { "node": "target-system" }
}
}
},
"protocol": { "const": "HTTPS" }
}
}
]
}
},
"required": ["nodes", "relationships"]
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "./requirements/encryption-in-transit.json",
"title": "Encryption in Transit Requirement",
"description": "Ensures that if HTTPS is used, TLS version is declared and must be >=1.2.",
"type": "object",
"properties": {
"protocol": {
"type": "string",
"enum": ["HTTP", "HTTPS"]
},
"tls-version": {
"type": "string",
"enum": ["1.2", "1.3"]
}
},
"allOf": [
{
"if": {
"properties": { "protocol": { "const": "HTTPS" } }
},
"then": {
"required": ["tls-version"]
}
}
]
}calm validate -p pattern.json -a architecture.json
(calm-demo) fbacon@CS00058225:~/GitHub/presentations/calm/architecture$ calm validate -p pattern.json -a architecture.json
info [file-system-document-loader]: architecture.json exists, loading as file...
info [file-system-document-loader]: pattern.json exists, loading as file...
info [calm-validate]: Formatting output as json
{
"jsonSchemaValidationOutputs": [],
"spectralSchemaValidationOutputs": [],
"hasErrors": false,
"hasWarnings": false{
"nodes": [
{
"description": "Molecule that triggers a Scheduled Event",
"node-type": "system",
"name": "Trigger",
"unique-id": "trigger"
},
{
"description": "Molecule that sends request to the Enterprise API when it is triggered",
"node-type": "system",
"name": "'Fetch from System' Connector",
"unique-id": "fetch-from-system-connector"
},
{
"description": "Molecule that converts payload to System Data Model",
"node-type": "system",
"name": "Processing",
"unique-id": "processing"
},
{
"description": "Molecule that initiates connection to System and sends payload over it",
"node-type": "system",
"name": "'Send to System' Connector",
"unique-id": "send-to-system-connector"
},
{
"description": "Target System",
"node-type": "system",
"name": "Target System",
"unique-id": "target-system"
}
],
"relationships": [
{
"unique-id": "event-trigger",
"description": "Scheduled event triggers API request",
"relationship-type": {
"connects": {
"source": {
"node": "trigger"
},
"destination": {
"node": "fetch-from-system-connector"
}
}
},
"protocol": "HTTPS",
"authentication": "OAuth2",
"controls": {
"encryption": {
"description": "Encryption controls for data in transit",
"requirements": [
{
"requirement-url": "/home/fbacon/CALM/demo/requirements/encryption-in-transit-requirement.json",
"config-url": "/home/fbacon/CALM/demo/configs/encryption-in-transit-config.json"
}
]
}
}
},
{
"unique-id": "publish-response",
"description": "Publishes response payload for processing",
"relationship-type": {
"connects": {
"source": {
"node": "fetch-from-system-connector"
},
"destination": {
"node": "processing"
}
}
},
"protocol": "HTTPS"
},
{
"unique-id": "processing complete",
"description": "Publishes transformed payload to 'Send to System' Connector",
"relationship-type": {
"connects": {
"source": {
"node": "processing"
},
"destination": {
"node": "send-to-system-connector"
}
}
},
"protocol": "HTTPS"
},
{
"unique-id": "payload-to-system",
"description": "Initiates connection to System and sends payload over it",
"relationship-type": {
"connects": {
"source": {
"node": "send-to-system-connector"
},
"destination": {
"node": "target-system"
}
}
},
"protocol": "HTTPS"
}
]
}{
"nodes": [
{
"description": "Molecule that triggers a Scheduled Event",
"node-type": "system",
"name": "Trigger",
"unique-id": "trigger"
},
{
"description": "Molecule that sends request to the Enterprise API when it is triggered",
"node-type": "system",
"name": "'Fetch from System' Connector",
"unique-id": "fetch-from-system-connector"
},
{
"description": "Molecule that converts payload to System Data Model",
"node-type": "system",
"name": "Processing",
"unique-id": "processing"
},
{
"description": "Molecule that initiates connection to System and sends payload over it",
"node-type": "system",
"name": "'Send to System' Connector",
"unique-id": "send-to-system-connector"
},
{
"description": "Target System",
"node-type": "system",
"name": "Target System",
"unique-id": "target-system"
}
],
"relationships": [
{
"unique-id": "event-trigger",
"description": "Scheduled event triggers API request",
"relationship-type": {
"connects": {
"source": {
"node": "processing"
},
"destination": {
"node": "fetch-from-system-connector"
}
}
},
"protocol": "HTTPS",
"authentication": "OAuth2",
"controls": {
"encryption": {
"description": "Encryption controls for data in transit",
"requirements": [
{
"requirement-url": "/home/fbacon/CALM/demo/requirements/encryption-in-transit-requirement.json",
"config-url": "/home/fbacon/CALM/demo/configs/encryption-in-transit-config.json"
}
]
}
}
},
{
"unique-id": "publish-response",
"description": "Publishes response payload for processing",
"relationship-type": {
"connects": {
"source": {
"node": "fetch-from-system-connector"
},
"destination": {
"node": "processing"
}
}
},
"protocol": "HTTPS"
},
{
"unique-id": "processing complete",
"description": "Publishes transformed payload to 'Send to System' Connector",
"relationship-type": {
"connects": {
"source": {
"node": "processing"
},
"destination": {
"node": "send-to-system-connector"
}
}
},
"protocol": "HTTPS"
},
{
"unique-id": "payload-to-system",
"description": "Initiates connection to System and sends payload over it",
"relationship-type": {
"connects": {
"source": {
"node": "send-to-system-connector"
},
"destination": {
"node": "target-system"
}
}
},
"protocol": "HTTPS"
}
]
}calm validate -p pattern.json -a invalid-architecture.json
(calm-demo) fbacon@CS00058225:~/GitHub/presentations/calm/architecture$ calm validate -p pattern.json -a bad-architecture.json
info [file-system-document-loader]: bad-architecture.json exists, loading as file...
info [file-system-document-loader]: pattern.json exists, loading as file...
info [calm-validate]: Formatting output as json
{
"jsonSchemaValidationOutputs": [
{
"code": "json-schema",
"severity": "error",
"message": "must be equal to constant",
"path": "/relationships/0/relationship-type",
"schemaPath": "#/properties/relationships/prefixItems/0/properties/relationship-type/const"
}
],
"spectralSchemaValidationOutputs": [
{
"code": "architecture-nodes-must-be-referenced",
"severity": "warning",
"message": "Node with ID 'trigger' is not referenced by any relationships.",
"path": "/nodes/0/unique-id",
"schemaPath": "",
"line_start": 0,
"line_end": 0,
"character_start": 118,
"character_end": 127
}
],
"hasErrors": true,
"hasWarnings": trueCALM: Architecture-as-Code | https://finleybacon.github.io/presentations/