Skip to content

ADR-0003: One IR Document per Bounded Context

Status: Accepted

Date: March 2026

Context

Protean's Domain class is the composition root — it holds all registered elements, resolves references, assigns aggregate clusters, and wires handlers. A natural question arises: what is the scope of a single Internal Representation (IR) document? Does it represent a module, an aggregate, a bounded context, or an entire system?

In DDD, a bounded context is the boundary within which a particular domain model applies. Within a bounded context, terms have precise meanings and models are internally consistent. Across bounded contexts, the same term may mean different things (a "Customer" in billing vs. shipping).

Some developers, especially early in a project, may use a single Domain instance for what are logically separate bounded contexts. Others may split too early, creating artificial boundaries. The IR needs a clear scope that matches how Protean actually works.

Decision

We will produce one IR document per Domain instance, and one Domain instance represents one bounded context. The equation is: one Domain = one BC = one IR document.

Multiple aggregates within one Domain are clusters within a single bounded context — Order and Payment aggregates in the same domain are not separate BCs. This is normal DDD. The IR captures their relationships (shared events, cross-aggregate handlers) because they exist within the same consistency boundary.

Multi-bounded-context visualization (context maps, inter-BC event flows) requires aggregating multiple IR documents from separate Domain instances. Each IR captures one deployment domain. Cross-BC features are explicitly deferred to Phase 6 (context maps) and Phase 14 (multi-repo) of the IR roadmap.

Consequences

The IR is self-contained. Every FQN reference within the document resolves to an element within the same document. There are no dangling cross-document references to manage, no import mechanism, no dependency resolution between IR files.

Tooling that needs a system-wide view (architecture diagrams spanning multiple services, cross-BC event flow visualization) must aggregate multiple IR documents. This is a deliberate separation — each IR is a complete, valid unit. Aggregation is a tool concern, not a schema concern.

The known limitation is that the IR cannot represent sub-context boundaries within a single Domain. If a developer packs two logically distinct bounded contexts into one Domain instance, the IR treats them as one. Phase 5 linting may detect this pattern (aggregate clusters with no event flow between them) and emit an informational diagnostic, but the IR itself will not add sub-context declarations unless Protean introduces explicit bounded context partitioning within a Domain.

This also means that Protean does not support multi-BC abstractions at the framework level. The framework is deliberately opinionated: if you need separate bounded contexts, use separate Domain instances. This avoids premature sub-context abstraction and keeps the Domain class focused on a single responsibility.