Files
gh-cubical6-melly/skills/c4model-relations/reference.md
2025-11-29 18:17:07 +08:00

9.4 KiB

C4 Model Relations - Detailed Reference

Table of Contents

  1. Protocol Documentation Guidelines
  2. Direction vs Coupling
  3. Best Practices per Level
  4. Graph Validity Rules
  5. 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/REST
  • HTTP/2 gRPC
  • PostgreSQL Wire Protocol
  • AMQP
  • OAuth 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

  1. Focus on protocols

    • Always specify communication protocol
    • Include authentication method for external relations
    • Document sync vs async nature
  2. Specify direction

    • Use outbound for active calls (API requests, queries)
    • Use inbound for passive receives (webhooks, callbacks)
    • Avoid bidirectional unless truly necessary
  3. Document external integrations

    • Mark external services clearly
    • Include vendor name (Stripe, SendGrid, etc.)
    • Note criticality for business operations
  4. Group similar relations

    • One relation for "Frontend → API" covering all endpoints
    • Don't create separate relations for each API endpoint

C2 Container Best Practices

  1. Be specific about API style

    • Use http-rest not just http
    • Use http-graphql for GraphQL
    • Distinguish between REST and RPC
  2. Differentiate read vs write

    • Use database-query for read-only
    • Use database-write for write-only
    • Use database-read-write for both
  3. Document cache patterns

    • Specify cache operations (read, write, both)
    • Include eviction strategy if relevant
    • Note cache hit/miss criticality
  4. Show message patterns

    • Use message-publish for producers
    • Use message-subscribe for consumers
    • Document topic/queue names in description

C3 Component Best Practices

  1. Assess coupling

    • Always include coupling field
    • Prefer loose coupling
    • Document tight coupling as technical debt
  2. Document design patterns

    • Use injects for DI
    • Use observes/notifies for Observer pattern
    • Use implements for Strategy/Interface patterns
  3. Show dependency direction

    • High-level → low-level (Controller → Service → Repository)
    • Abstract → concrete (Interface ← Implementation)
    • Stable → volatile
  4. 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-api or 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