9.4 KiB
C4 Model Relations - Detailed Reference
Table of Contents
- Protocol Documentation Guidelines
- Direction vs Coupling
- Best Practices per Level
- Graph Validity Rules
- Common Patterns
Relation Type Definitions
For complete type definitions for all C4 levels, see types.md.
Protocol Documentation Guidelines
When to Document Protocol
Always include protocol for:
- C1 system-to-system communication
- C2 container-to-container communication
- External integrations
- Any network communication
Optional for:
- C3 code-level dependencies (unless calling external APIs)
- In-process method calls
Protocol Format
Use standard protocol names:
Good:
HTTP/RESTHTTP/2 gRPCPostgreSQL Wire ProtocolAMQPOAuth 2.0
Bad:
rest(too vague)http(specify REST, GraphQL, etc.)database(specify PostgreSQL, MySQL, etc.)
Protocol Details to Include
For HTTP-based protocols:
- HTTP version (HTTP/1.1, HTTP/2)
- API style (REST, GraphQL, RPC)
- Authentication method
- Content type (JSON, XML, etc.)
For Database protocols:
- Database type (PostgreSQL, MySQL, MongoDB)
- Connection method (wire protocol, ORM)
- Authentication method
For Messaging protocols:
- Broker type (RabbitMQ, Kafka, SQS)
- Protocol (AMQP, Kafka Protocol)
- Pattern (pub-sub, work queue)
Direction vs Coupling
Direction (C1 Level)
Purpose: Describes the flow of communication between systems
outbound
Definition: Source system initiates communication Example: Frontend makes HTTP requests to API Use when: Source actively calls, queries, or requests from target
inbound
Definition: Target system initiates communication Example: External webhook calls your API Use when: Target pushes data, calls back, or triggers source
bidirectional
Definition: Communication flows both ways Example: WebSocket connection with messages in both directions Use when: True two-way communication (avoid overusing)
Best Practice: Prefer outbound/inbound over bidirectional for clarity. Create two separate relations if needed.
Coupling (C3 Level)
Purpose: Describes strength of dependency between components
loose
Definition: Minimal dependency, easily replaceable Characteristics:
- Components interact through interfaces or abstractions
- Easy to test (can use mocks)
- Easy to swap implementations
- Changes in one component don't force changes in another
Examples:
- Dependency injection
- Interface-based dependencies
- Event-driven communication
- Plugin architectures
tight
Definition: Strong dependency, hard to replace Characteristics:
- Direct class references
- Hard to test without real implementation
- Hard to swap implementations
- Changes cascade between components
Examples:
- Direct class instantiation
- Class inheritance
- Static method calls
- Global state dependencies
Best Practice: Prefer loose coupling. Document tight coupling as potential refactoring opportunity.
Best Practices per Level
C1 System Context Best Practices
-
Focus on protocols
- Always specify communication protocol
- Include authentication method for external relations
- Document sync vs async nature
-
Specify direction
- Use outbound for active calls (API requests, queries)
- Use inbound for passive receives (webhooks, callbacks)
- Avoid bidirectional unless truly necessary
-
Document external integrations
- Mark external services clearly
- Include vendor name (Stripe, SendGrid, etc.)
- Note criticality for business operations
-
Group similar relations
- One relation for "Frontend → API" covering all endpoints
- Don't create separate relations for each API endpoint
C2 Container Best Practices
-
Be specific about API style
- Use
http-restnot justhttp - Use
http-graphqlfor GraphQL - Distinguish between REST and RPC
- Use
-
Differentiate read vs write
- Use
database-queryfor read-only - Use
database-writefor write-only - Use
database-read-writefor both
- Use
-
Document cache patterns
- Specify cache operations (read, write, both)
- Include eviction strategy if relevant
- Note cache hit/miss criticality
-
Show message patterns
- Use
message-publishfor producers - Use
message-subscribefor consumers - Document topic/queue names in description
- Use
C3 Component Best Practices
-
Assess coupling
- Always include coupling field
- Prefer loose coupling
- Document tight coupling as technical debt
-
Document design patterns
- Use
injectsfor DI - Use
observes/notifiesfor Observer pattern - Use
implementsfor Strategy/Interface patterns
- Use
-
Show dependency direction
- High-level → low-level (Controller → Service → Repository)
- Abstract → concrete (Interface ← Implementation)
- Stable → volatile
-
Highlight circular dependencies
- Flag as warning in observations
- Consider refactoring
- Document workaround if intentional
Graph Validity Rules
Referential Integrity
Rule: All relation targets must reference valid entity IDs
Validation:
# Pseudo-code
for relation in entity.relations:
if relation.target not in valid_entity_ids:
raise ValidationError(f"Invalid target: {relation.target}")
Examples:
✅ Valid:
{
"id": "rel-api-to-db",
"target": "postgres-db", // postgres-db exists in containers list
"type": "database-read-write"
}
❌ Invalid:
{
"id": "rel-api-to-db",
"target": "mysql-db", // mysql-db doesn't exist
"type": "database-read-write"
}
No Self-References
Rule: Source cannot equal target
✅ Valid:
{ "source": "api-service", "target": "database" }
❌ Invalid:
{ "source": "api-service", "target": "api-service" }
Cross-Level References
Rule: Relations can reference entities at same or different levels
C1 → C1: System to system ✅ C2 → C2: Container to container within same system ✅ C2 → C1: Container to external system ✅ C3 → C3: Component to component within same container ✅ C3 → C2: Component to external container ✅
Bidirectional Relations
Rule: If bidirectional, both entities should document the relation
Best Practice: Prefer two unidirectional relations over one bidirectional
✅ Preferred:
// In entity A
{ "target": "B", "type": "http-rest", "direction": "outbound" }
// In entity B
{ "target": "A", "type": "websocket", "direction": "inbound" }
❌ Less clear:
// In entity A
{ "target": "B", "type": "http-rest", "direction": "bidirectional" }
// No corresponding relation in B
Dangling References
Rule: All targets should eventually resolve to a documented entity
Exceptions:
- External systems not in your control
- Mark these clearly in description
- Use
external-apior similar type
Common Patterns
Frontend-Backend Pattern
C1 Level:
{
"source": "web-application",
"target": "backend-api",
"type": "http-rest",
"direction": "outbound",
"protocol": "HTTP/REST"
}
C2 Level:
{
"source": "react-spa",
"target": "express-api",
"type": "http-rest",
"protocol": "HTTP/REST",
"isAsync": true
}
API-Database Pattern
C2 Level:
{
"source": "express-api",
"target": "postgres-db",
"type": "database-read-write",
"protocol": "PostgreSQL Wire Protocol",
"isAsync": false
}
Event-Driven Pattern
C1 Level:
{
"source": "order-service",
"target": "message-queue",
"type": "message-queue",
"direction": "outbound",
"protocol": "AMQP",
"isAsync": true
}
C2 Level:
{
"source": "order-container",
"target": "rabbitmq",
"type": "message-publish",
"protocol": "AMQP"
},
{
"source": "notification-worker",
"target": "rabbitmq",
"type": "message-subscribe",
"protocol": "AMQP"
}
Layered Architecture Pattern (C3)
{
"source": "user-controller",
"target": "user-service",
"type": "uses",
"coupling": "loose"
},
{
"source": "user-service",
"target": "user-repository",
"type": "injects",
"coupling": "loose"
}
Observer Pattern (C3)
{
"source": "order-service",
"target": "order-events",
"type": "notifies",
"coupling": "loose"
},
{
"source": "payment-service",
"target": "order-events",
"type": "observes",
"coupling": "loose"
}
Validation Checklist
Before finalizing relations documentation:
- All relation IDs are unique
- All targets reference valid entity IDs
- No self-references (source ≠ target)
- Direction specified for C1 relations
- Coupling specified for C3 relations
- Protocol documented for network communication
- Descriptions in active voice
- Types match C4 level (C1 types at C1, etc.)
- isAsync set appropriately
- Tags use lowercase kebab-case
- Critical relations tagged appropriately
References
- Type Definitions: types.md
- Examples: examples.md
- Main Skill: SKILL.md
- Validation Scripts:
${CLAUDE_PLUGIN_ROOT}/validation/scripts/ - Schema Documentation:
/docs/observations-relations-schema.md
Version: 1.0.0 Last Updated: 2025-11-17