Diagram as Code
Language Overview¶
Diagram as Code is an approach to creating technical diagrams using text-based declarative languages rather than graphical tools. This enables version control, collaboration through code reviews, automation in CI/CD pipelines, and consistency across documentation.
Key Characteristics¶
- Paradigm: Declarative, text-based diagram definition
- Typing: Schema-based validation (tool-specific)
- Runtime: Various (JavaScript, Java, Python, Go-based renderers)
- Primary Use Cases:
- Architecture documentation (AWS, Azure, GCP, Kubernetes)
- Sequence and flow diagrams for API documentation
- Entity-relationship diagrams for database schemas
- CI/CD pipeline visualization
- Infrastructure topology mapping
- C4 model software architecture
This Style Guide Covers¶
- Mermaid (flowcharts, sequence diagrams, ER diagrams)
- PlantUML (UML diagrams, deployment diagrams)
- Python Diagrams library (cloud architecture)
- D2 (modern declarative diagrams)
- Graphviz/DOT (dependency graphs, state machines)
- Structurizr DSL (C4 model architecture)
Tool Comparison Matrix¶
| Feature | Mermaid | PlantUML | Python Diagrams | D2 | Graphviz | Structurizr |
|---|---|---|---|---|---|---|
| Rendering | Browser/JS | Java/Server | Python/Graphviz | Go CLI | C CLI | Cloud/CLI |
| GitHub Native | ✅ Yes | ❌ No | ❌ No | ❌ No | ❌ No | ❌ No |
| GitLab Native | ✅ Yes | ✅ Yes | ❌ No | ❌ No | ❌ No | ❌ No |
| MkDocs Support | ✅ Yes | ✅ Plugin | ❌ No | ❌ No | ❌ No | ❌ No |
| Cloud Icons | ❌ Limited | ✅ Yes | ✅ Excellent | ✅ Yes | ❌ No | ❌ No |
| C4 Model | ✅ Yes | ✅ Yes | ❌ No | ❌ No | ❌ No | ✅ Native |
| Learning Curve | Low | Medium | Medium | Low | High | Medium |
| Best For | Docs | UML | Cloud Arch | Modern | Graphs | C4 |
Quick Reference¶
| Category | Convention | Example | Notes |
|---|---|---|---|
| File Naming | |||
| Mermaid | kebab-case.mmd |
user-flow.mmd |
Or inline in Markdown |
| PlantUML | kebab-case.puml |
deployment-diagram.puml |
Also .plantuml, .pu |
| Python Diagrams | snake_case.py |
aws_architecture.py |
Standard Python naming |
| D2 | kebab-case.d2 |
service-mesh.d2 |
|
| Graphviz | kebab-case.dot |
dependency-graph.dot |
Also .gv |
| Structurizr | kebab-case.dsl |
system-context.dsl |
|
| Node Naming | |||
| Short IDs | lowercase |
db, api, web |
Graph node identifiers |
| Display Labels | Title Case |
"Web Server" |
Human-readable labels |
| Direction | |||
| Left-to-Right | LR / direction: right |
Architecture flows | Default for system diagrams |
| Top-to-Bottom | TB / direction: down |
Hierarchies, flows | Default for org charts |
| Colors | |||
| Success/Healthy | #28a745 / green |
Active services | |
| Warning | #ffc107 / yellow |
Degraded services | |
| Error/Critical | #dc3545 / red |
Failed services | |
| Info/Neutral | #007bff / blue |
Informational | |
| Line Length | |||
| Labels | Max 40 chars | "Process payment" |
Wrap longer text |
| Node Names | Max 30 chars | "Authentication Service" |
Use abbreviations if needed |
Mermaid¶
Overview¶
Mermaid is a JavaScript-based diagramming tool that renders diagrams from text definitions. It has native support in GitHub, GitLab, and MkDocs, making it ideal for documentation that lives alongside code.
Supported Diagram Types¶
mindmap
root((Mermaid))
Flowcharts
graph TD
graph LR
Sequence
Messages
Activations
Class
Classes
Relationships
State
States
Transitions
ER
Entities
Relations
Gantt
Tasks
Milestones
C4
Context
Container
Naming Conventions¶
graph LR
%% Good: Short IDs with descriptive labels
api[API Gateway]
auth[Auth Service]
db[(PostgreSQL)]
%% Good: Clear relationship labels
api -->|JWT Token| auth
auth -->|Query| db
graph LR
%% Bad: Long IDs make code hard to read
api_gateway_service_main[API Gateway]
authentication_authorization_service[Auth Service]
postgresql_primary_database[(PostgreSQL)]
api_gateway_service_main --> authentication_authorization_service
authentication_authorization_service --> postgresql_primary_database
Direction Standards¶
%% Good: Left-to-right for request flows
graph LR
client[Client] --> lb[Load Balancer]
lb --> web1[Web Server 1]
lb --> web2[Web Server 2]
web1 --> db[(Database)]
web2 --> db
%% Good: Top-to-bottom for hierarchies
graph TB
ceo[CEO]
ceo --> cto[CTO]
ceo --> cfo[CFO]
cto --> eng1[Engineering]
cto --> eng2[Platform]
cfo --> fin[Finance]
%% Bad: Bottom-to-top is counterintuitive
graph BT
db[(Database)] --> web[Web Server]
web --> client[Client]
Flowchart Patterns¶
graph TD
%% Standard shapes for different node types
start([Start])
process[Process Step]
decision{Decision?}
database[(Database)]
subproc[[Subprocess]]
io[/Input Output/]
finish([End])
start --> process
process --> decision
decision -->|Yes| database
decision -->|No| subproc
database --> io
subproc --> io
io --> finish
graph TD
%% Use subgraphs for logical grouping
subgraph Frontend
react[React App]
nginx[Nginx]
end
subgraph Backend
api[FastAPI]
worker[Celery Worker]
end
subgraph Data
postgres[(PostgreSQL)]
redis[(Redis)]
end
react --> nginx
nginx --> api
api --> postgres
api --> redis
worker --> redis
worker --> postgres
Sequence Diagram Standards¶
sequenceDiagram
%% Good: Clear participant aliases
participant C as Client
participant G as API Gateway
participant A as Auth Service
participant D as Database
%% Good: Descriptive messages
C->>G: POST /login {credentials}
activate G
G->>A: Validate credentials
activate A
A->>D: Query user
D-->>A: User record
A-->>G: JWT token
deactivate A
G-->>C: 200 OK {token}
deactivate G
%% Good: Notes for context
Note over C,G: HTTPS encrypted
Note right of A: Token expires in 1h
sequenceDiagram
%% Good: Show error handling
participant U as User
participant S as Service
participant DB as Database
U->>S: Request data
activate S
S->>DB: Query
activate DB
alt Success
DB-->>S: Data
S-->>U: 200 OK
else Not Found
DB-->>S: Empty
S-->>U: 404 Not Found
else Error
DB-->>S: Exception
S-->>U: 500 Error
end
deactivate DB
deactivate S
Entity-Relationship Diagrams¶
erDiagram
%% Good: Clear entity and relationship naming
USER ||--o{ ORDER : places
USER {
uuid id PK
string email UK
string name
timestamp created_at
}
ORDER ||--|{ ORDER_ITEM : contains
ORDER {
uuid id PK
uuid user_id FK
decimal total
string status
timestamp created_at
}
ORDER_ITEM }|--|| PRODUCT : references
ORDER_ITEM {
uuid id PK
uuid order_id FK
uuid product_id FK
int quantity
decimal price
}
PRODUCT {
uuid id PK
string name
string sku UK
decimal price
int stock
}
C4 Diagrams in Mermaid¶
C4Context
title System Context Diagram - E-Commerce Platform
Person(customer, "Customer", "A user who purchases products")
Person(admin, "Admin", "Internal staff managing products")
System(ecommerce, "E-Commerce Platform", "Allows customers to browse and purchase products")
System_Ext(payment, "Payment Gateway", "Handles payment processing")
System_Ext(shipping, "Shipping Provider", "Manages order fulfillment")
System_Ext(email, "Email Service", "Sends notifications")
Rel(customer, ecommerce, "Browses, purchases", "HTTPS")
Rel(admin, ecommerce, "Manages products", "HTTPS")
Rel(ecommerce, payment, "Processes payments", "HTTPS/API")
Rel(ecommerce, shipping, "Creates shipments", "HTTPS/API")
Rel(ecommerce, email, "Sends emails", "SMTP")
C4Container
title Container Diagram - E-Commerce Platform
Person(customer, "Customer")
System_Boundary(ecommerce, "E-Commerce Platform") {
Container(spa, "Web Application", "React", "Single-page application")
Container(api, "API Gateway", "Kong", "Routes and authenticates requests")
Container(catalog, "Catalog Service", "Python/FastAPI", "Product catalog management")
Container(orders, "Order Service", "Python/FastAPI", "Order processing")
Container(db, "Database", "PostgreSQL", "Stores all data")
Container(cache, "Cache", "Redis", "Session and data caching")
Container(queue, "Message Queue", "RabbitMQ", "Async processing")
}
Rel(customer, spa, "Uses", "HTTPS")
Rel(spa, api, "Calls", "HTTPS/JSON")
Rel(api, catalog, "Routes", "HTTP")
Rel(api, orders, "Routes", "HTTP")
Rel(catalog, db, "Reads/Writes", "SQL")
Rel(orders, db, "Reads/Writes", "SQL")
Rel(orders, queue, "Publishes", "AMQP")
Rel(api, cache, "Caches", "Redis Protocol")
Gantt Charts¶
gantt
title Project Timeline
dateFormat YYYY-MM-DD
section Planning
Requirements gathering :done, req, 2024-01-01, 2024-01-15
Architecture design :done, arch, after req, 2w
Technical specification :done, spec, after arch, 1w
section Development
Backend API :active, api, 2024-02-05, 4w
Frontend UI :active, ui, 2024-02-05, 4w
Database schema :db, after spec, 2w
Integration :int, after api, 2w
section Testing
Unit tests :test1, after api, 1w
Integration tests :test2, after int, 1w
UAT :uat, after test2, 1w
section Deployment
Staging deployment :stage, after uat, 3d
Production deployment :milestone, prod, after stage, 0d
Styling Guidelines¶
graph LR
%% Good: Consistent color scheme
classDef primary fill:#007bff,stroke:#0056b3,color:#fff
classDef success fill:#28a745,stroke:#1e7e34,color:#fff
classDef warning fill:#ffc107,stroke:#d39e00,color:#000
classDef danger fill:#dc3545,stroke:#bd2130,color:#fff
classDef neutral fill:#6c757d,stroke:#545b62,color:#fff
lb[Load Balancer]:::primary
web1[Web Server 1]:::success
web2[Web Server 2]:::success
db[(Database)]:::neutral
cache[(Cache)]:::warning
lb --> web1
lb --> web2
web1 --> db
web2 --> db
web1 -.-> cache
web2 -.-> cache
%%{init: {'theme': 'base', 'themeVariables': {
'primaryColor': '#007bff',
'primaryTextColor': '#fff',
'primaryBorderColor': '#0056b3',
'lineColor': '#6c757d',
'secondaryColor': '#28a745',
'tertiaryColor': '#f8f9fa'
}}}%%
graph TD
A[Service A] --> B[Service B]
B --> C[Service C]
C --> D[Service D]
Complexity Limits¶
%% Good: Focused diagram with clear purpose
graph LR
subgraph "User Request Flow"
client[Client] --> cdn[CDN]
cdn --> lb[Load Balancer]
lb --> api[API Server]
api --> db[(Database)]
end
## Bad: Overly complex diagram (avoid this)
## - More than 15-20 nodes becomes hard to read
## - Multiple crossing lines create visual noise
## - Too many subgraphs obscure the main message
## Instead:
## - Split into multiple focused diagrams
## - Use different C4 levels (Context, Container, Component)
## - Link diagrams together in documentation
Mermaid Configuration¶
# mkdocs.yml - Enable Mermaid support
markdown_extensions:
- pymdownx.superfences:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format
{
"mermaid.theme": "default",
"mermaid.backgroundColor": "transparent",
"mermaid.maxTextSize": 50000
}
PlantUML¶
PlantUML Overview¶
PlantUML is a Java-based tool that creates UML diagrams from text descriptions. It excels at detailed UML diagrams, deployment diagrams, and has extensive icon libraries for cloud architecture.
PlantUML Diagram Types¶
@startmindmap
* PlantUML
** Sequence
** Class
** Use Case
** Activity
** Component
** Deployment
** State
** Object
** Timing
** Network
** Wireframe
** Gantt
** MindMap
** JSON/YAML
@endmindmap
PlantUML Naming Conventions¶
@startuml
' Good: Clear participant naming with stereotypes
actor User <<Human>>
participant "API Gateway" as api <<Service>>
participant "Auth Service" as auth <<Microservice>>
database "PostgreSQL" as db <<Database>>
User -> api: POST /login
api -> auth: Validate credentials
auth -> db: SELECT user
db --> auth: User record
auth --> api: JWT token
api --> User: 200 OK
@enduml
@startuml
' Good: Component naming with technology tags
!define RECTANGLE(x) rectangle x
!define DATABASE(x) database x
package "Backend Services" {
[Catalog API] <<Python/FastAPI>>
[Order API] <<Python/FastAPI>>
[Payment API] <<Node.js>>
}
package "Data Layer" {
database "Products DB" <<PostgreSQL>>
database "Orders DB" <<PostgreSQL>>
database "Cache" <<Redis>>
}
[Catalog API] --> [Products DB]
[Order API] --> [Orders DB]
[Order API] --> [Cache]
[Payment API] --> [Orders DB]
@enduml
Sequence Diagrams¶
@startuml
title Order Processing Sequence
' Participants with clear naming
actor Customer
participant "Web App" as web
participant "API Gateway" as gateway
participant "Order Service" as order
participant "Inventory Service" as inventory
participant "Payment Service" as payment
queue "Message Queue" as queue
database "Database" as db
' Main flow
Customer -> web: Place order
activate web
web -> gateway: POST /orders
activate gateway
gateway -> order: Create order
activate order
' Parallel processing
order -> inventory: Check stock
activate inventory
inventory --> order: Stock available
deactivate inventory
order -> payment: Process payment
activate payment
payment --> order: Payment confirmed
deactivate payment
' Async notification
order ->> queue: Publish OrderCreated
order --> gateway: Order confirmed
deactivate order
gateway --> web: 201 Created
deactivate gateway
web --> Customer: Order confirmation
deactivate web
' Background processing
queue -> inventory: Reserve stock
queue -> payment: Capture payment
note right of queue
Async processing
ensures reliability
end note
@enduml
Class Diagrams¶
@startuml
' Good: Clean class diagram with relationships
skinparam classAttributeIconSize 0
abstract class BaseModel {
+id: UUID
+created_at: datetime
+updated_at: datetime
--
+save(): void
+delete(): void
}
class User extends BaseModel {
+email: str
+name: str
+password_hash: str
--
+verify_password(password: str): bool
+generate_token(): str
}
class Order extends BaseModel {
+user_id: UUID
+status: OrderStatus
+total: Decimal
--
+add_item(product: Product, qty: int): void
+calculate_total(): Decimal
+submit(): void
}
class OrderItem {
+order_id: UUID
+product_id: UUID
+quantity: int
+price: Decimal
}
class Product extends BaseModel {
+name: str
+sku: str
+price: Decimal
+stock: int
--
+reserve(qty: int): bool
+release(qty: int): void
}
enum OrderStatus {
PENDING
CONFIRMED
SHIPPED
DELIVERED
CANCELLED
}
User "1" -- "0..*" Order: places >
Order "1" *-- "1..*" OrderItem: contains
OrderItem "0..*" -- "1" Product: references >
Order -- OrderStatus
@enduml
Deployment Diagrams¶
@startuml
!include <awslib/AWSCommon>
!include <awslib/AWSSimplified>
!include <awslib/Compute/EC2>
!include <awslib/Compute/Lambda>
!include <awslib/Database/RDS>
!include <awslib/Database/ElastiCache>
!include <awslib/NetworkingContentDelivery/CloudFront>
!include <awslib/NetworkingContentDelivery/ELB>
!include <awslib/Storage/S3>
title AWS Production Architecture
CloudFront(cdn, "CloudFront CDN", "Content delivery")
S3(static, "S3 Static Assets", "Web assets")
package "VPC - Production" {
ELB(alb, "Application Load Balancer", "HTTPS termination")
package "Public Subnets" {
EC2(bastion, "Bastion Host", "SSH access")
}
package "Private Subnets - App Tier" {
EC2(app1, "App Server 1", "t3.medium")
EC2(app2, "App Server 2", "t3.medium")
}
package "Private Subnets - Data Tier" {
RDS(db, "PostgreSQL", "db.r5.large")
ElastiCache(cache, "Redis Cluster", "cache.r5.large")
}
}
Lambda(processor, "Event Processor", "Async tasks")
cdn --> static
cdn --> alb
alb --> app1
alb --> app2
app1 --> db
app2 --> db
app1 --> cache
app2 --> cache
app1 --> processor
@enduml
Component Diagrams¶
@startuml
title Microservices Architecture
package "API Layer" {
[API Gateway] as gateway
[GraphQL Server] as graphql
}
package "Core Services" {
[User Service] as user <<gRPC>>
[Product Service] as product <<gRPC>>
[Order Service] as order <<gRPC>>
[Payment Service] as payment <<gRPC>>
}
package "Infrastructure" {
[Service Mesh] as mesh <<Istio>>
queue "Event Bus" as events <<Kafka>>
[Config Server] as config <<Consul>>
}
package "Data Stores" {
database "User DB" as userdb <<PostgreSQL>>
database "Product DB" as productdb <<PostgreSQL>>
database "Order DB" as orderdb <<PostgreSQL>>
database "Cache" as cache <<Redis>>
}
gateway --> mesh
graphql --> mesh
mesh --> user
mesh --> product
mesh --> order
mesh --> payment
user --> userdb
product --> productdb
order --> orderdb
payment --> events
user --> config
product --> config
order --> config
user --> cache
product --> cache
@enduml
PlantUML Styling¶
@startuml
' Consistent color palette
!define PRIMARY_COLOR #007bff
!define SUCCESS_COLOR #28a745
!define WARNING_COLOR #ffc107
!define DANGER_COLOR #dc3545
!define NEUTRAL_COLOR #6c757d
skinparam backgroundColor #ffffff
skinparam shadowing false
skinparam component {
BackgroundColor PRIMARY_COLOR
FontColor #ffffff
BorderColor #0056b3
}
skinparam database {
BackgroundColor NEUTRAL_COLOR
FontColor #ffffff
BorderColor #545b62
}
skinparam queue {
BackgroundColor WARNING_COLOR
FontColor #000000
BorderColor #d39e00
}
skinparam actor {
BackgroundColor SUCCESS_COLOR
FontColor #ffffff
BorderColor #1e7e34
}
actor User
component "Web App" as web
component "API" as api
database "Database" as db
queue "Queue" as q
User --> web
web --> api
api --> db
api --> q
@enduml
PlantUML Configuration¶
# .plantuml configuration
# Server-side rendering (recommended for CI)
PLANTUML_SERVER=https://www.plantuml.com/plantuml
# Local rendering (requires Java)
java -jar plantuml.jar -tsvg diagram.puml
# Pre-commit hook for PlantUML
- repo: local
hooks:
- id: plantuml-syntax
name: Validate PlantUML syntax
entry: java -jar plantuml.jar -checkonly
language: system
files: \.(puml|plantuml)$
Python Diagrams Library¶
Python Diagrams Overview¶
The Python Diagrams library creates cloud architecture diagrams programmatically. It has excellent support for AWS, Azure, GCP, Kubernetes, and other cloud providers with official icons.
Python Diagrams Installation¶
# Install with pip
pip install diagrams
# Install with uv
uv add diagrams
# Install with graphviz dependency (required)
# macOS
brew install graphviz
# Ubuntu/Debian
apt-get install graphviz
# Windows
choco install graphviz
Basic Architecture Diagram¶
"""
@module aws_web_architecture
@description AWS three-tier web architecture diagram
@version 1.0.0
@author Tyler Dukes
@last_updated 2024-01-15
"""
from diagrams import Diagram, Cluster, Edge
from diagrams.aws.compute import EC2, ECS, Lambda
from diagrams.aws.database import RDS, ElastiCache
from diagrams.aws.network import ELB, CloudFront, Route53
from diagrams.aws.storage import S3
def create_architecture_diagram() -> None:
"""Generate AWS web architecture diagram."""
graph_attr = {
"fontsize": "14",
"bgcolor": "white",
"pad": "0.5",
"splines": "spline",
}
with Diagram(
"AWS Web Architecture",
show=False,
filename="aws_web_architecture",
outformat="png",
graph_attr=graph_attr,
direction="LR",
):
# DNS and CDN
dns = Route53("Route 53")
cdn = CloudFront("CloudFront")
static = S3("Static Assets")
# Load balancer
lb = ELB("Application LB")
# Application tier
with Cluster("Application Tier"):
app_servers = [
ECS("App Server 1"),
ECS("App Server 2"),
ECS("App Server 3"),
]
# Data tier
with Cluster("Data Tier"):
db_primary = RDS("PostgreSQL Primary")
db_replica = RDS("PostgreSQL Replica")
cache = ElastiCache("Redis Cache")
# Serverless
processor = Lambda("Event Processor")
# Connections
dns >> cdn >> lb
cdn >> static
lb >> app_servers
for server in app_servers:
server >> db_primary
server >> cache
server >> processor
db_primary >> Edge(style="dashed") >> db_replica
if __name__ == "__main__":
create_architecture_diagram()
Kubernetes Architecture¶
"""
@module kubernetes_architecture
@description Kubernetes microservices deployment diagram
@version 1.0.0
"""
from diagrams import Diagram, Cluster
from diagrams.k8s.clusterconfig import HPA
from diagrams.k8s.compute import Deployment, Pod, ReplicaSet
from diagrams.k8s.network import Ingress, Service
from diagrams.k8s.storage import PV, PVC, StorageClass
from diagrams.k8s.podconfig import ConfigMap, Secret
def create_k8s_diagram() -> None:
"""Generate Kubernetes architecture diagram."""
with Diagram(
"Kubernetes Microservices",
show=False,
filename="k8s_architecture",
direction="TB",
):
ingress = Ingress("ingress-nginx")
with Cluster("API Namespace"):
api_svc = Service("api-service")
api_hpa = HPA("api-hpa")
with Cluster("API Deployment"):
api_deploy = Deployment("api-deployment")
api_pods = [Pod("api-pod-1"), Pod("api-pod-2"), Pod("api-pod-3")]
api_config = ConfigMap("api-config")
api_secret = Secret("api-secrets")
with Cluster("Database Namespace"):
db_svc = Service("postgres-service")
with Cluster("StatefulSet"):
db_pods = [Pod("postgres-0"), Pod("postgres-1")]
with Cluster("Storage"):
sc = StorageClass("fast-storage")
pvc = PVC("postgres-pvc")
pv = PV("postgres-pv")
# Connections
ingress >> api_svc >> api_deploy >> api_pods
api_hpa >> api_deploy
api_config >> api_pods[0]
api_secret >> api_pods[0]
api_pods >> db_svc >> db_pods
sc >> pvc >> pv
if __name__ == "__main__":
create_k8s_diagram()
Multi-Cloud Architecture¶
"""
@module multi_cloud_architecture
@description Multi-cloud deployment with AWS, Azure, and GCP
@version 1.0.0
"""
from diagrams import Diagram, Cluster
from diagrams.aws.compute import EKS
from diagrams.aws.database import RDS
from diagrams.aws.network import Route53
from diagrams.azure.compute import AKS
from diagrams.azure.database import CosmosDb
from diagrams.gcp.compute import GKE
from diagrams.gcp.database import Spanner
from diagrams.onprem.network import Traefik
def create_multi_cloud_diagram() -> None:
"""Generate multi-cloud architecture diagram."""
with Diagram(
"Multi-Cloud Architecture",
show=False,
filename="multi_cloud",
direction="TB",
):
dns = Route53("Global DNS")
lb = Traefik("Global Load Balancer")
with Cluster("AWS - US East"):
aws_k8s = EKS("EKS Cluster")
aws_db = RDS("PostgreSQL")
aws_k8s >> aws_db
with Cluster("Azure - Europe"):
azure_k8s = AKS("AKS Cluster")
azure_db = CosmosDb("CosmosDB")
azure_k8s >> azure_db
with Cluster("GCP - Asia"):
gcp_k8s = GKE("GKE Cluster")
gcp_db = Spanner("Cloud Spanner")
gcp_k8s >> gcp_db
dns >> lb
lb >> aws_k8s
lb >> azure_k8s
lb >> gcp_k8s
if __name__ == "__main__":
create_multi_cloud_diagram()
CI/CD Pipeline Diagram¶
"""
@module cicd_pipeline
@description CI/CD pipeline architecture diagram
@version 1.0.0
"""
from diagrams import Diagram, Cluster, Edge
from diagrams.onprem.vcs import Github
from diagrams.onprem.ci import GithubActions, Jenkins
from diagrams.onprem.container import Docker
from diagrams.onprem.registry import Harbor
from diagrams.aws.compute import EKS
from diagrams.aws.devtools import Codebuild
from diagrams.onprem.security import Trivy, Vault
def create_cicd_diagram() -> None:
"""Generate CI/CD pipeline diagram."""
with Diagram(
"CI/CD Pipeline",
show=False,
filename="cicd_pipeline",
direction="LR",
):
# Source
github = Github("GitHub Repository")
with Cluster("CI Pipeline"):
actions = GithubActions("GitHub Actions")
with Cluster("Build Stage"):
lint = Codebuild("Lint & Test")
build = Docker("Build Image")
scan = Trivy("Security Scan")
with Cluster("Artifact Storage"):
registry = Harbor("Container Registry")
secrets = Vault("Secrets Manager")
with Cluster("CD Pipeline"):
deploy_dev = EKS("Dev Cluster")
deploy_staging = EKS("Staging Cluster")
deploy_prod = EKS("Prod Cluster")
# Flow
github >> actions
actions >> lint >> build >> scan
scan >> registry
secrets >> Edge(style="dashed") >> build
registry >> deploy_dev
registry >> Edge(label="approval") >> deploy_staging
registry >> Edge(label="approval") >> deploy_prod
if __name__ == "__main__":
create_cicd_diagram()
Naming and Style Conventions¶
"""
@module diagram_conventions
@description Examples of naming and style conventions
@version 1.0.0
"""
from diagrams import Diagram, Cluster, Edge
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
def create_conventions_example() -> None:
"""Demonstrate naming and style conventions."""
# Good: Descriptive diagram name
with Diagram(
"Payment Processing System", # Clear, specific name
show=False,
filename="payment_system", # snake_case filename
outformat=["png", "svg"], # Multiple output formats
direction="LR", # Explicit direction
graph_attr={
"fontsize": "12",
"bgcolor": "white",
"pad": "0.5",
"splines": "spline", # Curved lines
"nodesep": "0.8", # Node spacing
"ranksep": "1.0", # Rank spacing
},
):
# Good: Descriptive labels
with Cluster("Payment Gateway"):
gateway = EC2("API Gateway")
# Good: Edge labels for relationship context
gateway >> Edge(
label="HTTPS",
color="green",
style="bold",
) >> RDS("Transactions DB")
# Bad examples (don't do these):
# - Diagram("diagram1") # Non-descriptive name
# - filename="DIAGRAM" # Uppercase filename
# - No direction specified (defaults may not be intuitive)
# - No graph_attr (default spacing may be cramped)
Python Diagrams File Organization¶
diagrams/
├── __init__.py
├── README.md
├── requirements.txt
│
├── architecture/
│ ├── __init__.py
│ ├── aws_production.py
│ ├── kubernetes_cluster.py
│ └── multi_cloud.py
│
├── infrastructure/
│ ├── __init__.py
│ ├── network_topology.py
│ ├── security_architecture.py
│ └── disaster_recovery.py
│
├── pipelines/
│ ├── __init__.py
│ ├── cicd_pipeline.py
│ └── data_pipeline.py
│
└── output/
├── aws_production.png
├── aws_production.svg
└── ...
Configuration¶
# diagrams/config.py
"""
@module diagram_config
@description Shared configuration for diagram generation
@version 1.0.0
"""
from typing import Dict, Any
# Standard graph attributes
GRAPH_ATTRS: Dict[str, str] = {
"fontsize": "14",
"bgcolor": "white",
"pad": "0.5",
"splines": "spline",
"nodesep": "0.8",
"ranksep": "1.0",
}
# Standard node attributes
NODE_ATTRS: Dict[str, str] = {
"fontsize": "12",
"fontname": "Sans-Serif",
}
# Standard edge attributes
EDGE_ATTRS: Dict[str, str] = {
"fontsize": "10",
"fontname": "Sans-Serif",
}
# Output formats
OUTPUT_FORMATS = ["png", "svg"]
# Color palette
COLORS = {
"primary": "#007bff",
"success": "#28a745",
"warning": "#ffc107",
"danger": "#dc3545",
"neutral": "#6c757d",
}
D2¶
D2 Overview¶
D2 is a modern diagram scripting language that turns text into diagrams. It has a clean, intuitive syntax and produces aesthetically pleasing output with minimal configuration.
Installation¶
# macOS
brew install d2
# Linux
curl -fsSL https://d2lang.com/install.sh | sh -s --
# Windows
choco install d2
# Verify installation
d2 --version
D2 Basic Syntax¶
# Simple connection
client -> server: HTTP Request
# Multiple connections
client -> server
server -> database
server -> cache
# Bidirectional
client <-> server: WebSocket
# Containers (grouping)
aws: AWS Cloud {
vpc: VPC {
public: Public Subnet {
lb: Load Balancer
bastion: Bastion Host
}
private: Private Subnet {
app: Application Server
db: Database Server
}
}
}
# Connections across containers
aws.vpc.public.lb -> aws.vpc.private.app
aws.vpc.private.app -> aws.vpc.private.db
Shape Types¶
# Rectangle (default)
service: Web Service
# Oval
user: User {shape: oval}
# Circle
status: Status {shape: circle}
# Cylinder (database)
database: PostgreSQL {shape: cylinder}
# Queue
queue: Message Queue {shape: queue}
# Package
package: npm Package {shape: package}
# Cloud
cloud: AWS {shape: cloud}
# Person
actor: Customer {shape: person}
# Hexagon
lb: Load Balancer {shape: hexagon}
# Diamond (decision)
decision: Approved? {shape: diamond}
# Document
doc: Report {shape: document}
# Page
page: Dashboard {shape: page}
Architecture Diagram¶
direction: right
# Title
title: E-Commerce Platform Architecture {
shape: text
near: top-center
style: {
font-size: 24
bold: true
}
}
# External actors
customer: Customer {
shape: person
style: {
fill: "#e1f5fe"
}
}
admin: Admin {
shape: person
style: {
fill: "#fff3e0"
}
}
# CDN and DNS
dns: Route 53 {
shape: cloud
}
cdn: CloudFront {
shape: hexagon
}
# Application tier
app: Application Tier {
style: {
fill: "#e8f5e9"
}
lb: ALB {
shape: hexagon
}
web: Web Servers {
server1: Server 1
server2: Server 2
server3: Server 3
}
api: API Gateway
}
# Services tier
services: Microservices {
style: {
fill: "#fff8e1"
}
catalog: Catalog Service
orders: Order Service
payments: Payment Service
notifications: Notification Service
}
# Data tier
data: Data Tier {
style: {
fill: "#fce4ec"
}
postgres: PostgreSQL {
shape: cylinder
}
redis: Redis Cache {
shape: cylinder
}
s3: S3 Storage {
shape: cylinder
}
queue: SQS Queue {
shape: queue
}
}
# Connections
customer -> dns: HTTPS
admin -> dns: HTTPS
dns -> cdn
cdn -> app.lb
app.lb -> app.web.server1
app.lb -> app.web.server2
app.lb -> app.web.server3
app.web.server1 -> app.api
app.web.server2 -> app.api
app.web.server3 -> app.api
app.api -> services.catalog
app.api -> services.orders
app.api -> services.payments
services.catalog -> data.postgres
services.orders -> data.postgres
services.payments -> data.postgres
services.orders -> data.queue
services.notifications <- data.queue
services.catalog -> data.redis
services.orders -> data.redis
cdn -> data.s3: Static assets
Sequence Diagram¶
shape: sequence_diagram
customer: Customer
web: Web App
api: API Gateway
auth: Auth Service
db: Database
customer -> web: 1. Login request
web -> api: 2. POST /auth/login
api -> auth: 3. Validate credentials
auth -> db: 4. Query user
db -> auth: 5. User record
auth -> api: 6. Generate JWT
api -> web: 7. Return token
web -> customer: 8. Login success
Class Diagram¶
User: User {
shape: class
+id: UUID
+email: string
+name: string
-password_hash: string
+created_at: datetime
+verify_password(pwd): bool
+generate_token(): string
+update_profile(data): void
}
Order: Order {
shape: class
+id: UUID
+user_id: UUID
+status: OrderStatus
+total: decimal
+created_at: datetime
+add_item(product, qty): void
+calculate_total(): decimal
+submit(): void
+cancel(): void
}
Product: Product {
shape: class
+id: UUID
+name: string
+sku: string
+price: decimal
+stock: int
+reserve(qty): bool
+release(qty): void
}
OrderItem: OrderItem {
shape: class
+id: UUID
+order_id: UUID
+product_id: UUID
+quantity: int
+price: decimal
}
# Relationships
User -> Order: places {
source-arrowhead: 1
target-arrowhead: * {
shape: arrow
}
}
Order -> OrderItem: contains {
source-arrowhead: 1
target-arrowhead: * {
shape: diamond
style.filled: true
}
}
OrderItem -> Product: references {
source-arrowhead: *
target-arrowhead: 1
}
Styling¶
# Global styles
style: {
fill: transparent
stroke: "#333"
}
# Container with custom style
services: Services {
style: {
fill: "#e3f2fd"
stroke: "#1976d2"
stroke-width: 2
border-radius: 8
shadow: true
}
api: API {
style: {
fill: "#4caf50"
font-color: white
bold: true
}
}
db: Database {
shape: cylinder
style: {
fill: "#ff9800"
font-color: white
}
}
}
# Connection styles
services.api -> services.db: Query {
style: {
stroke: "#2196f3"
stroke-width: 2
stroke-dash: 5
}
}
D2 Configuration¶
# Generate PNG
d2 diagram.d2 diagram.png
# Generate SVG
d2 diagram.d2 diagram.svg
# Watch mode for development
d2 --watch diagram.d2 diagram.svg
# Custom theme
d2 --theme 200 diagram.d2 diagram.svg
# Sketch mode
d2 --sketch diagram.d2 diagram.svg
# Layout engine
d2 --layout elk diagram.d2 diagram.svg
# d2.yaml configuration file
layout: elk
theme: 200
sketch: false
pad: 100
Graphviz/DOT¶
Graphviz Overview¶
Graphviz is a graph visualization software that uses the DOT language. It's particularly powerful for dependency graphs, state machines, and complex network topologies where automatic layout is essential.
Graphviz Basic Syntax¶
digraph G {
// Graph attributes
rankdir=LR;
node [shape=box, style=rounded];
edge [color=gray];
// Nodes
A [label="Start"];
B [label="Process"];
C [label="End"];
// Edges
A -> B;
B -> C;
}
// Undirected graph
graph Network {
layout=neato;
node [shape=circle];
A -- B;
A -- C;
B -- C;
B -- D;
C -- D;
}
Dependency Graph¶
digraph Dependencies {
rankdir=BT;
node [shape=box, style="rounded,filled", fillcolor=lightblue];
edge [color=gray];
// Core packages
subgraph cluster_core {
label="Core";
style=filled;
fillcolor=lightyellow;
core_utils [label="utils"];
core_config [label="config"];
core_logger [label="logger"];
}
// Data layer
subgraph cluster_data {
label="Data Layer";
style=filled;
fillcolor=lightgreen;
data_models [label="models"];
data_repos [label="repositories"];
data_db [label="database"];
}
// Service layer
subgraph cluster_services {
label="Services";
style=filled;
fillcolor=lightpink;
svc_user [label="user_service"];
svc_order [label="order_service"];
svc_payment [label="payment_service"];
}
// API layer
subgraph cluster_api {
label="API";
style=filled;
fillcolor=lavender;
api_routes [label="routes"];
api_middleware [label="middleware"];
api_schemas [label="schemas"];
}
// Dependencies
core_logger -> core_config;
core_utils -> core_config;
data_models -> core_utils;
data_repos -> data_models;
data_repos -> data_db;
data_db -> core_config;
data_db -> core_logger;
svc_user -> data_repos;
svc_user -> core_logger;
svc_order -> data_repos;
svc_order -> svc_user;
svc_payment -> data_repos;
svc_payment -> svc_order;
api_routes -> svc_user;
api_routes -> svc_order;
api_routes -> svc_payment;
api_routes -> api_middleware;
api_middleware -> core_logger;
api_schemas -> data_models;
}
State Machine¶
digraph OrderStateMachine {
rankdir=LR;
node [shape=circle];
// States
start [shape=point, width=0.2];
pending [label="Pending"];
confirmed [label="Confirmed"];
processing [label="Processing"];
shipped [label="Shipped"];
delivered [label="Delivered", peripheries=2];
cancelled [label="Cancelled", peripheries=2];
// Transitions
start -> pending [label="create"];
pending -> confirmed [label="confirm"];
pending -> cancelled [label="cancel"];
confirmed -> processing [label="process"];
confirmed -> cancelled [label="cancel"];
processing -> shipped [label="ship"];
processing -> cancelled [label="cancel\n(refund)"];
shipped -> delivered [label="deliver"];
}
Network Topology¶
graph NetworkTopology {
layout=fdp;
overlap=false;
splines=true;
// Styling
node [shape=box, style=filled];
edge [len=2];
// Internet
internet [label="Internet", shape=cloud, fillcolor=lightblue];
// DMZ
subgraph cluster_dmz {
label="DMZ";
style=filled;
fillcolor=lightyellow;
fw_external [label="Firewall\n(External)", shape=hexagon, fillcolor=red, fontcolor=white];
lb [label="Load Balancer", shape=hexagon, fillcolor=orange];
waf [label="WAF", shape=hexagon, fillcolor=orange];
}
// Application Zone
subgraph cluster_app {
label="Application Zone";
style=filled;
fillcolor=lightgreen;
fw_internal [label="Firewall\n(Internal)", shape=hexagon, fillcolor=red, fontcolor=white];
web1 [label="Web Server 1", fillcolor=white];
web2 [label="Web Server 2", fillcolor=white];
app1 [label="App Server 1", fillcolor=white];
app2 [label="App Server 2", fillcolor=white];
}
// Data Zone
subgraph cluster_data {
label="Data Zone";
style=filled;
fillcolor=lightpink;
fw_data [label="Firewall\n(Data)", shape=hexagon, fillcolor=red, fontcolor=white];
db_primary [label="DB Primary", shape=cylinder, fillcolor=white];
db_replica [label="DB Replica", shape=cylinder, fillcolor=white];
cache [label="Redis Cache", shape=cylinder, fillcolor=white];
}
// Connections
internet -- fw_external;
fw_external -- waf;
waf -- lb;
lb -- web1;
lb -- web2;
web1 -- fw_internal;
web2 -- fw_internal;
fw_internal -- app1;
fw_internal -- app2;
app1 -- fw_data;
app2 -- fw_data;
fw_data -- db_primary;
fw_data -- cache;
db_primary -- db_replica [style=dashed, label="replication"];
}
Styling Conventions¶
digraph Styling {
// Standard graph attributes
rankdir=LR;
bgcolor=white;
fontname="Helvetica";
fontsize=12;
pad=0.5;
nodesep=0.5;
ranksep=1.0;
splines=spline;
// Standard node attributes
node [
shape=box,
style="rounded,filled",
fontname="Helvetica",
fontsize=11,
fillcolor="#e3f2fd",
color="#1976d2",
penwidth=1.5
];
// Standard edge attributes
edge [
fontname="Helvetica",
fontsize=10,
color="#666666",
penwidth=1.0
];
// Color classes
node [fillcolor="#4caf50", fontcolor=white] success;
node [fillcolor="#f44336", fontcolor=white] error;
node [fillcolor="#ff9800", fontcolor=white] warning;
node [fillcolor="#2196f3", fontcolor=white] info;
// Usage
A [label="Success", fillcolor="#4caf50", fontcolor=white];
B [label="Warning", fillcolor="#ff9800", fontcolor=black];
C [label="Error", fillcolor="#f44336", fontcolor=white];
D [label="Info", fillcolor="#2196f3", fontcolor=white];
A -> B -> C -> D;
}
Graphviz Configuration¶
# Generate PNG
dot -Tpng diagram.dot -o diagram.png
# Generate SVG
dot -Tsvg diagram.dot -o diagram.svg
# Generate PDF
dot -Tpdf diagram.dot -o diagram.pdf
# Different layout engines
neato -Tpng diagram.dot -o diagram.png # Spring model
fdp -Tpng diagram.dot -o diagram.png # Force-directed
circo -Tpng diagram.dot -o diagram.png # Circular
twopi -Tpng diagram.dot -o diagram.png # Radial
Structurizr (C4 Model)¶
Structurizr Overview¶
Structurizr is a DSL for creating software architecture diagrams following the C4 model (Context, Container, Component, Code). It provides a structured approach to documenting software architecture at multiple levels of abstraction.
C4 Model Levels¶
Level 1: System Context
└── Shows the system in context with users and external systems
Level 2: Container
└── Shows the high-level technology choices (web apps, databases, etc.)
Level 3: Component
└── Shows the internal components within each container
Level 4: Code
└── Shows the implementation details (classes, interfaces)
System Context Diagram¶
workspace {
name "E-Commerce Platform"
description "Architecture documentation for the e-commerce platform"
model {
# People
customer = person "Customer" "A user who browses and purchases products" {
tags "External"
}
admin = person "Administrator" "Internal staff managing the platform" {
tags "Internal"
}
support = person "Support Agent" "Customer support representative" {
tags "Internal"
}
# Software Systems
ecommerce = softwareSystem "E-Commerce Platform" "Allows customers to browse and purchase products" {
tags "Primary"
}
# External Systems
paymentGateway = softwareSystem "Payment Gateway" "Processes credit card payments" {
tags "External System"
}
shippingProvider = softwareSystem "Shipping Provider" "Handles order fulfillment and delivery" {
tags "External System"
}
emailService = softwareSystem "Email Service" "Sends transactional emails" {
tags "External System"
}
analytics = softwareSystem "Analytics Platform" "Collects and analyzes user behavior" {
tags "External System"
}
# Relationships
customer -> ecommerce "Browses products, places orders" "HTTPS"
admin -> ecommerce "Manages products, inventory, orders" "HTTPS"
support -> ecommerce "Handles customer inquiries" "HTTPS"
ecommerce -> paymentGateway "Processes payments" "HTTPS/REST"
ecommerce -> shippingProvider "Creates shipments" "HTTPS/REST"
ecommerce -> emailService "Sends emails" "SMTP"
ecommerce -> analytics "Sends events" "HTTPS"
}
views {
systemContext ecommerce "SystemContext" {
include *
autoLayout lr
}
styles {
element "Person" {
shape Person
background #08427b
color #ffffff
}
element "External" {
background #999999
}
element "Internal" {
background #08427b
}
element "Software System" {
background #1168bd
color #ffffff
}
element "Primary" {
background #438dd5
}
element "External System" {
background #999999
}
}
}
}
Container Diagram¶
workspace extends "context.dsl" {
model {
ecommerce = softwareSystem "E-Commerce Platform" {
# Web Applications
webapp = container "Web Application" "Single-page application for customers" "React, TypeScript" {
tags "Web Browser"
}
adminApp = container "Admin Portal" "Internal admin dashboard" "React, TypeScript" {
tags "Web Browser"
}
# API Layer
apiGateway = container "API Gateway" "Routes and authenticates API requests" "Kong" {
tags "API"
}
# Microservices
catalogService = container "Catalog Service" "Manages product catalog" "Python, FastAPI" {
tags "Microservice"
}
orderService = container "Order Service" "Handles order processing" "Python, FastAPI" {
tags "Microservice"
}
userService = container "User Service" "Manages user accounts" "Python, FastAPI" {
tags "Microservice"
}
paymentService = container "Payment Service" "Processes payments" "Node.js, Express" {
tags "Microservice"
}
notificationService = container "Notification Service" "Sends notifications" "Python, FastAPI" {
tags "Microservice"
}
# Data Stores
catalogDb = container "Catalog Database" "Stores product information" "PostgreSQL" {
tags "Database"
}
orderDb = container "Order Database" "Stores order information" "PostgreSQL" {
tags "Database"
}
userDb = container "User Database" "Stores user accounts" "PostgreSQL" {
tags "Database"
}
cache = container "Cache" "Caches frequently accessed data" "Redis" {
tags "Cache"
}
messageQueue = container "Message Queue" "Async message processing" "RabbitMQ" {
tags "Queue"
}
# Relationships
customer -> webapp "Uses" "HTTPS"
admin -> adminApp "Uses" "HTTPS"
webapp -> apiGateway "Calls" "HTTPS/JSON"
adminApp -> apiGateway "Calls" "HTTPS/JSON"
apiGateway -> catalogService "Routes" "HTTP/JSON"
apiGateway -> orderService "Routes" "HTTP/JSON"
apiGateway -> userService "Routes" "HTTP/JSON"
catalogService -> catalogDb "Reads/Writes" "SQL"
catalogService -> cache "Caches" "Redis Protocol"
orderService -> orderDb "Reads/Writes" "SQL"
orderService -> paymentService "Calls" "HTTP/JSON"
orderService -> messageQueue "Publishes" "AMQP"
userService -> userDb "Reads/Writes" "SQL"
userService -> cache "Caches" "Redis Protocol"
paymentService -> paymentGateway "Processes" "HTTPS"
notificationService -> messageQueue "Consumes" "AMQP"
notificationService -> emailService "Sends" "SMTP"
}
}
views {
container ecommerce "Containers" {
include *
autoLayout lr
}
styles {
element "Web Browser" {
shape WebBrowser
background #438dd5
color #ffffff
}
element "Microservice" {
shape Hexagon
background #85bbf0
}
element "Database" {
shape Cylinder
background #438dd5
color #ffffff
}
element "Cache" {
shape Cylinder
background #85bbf0
}
element "Queue" {
shape Pipe
background #85bbf0
}
element "API" {
shape RoundedBox
background #438dd5
color #ffffff
}
}
}
}
Component Diagram¶
workspace extends "containers.dsl" {
model {
orderService = container "Order Service" {
# API Layer
orderController = component "Order Controller" "REST API endpoints for orders" "FastAPI Router"
orderSchemas = component "Order Schemas" "Request/response validation" "Pydantic"
# Service Layer
orderServiceLayer = component "Order Service" "Business logic for orders" "Python"
paymentClient = component "Payment Client" "Client for payment service" "httpx"
inventoryClient = component "Inventory Client" "Client for inventory checks" "httpx"
# Repository Layer
orderRepository = component "Order Repository" "Data access for orders" "SQLAlchemy"
orderItemRepository = component "Order Item Repository" "Data access for order items" "SQLAlchemy"
# Domain Layer
orderModel = component "Order Model" "Order domain entity" "SQLAlchemy Model"
orderItemModel = component "Order Item Model" "Order item entity" "SQLAlchemy Model"
# Events
orderEventPublisher = component "Order Event Publisher" "Publishes order events" "Pika"
# Relationships
orderController -> orderSchemas "Validates with"
orderController -> orderServiceLayer "Uses"
orderServiceLayer -> paymentClient "Processes payments"
orderServiceLayer -> inventoryClient "Checks inventory"
orderServiceLayer -> orderRepository "Persists orders"
orderServiceLayer -> orderEventPublisher "Publishes events"
orderRepository -> orderModel "Maps"
orderRepository -> orderItemRepository "Uses"
orderItemRepository -> orderItemModel "Maps"
}
# External relationships
apiGateway -> orderController "Routes requests"
orderRepository -> orderDb "Queries"
orderEventPublisher -> messageQueue "Publishes to"
paymentClient -> paymentService "Calls"
}
views {
component orderService "OrderServiceComponents" {
include *
autoLayout tb
}
styles {
element "Component" {
background #85bbf0
color #000000
}
}
}
}
Deployment Diagram¶
workspace extends "containers.dsl" {
model {
production = deploymentEnvironment "Production" {
deploymentNode "AWS" {
tags "Cloud Provider"
deploymentNode "us-east-1" {
tags "Region"
deploymentNode "VPC" {
deploymentNode "Public Subnets" {
deploymentNode "ALB" {
loadBalancer = infrastructureNode "Application Load Balancer" {
technology "AWS ALB"
}
}
}
deploymentNode "Private Subnets - App" {
deploymentNode "EKS Cluster" {
deploymentNode "API Gateway Pod" {
containerInstance apiGateway
}
deploymentNode "Catalog Service Pod" {
containerInstance catalogService
}
deploymentNode "Order Service Pod" {
containerInstance orderService
}
deploymentNode "User Service Pod" {
containerInstance userService
}
}
}
deploymentNode "Private Subnets - Data" {
deploymentNode "RDS" {
containerInstance catalogDb
containerInstance orderDb
containerInstance userDb
}
deploymentNode "ElastiCache" {
containerInstance cache
}
deploymentNode "Amazon MQ" {
containerInstance messageQueue
}
}
}
}
}
deploymentNode "CloudFlare" {
cdn = infrastructureNode "CDN" {
technology "CloudFlare CDN"
}
}
}
}
views {
deployment ecommerce "Production" "ProductionDeployment" {
include *
autoLayout lr
}
styles {
element "Cloud Provider" {
background #232f3e
color #ffffff
}
element "Region" {
background #147eba
color #ffffff
}
}
}
}
Structurizr Configuration¶
# Install Structurizr CLI
# Download from https://github.com/structurizr/cli
# Validate DSL
structurizr-cli validate -workspace workspace.dsl
# Export to PlantUML
structurizr-cli export -workspace workspace.dsl -format plantuml
# Export to Mermaid
structurizr-cli export -workspace workspace.dsl -format mermaid
# Push to Structurizr Cloud
structurizr-cli push -workspace workspace.dsl -id WORKSPACE_ID -key API_KEY -secret API_SECRET
CI/CD Integration¶
GitHub Actions Workflow¶
# .github/workflows/diagrams.yml
name: Validate and Generate Diagrams
on:
push:
paths:
- 'docs/**/*.md'
- 'diagrams/**'
- '.github/workflows/diagrams.yml'
pull_request:
paths:
- 'docs/**/*.md'
- 'diagrams/**'
jobs:
validate-mermaid:
name: Validate Mermaid Diagrams
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Mermaid CLI
run: npm install -g @mermaid-js/mermaid-cli
- name: Validate Mermaid in Markdown
run: |
find docs -name '*.md' -exec grep -l '```mermaid' {} \; | while read file; do
echo "Validating Mermaid in $file"
mmdc -i "$file" -o /dev/null 2>&1 || exit 1
done
validate-plantuml:
name: Validate PlantUML Diagrams
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate PlantUML files
uses: docker://plantuml/plantuml:latest
with:
args: -checkonly diagrams/**/*.puml
generate-python-diagrams:
name: Generate Python Diagrams
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y graphviz
pip install diagrams
- name: Generate diagrams
run: |
for file in diagrams/**/*.py; do
echo "Generating diagram from $file"
python "$file"
done
- name: Upload generated diagrams
uses: actions/upload-artifact@v4
with:
name: generated-diagrams
path: diagrams/output/
validate-d2:
name: Validate D2 Diagrams
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install D2
run: |
curl -fsSL https://d2lang.com/install.sh | sh -s --
- name: Validate D2 files
run: |
for file in diagrams/**/*.d2; do
echo "Validating $file"
d2 fmt --check "$file"
done
validate-graphviz:
name: Validate Graphviz Diagrams
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Graphviz
run: sudo apt-get install -y graphviz
- name: Validate DOT files
run: |
for file in diagrams/**/*.dot; do
echo "Validating $file"
dot -Tsvg "$file" -o /dev/null
done
Pre-commit Hooks¶
# .pre-commit-config.yaml additions for diagram validation
repos:
# Mermaid validation (requires Node.js)
- repo: local
hooks:
- id: mermaid-lint
name: Validate Mermaid diagrams
entry: bash -c 'npx -y @mermaid-js/mermaid-cli -i "$@" -o /dev/null'
language: system
files: \.mmd$
pass_filenames: true
# PlantUML validation (requires Java)
- repo: local
hooks:
- id: plantuml-lint
name: Validate PlantUML diagrams
entry: java -jar /path/to/plantuml.jar -checkonly
language: system
files: \.(puml|plantuml)$
pass_filenames: true
# D2 formatting check
- repo: local
hooks:
- id: d2-fmt
name: Check D2 formatting
entry: d2 fmt --check
language: system
files: \.d2$
pass_filenames: true
# Graphviz validation
- repo: local
hooks:
- id: graphviz-lint
name: Validate Graphviz DOT files
entry: bash -c 'dot -Tsvg "$@" -o /dev/null'
language: system
files: \.(dot|gv)$
pass_filenames: true
# Python diagrams syntax check
- repo: local
hooks:
- id: python-diagrams-check
name: Check Python diagrams syntax
entry: python -m py_compile
language: system
files: diagrams/.*\.py$
pass_filenames: true
IDE Configuration¶
VS Code Extensions¶
{
"recommendations": [
"bierner.markdown-mermaid",
"jebbs.plantuml",
"terrastruct.d2",
"joaompinto.vscode-graphviz",
"tintinweb.graphviz-interactive-preview",
"systemticks.c4-dsl-extension"
]
}
VS Code Settings¶
{
"[mermaid]": {
"editor.formatOnSave": true,
"editor.tabSize": 2,
"editor.insertSpaces": true
},
"[plantuml]": {
"editor.formatOnSave": false,
"editor.tabSize": 2,
"editor.insertSpaces": true
},
"[d2]": {
"editor.formatOnSave": true,
"editor.tabSize": 2,
"editor.insertSpaces": true
},
"[dot]": {
"editor.formatOnSave": false,
"editor.tabSize": 2,
"editor.insertSpaces": true
},
"plantuml.server": "https://www.plantuml.com/plantuml",
"plantuml.render": "PlantUMLServer",
"plantuml.exportFormat": "svg",
"graphviz-interactive-preview.renderEngine": "dot",
"d2.execPath": "/usr/local/bin/d2",
"files.associations": {
"*.mmd": "mermaid",
"*.puml": "plantuml",
"*.plantuml": "plantuml",
"*.d2": "d2",
"*.dot": "dot",
"*.gv": "dot",
"*.dsl": "structurizr"
}
}
Project File Organization¶
project/
├── docs/
│ ├── architecture/
│ │ ├── system-context.md # Mermaid C4 context
│ │ ├── containers.md # Mermaid C4 containers
│ │ └── deployment.md # Mermaid deployment
│ │
│ └── api/
│ └── sequences/
│ ├── authentication.md # Mermaid sequence
│ └── order-flow.md # Mermaid sequence
│
├── diagrams/
│ ├── README.md
│ │
│ ├── architecture/ # Python Diagrams
│ │ ├── __init__.py
│ │ ├── aws_production.py
│ │ ├── kubernetes.py
│ │ └── multi_cloud.py
│ │
│ ├── uml/ # PlantUML
│ │ ├── class-diagram.puml
│ │ ├── deployment.puml
│ │ └── components.puml
│ │
│ ├── flows/ # D2
│ │ ├── user-journey.d2
│ │ └── data-flow.d2
│ │
│ ├── dependencies/ # Graphviz
│ │ ├── module-deps.dot
│ │ └── package-deps.dot
│ │
│ ├── c4/ # Structurizr
│ │ ├── workspace.dsl
│ │ └── views/
│ │
│ └── output/ # Generated images
│ ├── aws_production.png
│ ├── aws_production.svg
│ └── ...
│
└── .github/
└── workflows/
└── diagrams.yml # CI validation
Anti-Patterns¶
Overly Complex Diagrams¶
%% Bad: Too many nodes and connections
%% This diagram is hard to read and understand
graph TD
A --> B --> C --> D --> E --> F
A --> C
A --> D
B --> D
B --> E
C --> F
D --> F
E --> F
A --> F
%% ... imagine 20 more nodes
%% Good: Split into focused diagrams
%% Diagram 1: High-level overview
graph LR
subgraph "System Overview"
Client --> Gateway --> Services --> Database
end
Inconsistent Styling¶
# Bad: Inconsistent colors and styles
service1: Service 1 {
style.fill: red
}
service2: Service 2 {
style.fill: "#00ff00"
}
service3: Service 3 {
style.fill: blue
}
# No pattern, just random colors
# Good: Consistent color scheme
vars: {
d2-config: {
theme-id: 200
}
}
# Use semantic colors
healthy: Healthy Service {
style.fill: "#28a745"
}
degraded: Degraded Service {
style.fill: "#ffc107"
}
failed: Failed Service {
style.fill: "#dc3545"
}
Missing Labels¶
@startuml
' Bad: No context about relationships
A -> B
B -> C
C -> D
@enduml
@startuml
' Good: Clear labels explain the flow
actor User
User -> WebApp: HTTP Request
WebApp -> API: REST Call
API -> Database: SQL Query
@enduml
Wrong Tool for the Job¶
# Bad: Using Mermaid for complex UML class diagrams
# Mermaid's class diagram support is limited
# Good: Use PlantUML for detailed UML
# Use Mermaid for quick documentation diagrams
# Use Python Diagrams for cloud architecture
# Use D2 for modern, aesthetic diagrams
# Use Graphviz for complex dependency graphs
# Use Structurizr for formal C4 architecture
Accessibility Guidelines¶
Alt Text for Diagrams¶
<!-- Good: Descriptive alt text -->

<!-- Bad: Non-descriptive -->

Color Accessibility¶
%% Good: Use patterns and labels, not just color
graph LR
classDef success fill:#28a745,stroke:#1e7e34,stroke-width:2px
classDef warning fill:#ffc107,stroke:#d39e00,stroke-width:2px,stroke-dasharray: 5 5
classDef error fill:#dc3545,stroke:#bd2130,stroke-width:3px
A[Service A]:::success
B[Service B]:::warning
C[Service C]:::error
A -->|OK| B
B -->|Degraded| C
Text Descriptions¶
## System Architecture
The following diagram illustrates our three-tier architecture:
1. **Presentation Layer**: React SPA served via CloudFront CDN
2. **Application Layer**: Kubernetes-hosted microservices behind ALB
3. **Data Layer**: PostgreSQL primary with read replica, Redis cache
```mermaid
graph LR
CDN --> ALB --> Services --> Database
Key characteristics:
- All traffic encrypted with TLS 1.3
- Services communicate via gRPC
- Database connections pooled via PgBouncer
References¶
Official Documentation¶
- Mermaid Documentation
- PlantUML Language Reference
- Python Diagrams Library
- D2 Language Documentation
- Graphviz Documentation
- Structurizr DSL Reference
- C4 Model
Tools and Utilities¶
Related Guides¶
Maintainer: Tyler Dukes