👉🏼 Click here to Join I ❤️ .NET WhatsApp Channel to get 🔔 notified about new articles and other updates.
Context Maps and Relationships in DDD - Visualizing Bounded Context Integrations in .NET

Context Maps and Relationships in DDD - Visualizing Bounded Context Integrations in .NET

Author - Abdul Rahman (Bhai)

DDD

22 Articles

Improve

Table of Contents

  1. What we gonna do?
  2. Why we gonna do?
  3. How we gonna do?
  4. Summary

What we gonna do?

You have defined your Bounded Contexts. Sales owns its model. Billing owns its model. Support owns its model. Now comes the next question that every team eventually asks: how do we document how these contexts relate to each other?

The answer is the Context Map — a diagram and shared understanding that shows all your Bounded Contexts, how they communicate, which integration pattern is in use, and who owns what. Think of it not as an architecture document that gathers dust, but as a team communication tool.

In this article you will learn what a Context Map is, the key relationship patterns (Customer-Supplier, Partnership, Anti-Corruption Layer), and how to apply them to a real licensing platform.

Why we gonna do?

Integration Without a Context Map

Teams often skip the Context Map because it feels like extra documentation overhead. The cost of skipping it only becomes clear when things break. Here is what the two worlds look like:


Without Context Map               | With Context Map
──────────────────────────────────────────────────────────────────────
Integration is implicit           | Integration is explicit
Dependencies are unclear          | All dependencies are documented
Power dynamics are hidden         | Relationships are clear and visible
Changes break unexpectedly        | Changes are planned
Coordination is ad-hoc            | Coordination is structured
──────────────────────────────────────────────────────────────────────

Three Groups of Relationships

Context Maps organise relationships into three broad categories. Understanding the category tells you how much coordination is needed and who has the power to break things:


Group        | Meaning
──────────────────────────────────────────────────────────────────────
Cooperative  | Teams work closely together and evolve models jointly
Directed     | One context depends on another — direction matters
Separate     | Contexts deliberately avoid tight coupling
──────────────────────────────────────────────────────────────────────

How we gonna do?

The Key Relationship Patterns

Within those three groups, DDD defines several named patterns. The three most common ones in practice are:


Pattern                  | Short description
──────────────────────────────────────────────────────────────────────────────────────
Customer-Supplier        | One context (supplier) provides, the other (customer) consumes.
                         | The consumer depends on the supplier, not the other way around.

Partnership              | Two contexts evolve together. Any change to the integration
                         | must be coordinated by both teams simultaneously.

Anti-Corruption Layer    | One context integrates with an external system via a translation
                         | layer that prevents external concepts from leaking into the domain.
──────────────────────────────────────────────────────────────────────────────────────

Building the Context Map for a Licensing Platform

Consider a licensing platform with four internal contexts and one external payment processor. Start by assigning each context to a team:


Context       | Team        | Role
────────────────────────────────────────────────────
Sales         | Team A      | Creates customers, raises events
Activation    | Team B      | Activates licenses
Support       | Team C      | Manages support tickets
Billing       | Team D      | Invoices and payments
Stripe        | External    | Third-party payment processor
────────────────────────────────────────────────────

Now map the relationships. The full integration diagram looks like this:


┌──────────────────────────────────────────────────────────────────┐
│  Context Map - Licensing Platform                                │
│                                                                  │
│                 ┌──────────┐                                     │
│       ┌────────▶│ Billing  │ (Customer-Supplier)                 │
│       │         └────┬─────┘                                     │
│       │              │ Anti-Corruption Layer                     │
│       │              ▼                                           │
│  ┌────┴─────┐    ┌──────────┐                                    │
│  │  Sales   │    │  Stripe  │ (External System)                  │
│  └────┬─────┘    └──────────┘                                    │
│       │                                                          │
│       │(Customer-Supplier)                                       │
│       │                                                          │
│  ┌────▼──────┐ Partnership ┌──────────┐                          │
│  │Activation │◀───────────▶│ Support  │                          │
│  └───────────┘             └──────────┘                          │
│       ▲                         ▲                                │
│       └────────────┬────────────┘                                │
│                    │ (both depend on Sales)                      │
└──────────────────────────────────────────────────────────────────┘

Expressing the Context Map in Code

A Context Map is not just a diagram. It drives actual code structure. The Customer-Supplier relationship means the supplier publishes an event contract that consumers implement against. Here is how that looks in C#:


// Sales context (the supplier) publishes a stable event contract
// File: SalesContext/Events/CustomerRegistered.cs
namespace SalesContext.Events;

/// <summary>
/// Published by Sales when a new customer is registered.
/// Consumed by Billing and Activation (Customer-Supplier).
/// </summary>
public sealed record CustomerRegistered(
    Guid CustomerId,
    string Segment,
    DateTimeOffset OccurredAt);

// Activation context (a customer) subscribes to Sales events
// File: ActivationContext/Handlers/ActivationCustomerHandler.cs
namespace ActivationContext.Handlers;

public sealed class ActivationCustomerHandler
{
    private readonly IActivationCustomerRepository _repo;

    public ActivationCustomerHandler(IActivationCustomerRepository repo)
        => _repo = repo;

    public async Task HandleAsync(
        SalesContext.Events.CustomerRegistered evt,
        CancellationToken ct = default)
    {
        var customer = ActivationCustomer.Create(
            new CustomerId(evt.CustomerId));

        await _repo.SaveAsync(customer, ct);
    }
}

The Partnership between Activation and Support requires a shared, versioned contract that both teams must agree on before either side can change it:


// Shared contract between Activation and Support (partnership)
// File: Shared/Contracts/LicenseActivatedEvent.cs
namespace Shared.Contracts;

/// <summary>
/// Raised by Activation, consumed by Support.
/// Both teams must agree on and version this contract — it is a partnership.
/// </summary>
public sealed record LicenseActivated(
    Guid LicenseId,
    Guid CustomerId,
    string HardwareFingerprint,
    DateTimeOffset ActivatedAt);

// Support context reacts to license activations
// File: SupportContext/Handlers/LinkActivationToTicketHandler.cs
namespace SupportContext.Handlers;

public sealed class LinkActivationToTicketHandler
{
    private readonly IOpenTicketRepository _tickets;

    public LinkActivationToTicketHandler(IOpenTicketRepository tickets)
        => _tickets = tickets;

    public async Task HandleAsync(
        Shared.Contracts.LicenseActivated evt,
        CancellationToken ct = default)
    {
        // If a ticket exists for this customer's activation issue, auto-resolve it
        var openTickets = await _tickets.FindByCustomerAsync(
            new CustomerId(evt.CustomerId), ct);

        foreach (var ticket in openTickets.Where(t => t.IsActivationIssue()))
            ticket.AutoResolve($"License activated on {evt.HardwareFingerprint}");

        await _tickets.SaveAllAsync(openTickets, ct);
    }
}

Summarising the Relationship Table

A concise relationship table keeps the Context Map consumable at a glance. Keep one of these in your team wiki and update it whenever a new integration is added:


Source      | Target      | Relationship            | Ownership Note
────────────────────────────────────────────────────────────────────────────────
Sales       | Billing     | Customer-Supplier       | Billing depends on Sales events
Sales       | Activation  | Customer-Supplier       | Activation depends on Sales events
Sales       | Support     | Customer-Supplier       | Support depends on Sales events
Activation  | Support     | Partnership             | Must coordinate changes together
Billing     | Stripe      | Anti-Corruption Layer   | Billing protects domain from Stripe
────────────────────────────────────────────────────────────────────────────────

Reading this table tells you immediately who to call when something breaks, who approves schema changes to an event, and where careful coordination is required.

Summary

In this article, you learned how to document and implement Bounded Context relationships using a Context Map:

  • A Context Map is a team communication tool that shows all contexts, integrations, and ownership.
  • Customer-Supplier: the consumer depends on the supplier's stable event contract.
  • Partnership: both sides must coordinate changes — useful when contexts co-evolve tightly.
  • Anti-Corruption Layer: isolates your domain from an external system's model.
  • The relationship table is the most actionable artefact — it immediately answers who to contact when things break.
  • Relationships drive code structure: event contracts, handler namespaces, and versioning strategies all follow from the map.

The Anti-Corruption Layer deserves a full treatment of its own because it is one of the most powerful protective patterns in DDD. That is the topic of the next article.

👉🏼 Click here to Join I ❤️ .NET WhatsApp Channel to get 🔔 notified about new articles and other updates.
  • DDD
  • Domain-Driven Design
  • DDD
  • Context Maps
  • Bounded Contexts
  • Customer-Supplier
  • Partnership
  • Anti-Corruption Layer
  • Strategic Design
  • .NET
  • C#