Overview
Chapter 03: C4 Model Visual Ontology & Structurizr Automation
Playbook Track: 05 – Presentation Slides & Architecture Diagrams (Visual Systems, Claude Code & Antigravity Workflows)
Target Audience: Year 1 Computer Science & Software Engineering Students Core Tooling Stack: The C4 Model, Structurizr DSL, Gemini 2.5 Pro (Architecture Modeling), Claude 3.7 Sonnet, Python 3.11+
Delivery Status: 🔍 Ready for Review (Tier 1 Markdown)
1. The Big Picture & Real-World Analogy
The Zoom Lens on Google Maps
Imagine you are using Google Maps to plan a trip:
- The Global View (Level 1: System Context): You see whole countries, continents, and oceans. You see that you are traveling from Tokyo to San Francisco. You do NOT see individual fire hydrants or living room sofas!
- The City View (Level 2: Containers): You zoom into San Francisco. You see highways, the bay, major airports, and hospitals. In software, these are deployable apps: the Web Server, the PostgreSQL database, and the Redis cache.
- The Building Floorplan (Level 3: Components): You zoom into the Airport Terminal. You see the baggage claim, security checkpoint, and ticket counter. In software, these are internal modules:
AuthController,PaymentService, andOrderRepository. - The Blueprint (Level 4: Code): You zoom into the baggage carousel motor wiring diagram. In software, this is actual class code and AST symbols.
Before Simon Brown invented the C4 Model, software architecture diagrams were a complete disaster called "Boxology": People drew a single messy picture with 25 random boxes: a customer, an AWS Lambda function, a single database table column, and an internal Java class all sitting side-by-side with no hierarchy!
The C4 Model brings scientific discipline to diagrams: you pick an explicit level of zoom, so executives see the big picture without drowning in code details, and engineers see exact deployment technologies.
2. Engineering Jargon Demystifier Table
| Industry Term | What It Actually Means | Freshman Student Analogy |
|---|---|---|
| C4 Model | A 4-level visual framework for software architecture: Context, Containers, Components, Code. | The zoom slider on Google Maps: World -> City -> Building -> Room floorplan. |
| Structurizr DSL | A standardized text language for defining C4 architecture models once, then generating multiple diagram views automatically. | Writing a database schema once and generating multiple SQL views and reports from it. |
| System Boundary | The boundary line separating what your team owns from external third-party software (like Stripe, Google, or Auth0). | The property fence around your house showing where your yard ends and the public street begins. |
| Container (C4) | A standalone deployable software program or data store (e.g. a Go web app, a PostgreSQL database, an iPhone app). | An individual physical building or vehicle that operates independently. |
| Component (C4) | A logical module or group of related classes inside a container (e.g. BillingService). |
An office or department inside a building. |
| Cross-Level Violation | An architectural error where an arrow skips levels (e.g. an external customer directly calling an internal database table). | A customer walking into a restaurant kitchen and taking raw meat out of the freezer instead of ordering from the waiter. |
| Orphaned Component | A component drawn on a diagram that has zero connections to any controller, service, or database. | A room in a house that has no doors or hallways leading into it. |
3. The 5-Minute Micro-Lab: C4 Boundary Violation Checker
Run this zero-dependency Python script to see how an automated C4 validator flags cross-level boundary violations:
"""
Micro-Lab: C4 Architectural Boundary Validator
PB-05 Chapter 3 Micro-Lab (Zero External Dependencies)
"""
def validate_c4_connections(relationships: list) -> list:
violations = []
for src, dst, proto in relationships:
# Rule: External Users cannot connect directly to internal Databases!
# They MUST pass through an API Gateway or Web App container.
if src.get("type") == "PERSON" and dst.get("type") == "DATABASE":
violations.append(
f"CROSS_LEVEL_VIOLATION: User '{src['name']}' directly accesses Database '{dst['name']}'! Must route through an API container."
)
# Rule: Components cannot be accessed directly from external systems
if src.get("level") == 1 and dst.get("level") == 3:
violations.append(
f"BOUNDARY_LEAK: External System '{src['name']}' directly invokes internal Component '{dst['name']}'."
)
return violations
if __name__ == "__main__":
actors = {
"customer": {"name": "Customer", "type": "PERSON", "level": 1},
"gateway": {"name": "API Gateway", "type": "CONTAINER", "level": 2},
"db": {"name": "CustomerDB", "type": "DATABASE", "level": 2},
"auth_comp": {"name": "TokenVerifier", "type": "COMPONENT", "level": 3}
}
# Case 1: Illegal architecture (User connects directly to DB!)
bad_edges = [(actors["customer"], actors["db"], "SQL Port 5432")]
# Case 2: Clean C4 architecture (User -> Gateway -> DB)
good_edges = [
(actors["customer"], actors["gateway"], "HTTPS REST"),
(actors["gateway"], actors["db"], "SQL Connection Pool")
]
print("=== Auditing Flawed Architecture ===")
v1 = validate_c4_connections(bad_edges)
for issue in v1:
print(f" [FLAGGED]: {issue}")
print("\n=== Auditing Clean Architecture ===")
v2 = validate_c4_connections(good_edges)
print(f"Violations Detected: {len(v2)} -> ARCHITECTURE IS CLEAN!")
4. Visual Ontology & Structurizr Single-Source Pipeline
In civil engineering, cartography, and electrical design, visual communication is governed by universal, mathematical standards:
- A map has standardized zoom levels: continent, country, city, street, and parcel. A cartographer never draws individual streetlights on a world map.
- An electrical blueprint uses standardized symbols for resistors, capacitors, and ground planes. An engineer never draws an ad-hoc cartoon lightning bolt to represent AC current.
Yet in software engineering, architecture diagrams frequently resemble an anarchic mess of shapes, colors, and line widths—derisively termed "Boxology":
- A single diagram arbitrarily mixes AWS Lambda functions (containers), an abstract payment platform (external system), a database table (data model), and an internal utility class (code).
- Stakeholders have no idea what level of zoom they are inspecting: an executive is overwhelmed by internal gRPC endpoints, while a developer lacks the information needed to deploy services.
To establish professional, scientific rigor in visual architecture, the industry relies on Simon Brown's C4 Model and Structurizr DSL.
+---------------------------------------------------------------------------------------------------+
| THE C4 MODEL HIERARCHICAL VISUAL ONTOLOGY |
+---------------------------------------------------------------------------------------------------+
| |
| LEVEL 1: SYSTEM CONTEXT |
| Zoom: 10,000 feet |
| Audience: Non-technical executives, product managers, developers |
| Scope: Software systems, external integrations, human users (People & Systems) |
| |
| LEVEL 2: CONTAINER DIAGRAM |
| Zoom: 5,000 feet |
| Audience: Solutions architects, DevOps engineers, tech leads |
| Scope: Deployable applications, microservices, datastores, message queues |
| (Must explicitly declare technology stacks: Go, PostgreSQL, Kafka) |
| |
| LEVEL 3: COMPONENT DIAGRAM |
| Zoom: 1,000 feet |
| Audience: Core software developers and code reviewers |
| Scope: Internal modules, controllers, handlers, repositories within a Container |
| |
| LEVEL 4: CODE / CLASS DIAGRAM |
| Zoom: Ground level (AST) |
| Audience: Individual contributors |
| Scope: Class diagrams, interfaces, entity-relationship models (Automated via AST) |
| |
+---------------------------------------------------------------------------------------------------+
1.1 The Single-Source-of-Truth Principle (Structurizr DSL)
A fatal flaw of traditional diagramming is drawing separate, uncoordinated files for Context, Containers, and Components. When a service is renamed, the architect must edit four different diagrams.
Structurizr DSL solves this by enforcing a Single Source of Truth Model:
- You define the architecture once in a declarative data model (Systems, Containers, Components, Relationships).
- The compiler renders multiple views from that single model:
- System Context View
- Container View
- Component View
- Dynamic Execution View
- Renaming a container in the model automatically cascades to all views simultaneously, preventing architectural drift.
2. C4 Model Zooming & Abstraction Lifecycle
flowchart TD
subgraph Level1["Level 1: System Context"]
User((Customer)) -->|HTTPS| ECommerceSystem["E-Commerce Platform
[Software System]"]
ECommerceSystem -->|API| PaymentGateway["Stripe Gateway
[External System]"]
end
subgraph Level2["Level 2: Container (Zoom inside E-Commerce System)"]
WebApp["Single Page App
[React / TS]"] -->|HTTPS / JSON| APIGw["API Gateway
[Envoy Proxy]"]
APIGw -->|gRPC| OrderSvc["Order Service
[Go / Gin]"]
OrderSvc -->|SQL / TCP| OrderDB[("Order Database
[PostgreSQL 16]")]
end
subgraph Level3["Level 3: Component (Zoom inside Order Service Container)"]
OrderController["Order Controller
[Gin Handler]"] -->|In-memory| OrderServiceLogic["Order Domain Service
[Go Core]"]
OrderServiceLogic -->|SQL Interface| OrderRepo["Order Repository
[GORM / SQL]"]
end
Level1 -. "Zoom In" .-> Level2
Level2 -. "Zoom In" .-> Level3
style Level1 fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px;
style Level2 fill:#e8f5e9,stroke:#4caf50,stroke-width:2px;
style Level3 fill:#fff3e0,stroke:#ff9800,stroke-width:2px;
3. Gate 2: Mandatory Manual vs. Programmatic Contrasts
Adopting the C4 visual ontology eliminates the ambiguity of ad-hoc "Boxology".
| Epistemic Dimension | Ad-Hoc "Boxology" (Manual Drawing) | C4 Model & Structurizr DSL | Operational Consequence |
|---|---|---|---|
| Abstraction Integrity | Inconsistent: boxes represent classes, databases, and third-party vendors simultaneously. | Strict 4-tier hierarchy: every node is explicitly typed as a Person, System, Container, or Component. | Eliminates cognitive confusion; audiences inspect only the abstraction level relevant to them. |
| Model Synchronization | Redundant: Context, Container, and Component diagrams are drawn in separate, disconnected files. | Unified model: a single .dsl file generates multiple views automatically. |
Renaming an entity in code updates all visual views instantly with zero manual redrawing. |
| Technology Specification | Omitted: boxes are labeled "Core Engine" without disclosing language, runtime, or framework. | Mandatory: every Container and Component must declare its underlying technology stack ([Go / Gin]). |
Prevents architectural blind spots during security, scalability, and infrastructure reviews. |
| Cross-Boundary Leakage | Frequent: external users are drawn connecting directly to internal private database tables. | Prevented: linter detects and rejects cross-level relationship violations programmatically. | Enforces strict network and security encapsulation in architectural designs. |
| AI Generation | Brittle: LLMs hallucinate arbitrary box layouts and unstandardized shapes. | Deterministic: LLMs emit structured Structurizr DSL or C4-Mermaid conforming to strict JSON schemas. | Enables autonomous AI agents to maintain system architecture documentation in CI/CD. |
4. Gate 3: Frontier AI Prompts & C4 Modeling Schemas
Frontier models like Gemini 2.5 Pro act as expert architecture modelers when provided with C4 ontology constraints.
4.1 C4 Architecture Modeling Prompt (gemini-2.5-pro)
SYSTEM INSTRUCTION: You are a Principal Enterprise Systems Architect and C4 Model Evangelist.
TASK: Analyze the provided system requirements or code repository and generate a formal C4 Model in Structurizr DSL.
CONSTRAINTS:
1. Strict Hierarchical Levels:
- Level 1: Define external People and Software Systems.
- Level 2: Decompose the primary system into deployable Containers (Web Apps, APIs, Workers, Databases, Queues). Every container MUST specify its technology stack.
- Level 3: Decompose the critical container into internal Components (Controllers, Domain Services, Repositories).
2. Zero Abstraction Jumping: Never connect a Person or External System directly to an internal Component. All external traffic must enter through a Container boundary.
3. Explicit Relationship Annotations: Every link must specify an action description and a protocol/technology (e.g., "Sends payments using HTTPS / REST").
4. Emit clean, compilable Structurizr DSL code enclosed in triple backticks.
4.2 Structured JSON Schema for C4 Workspaces (C4WorkspaceArchitectureSchema)
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "C4WorkspaceArchitecture",
"type": "object",
"properties": {
"name": { "type": "string" },
"description": { "type": "string" },
"elements": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"element_id": { "type": "string" },
"name": { "type": "string" },
"element_type": { "type": "string", "enum": ["PERSON", "SYSTEM", "CONTAINER", "COMPONENT"] },
"level": { "type": "string", "enum": ["CONTEXT", "CONTAINER", "COMPONENT", "CODE"] },
"description": { "type": "string" },
"technology": { "type": ["string", "null"] },
"parent_id": { "type": ["string", "null"] }
},
"required": ["element_id", "name", "element_type", "level", "description"]
}
},
"relationships": {
"type": "array",
"items": {
"type": "object",
"properties": {
"source_id": { "type": "string" },
"target_id": { "type": "string" },
"description": { "type": "string" },
"technology": { "type": ["string", "null"] }
},
"required": ["source_id", "target_id", "description"]
}
}
},
"required": ["name", "description", "elements", "relationships"]
}
5. Gate 4: Quantitative Visual & Tooling Trade-Off Matrix
Choosing a C4 modeling implementation involves fundamental trade-offs:
| Implementation Approach | Abstraction Level Enforcement | Multi-View Generation from Single Model | Git Diffability | CI/CD Linting Integration | Interactive Web UI |
|---|---|---|---|---|---|
| Manual Draw.io C4 Stencils | [FAIL] None (Pure drawing) | [FAIL] None (Redraw per view) | Poor (Binary/XML) | [FAIL] None | [FAIL] Static image only |
| C4-PlantUML Library | Moderate (Macros: Container()) |
Partial (Separate .puml files) |
Good (Text) | Moderate (Java/Graphviz) | Moderate (PlantUML server) |
| Mermaid C4 Syntax | Moderate (Experimental syntax) | Partial (Separate markdown blocks) | Excellent (Native Git) | Native (Node CLI) | Native browser render |
| Native Structurizr DSL | Strict (Compiler enforced) | Native (One model $ o$ all views) | Superior (Clean DSL) | High (Structurizr CLI) | Rich (Pan, zoom, animations) |
| LikeC4 (Next-Gen TS/DSL) | Strict (Type-safe hierarchy) | Native (Automated view generation) | Superior (TypeScript-like) | Fast (Node/Rust binary) | State-of-the-Art Web App |
6. Gate 5: The 10 Methodological Threats to Validity & C4 Anti-Patterns
Architects modeling systems with C4 must defend against ten common failure modes:
1. Abstraction Boundary Leakage (Cross-Level Jumping)
- Anti-Pattern: An arrow connecting an external User directly to an internal database or component, bypassing the container boundary.
- Defense: Enforce automated linting: flag any relationship between a Level 1 element and a Level 3 element as a fatal hierarchy breach.
2. Missing Technology Stack Declarations
- Anti-Pattern: Drawing containers labeled only as "Backend Service" without indicating whether it is Python, Go, Java, or Rust.
- Defense: Mandatory metadata schema: require
technologystrings on all Container and Component definitions.
3. Conflating Docker Containers with C4 Containers
- Anti-Pattern: Assuming every Docker image is a C4 container. In C4, a container is a deployable unit of compute or storage (e.g., a Single-Page App in S3, a relational database, or a worker process).
- Defense: Define C4 containers based on process execution and storage boundaries rather than virtualization packaging.
4. The "Infinite Component" Explosion
- Anti-Pattern: Attempting to model all 150 internal classes of a microservice in a Component diagram, reproducing the codebase as an unreadable diagram.
- Defense: Limit Component diagrams to coarse-grained architectural components (Controllers, Domain Services, Gateways, Repositories).
5. Multi-Model Synchronization Rot
- Anti-Pattern: Maintaining Context, Container, and Component diagrams across separate graphics files, allowing them to drift out of sync.
- Defense: Use Structurizr DSL or unified C4 data structures where views are rendered dynamically from a single canonical model.
6. Unscoped External Dependencies
- Anti-Pattern: Drawing external cloud services (AWS S3, SendGrid) inside the enterprise system boundary.
- Defense: Explicitly mark external systems using
softwareSystem "..." { ... }with external tags to maintain the clear scope of ownership.
7. Missing Protocol Semantics in Relationships
- Anti-Pattern: Relationships labeled simply "calls" or "uses" without stating whether communication is synchronous HTTP, gRPC, or asynchronous message queuing.
- Defense: Enforce the C4 relationship standard:
[Description] [Protocol](e.g.,"Submits order using HTTPS / JSON").
8. Orphaned Internal Components
- Anti-Pattern: Defining a component with business logic that has no assigned parent container.
- Defense: Structural validation rule: every Component must have a valid
parent_idreferencing an existing Container.
9. Neglecting Deployment Views
- Anti-Pattern: Showing static container relationships but omitting how containers map onto actual cloud infrastructure (Kubernetes pods, availability zones, read replicas).
- Defense: Complement structural C4 views with dedicated C4 Deployment Diagrams illustrating infrastructure nodes.
10. Over-Engineering Level 4 (Code Diagrams)
- Anti-Pattern: Spending hours manually drawing UML class diagrams for code that changes daily.
- Defense: Never draw Level 4 manually; generate class and AST diagrams on demand using IDE tools (e.g., Tree-sitter or compiler plugins).
11. Gate 6: Mandatory Hands-On Lab (Visual Engineering Challenge)
Objective
You will engineer an automated C4 Hierarchy Validator & Structurizr DSL Generator in zero-dependency Python 3.11+. The engine will ingest a C4 architectural model, enforce strict abstraction boundary rules, detect orphaned components and cross-level violations, and compile the model into valid Structurizr DSL.
Experimental Protocol
- Model Formulation: Define a multi-tier payment platform containing Persons, Software Systems, Containers (API Gateway, Ledger DB), and internal Components (JWT Authenticator).
- Hierarchy Validation: Verify that components have valid parent containers, ensure technology stacks are declared, and guarantee that no cross-level abstraction violations occur.
- Structurizr DSL Compilation: Transpile the validated in-memory model into standard Structurizr DSL with automated view generation.
- Error Injection & Defense: Test that the validator intercepts orphaned components and cross-level jumps with precise error codes.
12. Gate 7: Mandatory Recommended Answer & Executable Solution
The following zero-dependency Python 3.11+ script provides the complete, tested reference implementation of the C4 Hierarchy Validator & Structurizr DSL Generator.
"""
test_ch03_diagram_engine.py
Zero-dependency Python 3.11+ engine for PB-05 Chapter 3:
C4HierarchyValidator & StructurizrDslGenerator
"""
from dataclasses import dataclass, field
from enum import Enum
from typing import List, Dict, Any, Optional
class C4Level(str, Enum):
CONTEXT = "CONTEXT" # Level 1: People & Software Systems
CONTAINER = "CONTAINER" # Level 2: Applications, Microservices, Datastores
COMPONENT = "COMPONENT" # Level 3: Modules, Controllers, Repositories
CODE = "CODE" # Level 4: Classes / Functions
class C4ElementType(str, Enum):
PERSON = "PERSON"
SYSTEM = "SYSTEM"
CONTAINER = "CONTAINER"
COMPONENT = "COMPONENT"
@dataclass
class C4Element:
element_id: str
name: str
element_type: C4ElementType
level: C4Level
description: str
technology: Optional[str] = None
parent_id: Optional[str] = None
@dataclass
class C4Relationship:
source_id: str
target_id: str
description: str
technology: Optional[str] = None
@dataclass
class C4Workspace:
name: str
description: str
elements: Dict[str, C4Element] = field(default_factory=dict)
relationships: List[C4Relationship] = field(default_factory=list)
class C4HierarchyValidator:
"""Validates structural encapsulation and prevents cross-level abstraction leakage in C4 models."""
@classmethod
def validate(cls, workspace: C4Workspace) -> List[Dict[str, str]]:
findings: List[Dict[str, str]] = []
# Rule 1: Every Component MUST have a valid Container parent
for elem in workspace.elements.values():
if elem.level == C4Level.COMPONENT:
if not elem.parent_id:
findings.append({
"code": "C4_001",
"severity": "ERROR",
"message": f"Component '{elem.name}' (id: {elem.element_id}) is orphaned: missing required parent Container.",
"target": elem.element_id
})
elif elem.parent_id not in workspace.elements or workspace.elements[elem.parent_id].level != C4Level.CONTAINER:
findings.append({
"code": "C4_002",
"severity": "ERROR",
"message": f"Component '{elem.name}' parent '{elem.parent_id}' is not a valid Container.",
"target": elem.element_id
})
# Rule 2: Enforce technology specification on Containers and Components
for elem in workspace.elements.values():
if elem.level in [C4Level.CONTAINER, C4Level.COMPONENT]:
if not elem.technology or elem.technology.strip() == "":
findings.append({
"code": "C4_003",
"severity": "WARNING",
"message": f"Element '{elem.name}' ({elem.level.value}) lacks an explicit technology stack definition.",
"target": elem.element_id
})
# Rule 3: Abstraction boundary integrity: Disallow cross-level relationship jumping
# A Context level element (Person/External System) should never directly connect to an internal Component (Level 3)
for rel in workspace.relationships:
src = workspace.elements.get(rel.source_id)
tgt = workspace.elements.get(rel.target_id)
if not src or not tgt:
findings.append({
"code": "C4_004",
"severity": "ERROR",
"message": f"Dangling relationship between '{rel.source_id}' and '{rel.target_id}'.",
"target": f"{rel.source_id}->{rel.target_id}"
})
continue
if (src.level == C4Level.CONTEXT and tgt.level == C4Level.COMPONENT) or \
(src.level == C4Level.COMPONENT and tgt.level == C4Level.CONTEXT):
findings.append({
"code": "C4_005",
"severity": "ERROR",
"message": f"Cross-level abstraction violation: Relationship '{src.name} ({src.level.value}) -> {tgt.name} ({tgt.level.value})' bypasses the Container boundary.",
"target": f"{rel.source_id}->{rel.target_id}"
})
return findings
class StructurizrDslGenerator:
"""Compiles verified C4 workspaces into standard Structurizr DSL."""
@classmethod
def generate_dsl(cls, workspace: C4Workspace) -> str:
lines = [
f"workspace \"{workspace.name}\" \"{workspace.description}\" {{",
" model {",
]
# 1. Top-level Persons & Systems
people = [e for e in workspace.elements.values() if e.element_type == C4ElementType.PERSON]
systems = [e for e in workspace.elements.values() if e.element_type == C4ElementType.SYSTEM]
containers = [e for e in workspace.elements.values() if e.element_type == C4ElementType.CONTAINER]
components = [e for e in workspace.elements.values() if e.element_type == C4ElementType.COMPONENT]
for p in people:
lines.append(f" {p.element_id} = person \"{p.name}\" \"{p.description}\"")
for s in systems:
lines.append(f" {s.element_id} = softwareSystem \"{s.name}\" \"{s.description}\" {{")
# Embed Containers belonging to this System
sys_containers = [c for c in containers if c.parent_id == s.element_id or c.parent_id is None]
for c in sys_containers:
tech_str = f" \"{c.technology}\"" if c.technology else ""
lines.append(f" {c.element_id} = container \"{c.name}\" \"{c.description}\"{tech_str} {{")
# Embed Components belonging to this Container
cont_components = [cmp for cmp in components if cmp.parent_id == c.element_id]
for cmp in cont_components:
cmp_tech = f" \"{cmp.technology}\"" if cmp.technology else ""
lines.append(f" {cmp.element_id} = component \"{cmp.name}\" \"{cmp.description}\"{cmp_tech}")
lines.append(" }")
lines.append(" }")
# 2. Relationships
lines.append("")
for r in workspace.relationships:
tech_str = f" \"{r.technology}\"" if r.technology else ""
lines.append(f" {r.source_id} -> {r.target_id} \"{r.description}\"{tech_str}")
lines.extend([
" }",
" views {",
" systemContext " + (systems[0].element_id if systems else "system") + " \"SystemContext\" {",
" include *",
" autoLayout",
" }",
" }",
"}"
])
return "\n".join(lines)
# ==========================================
# Self-Test Verification Suite
# ==========================================
if __name__ == "__main__":
import unittest
class TestC4ModelEngine(unittest.TestCase):
def setUp(self):
self.ws = C4Workspace(
name="PaymentPlatform",
description="Enterprise Payment Processing Infrastructure"
)
# Level 1: Person & System
self.ws.elements["customer"] = C4Element("customer", "Customer", C4ElementType.PERSON, C4Level.CONTEXT, "E-commerce buyer")
self.ws.elements["payment_sys"] = C4Element("payment_sys", "Payment Platform", C4ElementType.SYSTEM, C4Level.CONTEXT, "Core payment engine")
# Level 2: Containers
self.ws.elements["api_gateway"] = C4Element("api_gateway", "API Gateway", C4ElementType.CONTAINER, C4Level.CONTAINER, "Routes requests", technology="Envoy Proxy", parent_id="payment_sys")
self.ws.elements["payment_db"] = C4Element("payment_db", "Ledger Database", C4ElementType.CONTAINER, C4Level.CONTAINER, "Stores transactions", technology="PostgreSQL 16", parent_id="payment_sys")
# Level 3: Components inside API Gateway
self.ws.elements["auth_filter"] = C4Element("auth_filter", "JWT Authenticator", C4ElementType.COMPONENT, C4Level.COMPONENT, "Validates tokens", technology="Go Middleware", parent_id="api_gateway")
# Legal Relationships
self.ws.relationships.append(C4Relationship("customer", "api_gateway", "Submits payment request", "HTTPS / JSON"))
self.ws.relationships.append(C4Relationship("auth_filter", "payment_db", "Logs audit token", "SQL"))
def test_clean_c4_validation_and_dsl_generation(self):
findings = C4HierarchyValidator.validate(self.ws)
errors = [f for f in findings if f["severity"] == "ERROR"]
self.assertEqual(len(errors), 0)
dsl = StructurizrDslGenerator.generate_dsl(self.ws)
self.assertIn("workspace \"PaymentPlatform\"", dsl)
self.assertIn("customer = person \"Customer\"", dsl)
self.assertIn("api_gateway = container \"API Gateway\"", dsl)
self.assertIn("auth_filter = component \"JWT Authenticator\"", dsl)
def test_catch_orphaned_component(self):
# Create a component without a parent
self.ws.elements["rogue_comp"] = C4Element("rogue_comp", "Rogue Component", C4ElementType.COMPONENT, C4Level.COMPONENT, "Unparented logic", technology="Python")
findings = C4HierarchyValidator.validate(self.ws)
orphans = [f for f in findings if f["code"] == "C4_001"]
self.assertEqual(len(orphans), 1)
self.assertEqual(orphans[0]["target"], "rogue_comp")
def test_catch_cross_level_boundary_violation(self):
# Illegal: Customer (Level 1 Context) directly connecting to internal auth_filter Component (Level 3)
self.ws.relationships.append(C4Relationship("customer", "auth_filter", "Direct illegal component call"))
findings = C4HierarchyValidator.validate(self.ws)
violations = [f for f in findings if f["code"] == "C4_005"]
self.assertEqual(len(violations), 1)
def test_warning_on_missing_technology(self):
# Container without tech
self.ws.elements["no_tech_cont"] = C4Element("no_tech_cont", "Worker Container", C4ElementType.CONTAINER, C4Level.CONTAINER, "Async worker", parent_id="payment_sys")
findings = C4HierarchyValidator.validate(self.ws)
tech_warnings = [f for f in findings if f["code"] == "C4_003"]
self.assertTrue(len(tech_warnings) >= 1)
suite = unittest.TestLoader().loadTestsFromTestCase(TestC4ModelEngine)
runner = unittest.TextTestRunner(verbosity=2)
test_result = runner.run(suite)
if not test_result.wasSuccessful():
exit(1)
print("\n[PASS] All PB-05 Chapter 3 Unit Tests Passed Successfully (100% Conformance).")
Verification & Execution Output
When executed in Python 3.11+, this engine confirms clean C4 validation, Structurizr DSL compilation, orphan component detection, and boundary violation interception:
test_catch_cross_level_boundary_violation (__main__.TestC4ModelEngine.test_catch_cross_level_boundary_violation) ... ok
test_catch_orphaned_component (__main__.TestC4ModelEngine.test_catch_orphaned_component) ... ok
test_clean_c4_validation_and_dsl_generation (__main__.TestC4ModelEngine.test_clean_c4_validation_and_dsl_generation) ... ok
test_warning_on_missing_technology (__main__.TestC4ModelEngine.test_warning_on_missing_technology) ... ok
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
[PASS] All PB-05 Chapter 3 Unit Tests Passed Successfully (100% Conformance).
9. Summary & Visual Engineering Milestone Checklist
Before moving to Chapter 04 (Programmatic Slide Generation with Python-PPTX & Marp):
- Mastered the 4-tier C4 Model visual ontology (Context, Container, Component, Code).
- Implemented single-source-of-truth modeling using Structurizr DSL paradigms.
- Contrasted naive "Boxology" with formal C4 hierarchical encapsulation.
- Calibrated Gemini 2.5 Pro prompts for C4 architecture extraction from codebases.
- Compiled the Quantitative Trade-Off Matrix for C4 modeling frameworks.
- Analyzed and mitigated the 10 Critical C4 Anti-Patterns (including boundary leakage).
- Executed and validated the zero-dependency Python 3.11+ C4 validator and DSL engine.