Workspace¶
The Workspace is the top-level container for your entire architecture documentation. Think of it as your architecture’s universe — everything that exists in your system lives within a workspace. It holds your models (people, systems, containers, components), deployment environments, views, and styling rules. Without a workspace, architectural concepts are not organized or associated with a specific context.
Every buildzr project starts by creating a workspace using a context manager:
from buildzr.dsl import Workspace
with Workspace('My Architecture') as w:
# Define your architecture here
pass
Configuration¶
When creating a workspace, you can configure several important behaviors:
Name and Description¶
Every workspace needs a name. Descriptions are optional but recommended.
with Workspace(
'E-Commerce Platform',
description='Architecture for our online shopping system'
) as w:
pass
Scope¶
The scope parameter determines what level of architecture your workspace focuses on:
'landscape'- Multiple systems across your organization'software_system'(default) - A single software system in detailNone- No specific scope
# For documenting multiple systems
with Workspace('Enterprise Architecture', scope='landscape') as w:
crm = SoftwareSystem('CRM')
erp = SoftwareSystem('ERP')
warehouse = SoftwareSystem('Warehouse Management')
# For documenting a single system in depth
with Workspace('Payment Service', scope='software_system') as w:
with SoftwareSystem('Payment Service') as payment:
api = Container('API')
database = Container('Database')
worker = Container('Background Worker')
Implied Relationships¶
When implied_relationships=True, buildzr automatically creates parent-level relationships based on child-level ones. If your frontend container talks to their API container, it implies your system talks to their system.
with Workspace('w', implied_relationships=True) as w:
with SoftwareSystem('System A') as a:
frontend = Container('Frontend')
with SoftwareSystem('System B') as b:
api = Container('API')
# This explicitly creates: frontend >> api
# This implicitly creates: a >> b
frontend >> "Calls" >> api
See Implied Relationships for more details.
Group Separator¶
When using nested groups, the group_separator determines how group names are joined. The default is '/'.
with Workspace('w', group_separator='/') as w:
with Group("Engineering"):
with Group("Backend"):
api = SoftwareSystem('API')
# Full group name: "Engineering/Backend"
Hierarchical Structure¶
buildzr uses Python’s context managers (with statements) to create nested structures. This makes your code mirror your architecture’s hierarchy.
from buildzr.dsl import Workspace, SoftwareSystem, Container, Component
with Workspace('E-Commerce Platform') as w:
# Software System level
with SoftwareSystem('E-Commerce') as ecommerce:
# Container level
with Container('API') as api:
# Component level
auth = Component('Auth Service')
payment = Component('Payment Service')
catalog = Component('Catalog Service')
auth >> "Validates requests for" >> payment
auth >> "Validates requests for" >> catalog
The nesting naturally represents containment: components live in containers, containers live in systems, systems live in workspaces. No manual parent-child linking required.
Groups¶
Groups organize related elements visually in your diagrams. They don’t affect the logical architecture — they’re purely for presentation and communication.
from buildzr.dsl import Workspace, SoftwareSystem, Person, Group
with Workspace('w') as w:
with Group("Internal Systems"):
crm = SoftwareSystem('CRM')
erp = SoftwareSystem('ERP')
inventory = SoftwareSystem('Inventory Management')
with Group("External Systems"):
payment_gateway = SoftwareSystem('Stripe')
email_service = SoftwareSystem('SendGrid')
with Group("Users"):
employee = Person('Employee')
customer = Person('Customer')
Nested Groups¶
Groups can be nested to create hierarchical organization:
with Workspace('w') as w:
with Group("Company 1"):
with Group("Department 1"):
system_a = SoftwareSystem("System A")
system_b = SoftwareSystem("System B")
with Group("Department 2"):
system_c = SoftwareSystem("System C")
with Group("Company 2"):
with Group("Department 1"):
system_d = SoftwareSystem("System D")
with Group("Department 2"):
system_e = SoftwareSystem("System E")
The full group name for system_a would be "Company 1/Department 1" (using the default / separator).
Accessing Elements¶
After defining elements in your workspace, you can access them as attributes using transformed names:
with Workspace('w') as w:
user = Person('Web Application User')
payment_system = SoftwareSystem('Payment System')
# Access via original variable
user >> payment_system
# Or access via workspace attributes (names are lowercased and spaces become underscores)
w.web_application_user >> w.payment_system
You can also use dictionary-style access:
This is particularly useful when you need to reference elements defined in one part of your code from another part.
Exporting¶
Once you’ve defined your architecture, export it to JSON for visualization in tools like Structurizr:
# norun
with Workspace('My Architecture') as w:
# ... define your architecture ...
# Export to JSON
w.to_json('workspace.json')
# Export with pretty formatting
w.to_json('workspace_pretty.json', pretty=True)
The JSON file can be uploaded to Structurizr’s web interface or used with other C4 model visualization tools.
Complete Example¶
Here’s a complete example bringing together all workspace concepts:
from buildzr.dsl import (
Workspace,
Person,
SoftwareSystem,
Container,
Component,
SystemContextView,
ContainerView,
Group,
desc,
)
with Workspace(
'Online Banking System',
description='Core banking platform architecture',
scope='software_system',
implied_relationships=True
) as w:
# Define people
with Group("Users"):
customer = Person('Customer', description='Bank customer')
support = Person('Support Staff', description='Customer support team')
# Define our main system
with SoftwareSystem('Online Banking') as banking:
web_app = Container('Web Application', technology='React')
mobile_app = Container('Mobile App', technology='React Native')
with Container('API Gateway', technology='Node.js/Express') as api:
auth = Component('Authentication')
accounts = Component('Account Management')
transactions = Component('Transaction Processing')
auth >> "Protects" >> accounts
auth >> "Protects" >> transactions
database = Container('Database', technology='PostgreSQL')
web_app >> "Makes API calls to" >> api
mobile_app >> "Makes API calls to" >> api
api >> "Reads from and writes to" >> database
# External systems
with Group("External"):
email = SoftwareSystem('Email System', description='SendGrid')
payment = SoftwareSystem('Payment Gateway', description='Stripe')
# Relationships
customer >> [
desc("Uses") >> web_app,
desc("Uses") >> mobile_app,
]
support >> "Manages customers via" >> web_app
api >> "Sends notifications via" >> email
api >> "Processes payments via" >> payment
# Create views
SystemContextView(
software_system_selector=banking,
key='banking_context',
description='System context for online banking',
auto_layout='tb'
)
ContainerView(
software_system_selector=banking,
key='banking_containers',
description='Container view of online banking',
auto_layout='tb'
)
# Export (with pretty json formatting) 💅
w.to_json('workspace.json', pretty=True)