Skip to content
bitzorcas
中EN

Concept

Modular Monolith: Physical Isolation, Contract Boundaries & ArchUnit

Explore the BitzOrcas.Modern modular monolith architecture: Contracts/Domain/Application project segregation, 5 inter-module collaboration rules, and ArchUnit architecture tests.

Last updated

The Modular Monolith is the foundation of BitzOrcas.Modern. It preserves the rapid in-process local debugging and single-deployable ergonomics of a monolith while enforcing microservice-grade physical project boundaries.

Physical Module Topology

BitzOrcas.Modules.LegalBitzOrcas.Modules.BillingReference Contracts OnlyNo Domain ReferenceNo Application Reference

Forbidden Dependencies (ArchUnit Blocked)

Allowed Dependency

Billing.Application (Vertical Slices)

Billing.Domain (Billing Aggregate)

Billing.Contracts (DTOs & Events)

Legal.Application (Matter Slices)

Legal.Domain (Matter Aggregate)

Legal.Contracts (Public Contracts)


Standard Module Structure

Every domain module is divided into 3 physical .csproj projects:

ProjectPhysical NamingPurposePermitted References
1. Public Contracts*.ContractsRead-only DTOs and IIntegrationEvent contractsReferenced by any external module
2. Domain Core*.DomainAggregate roots, entities, value objects, and domain eventsReferenced only by internal Application
3. Application Slices*.ApplicationVertical slices, commands, rules, and IAppModule rootReferenced only by Host composition roots

5 Rules for Inter-Module Collaboration

  1. Contract-Only References: Project references across modules are strictly restricted to *.Contracts projects;
  2. Queries via Read Ports: Modules query external data through public read ports, never by injecting foreign aggregate repositories;
  3. State Broadcasts via Integration Events: Domain mutations publish integration events via CAP Transactional Outbox;
  4. Transactional Outbox Consistency: Integration events commit within the same local database transaction as business state;
  5. In-Process Domain Events: Internal DomainEvent instances remain scoped to the originating transaction boundary.

ArchUnit Boundary Guards

tests/BitzOrcas.Architecture.Tests/ModuleBoundaryTests.cs
using ArchUnitNET.Domain;
using ArchUnitNET.Fluent;
using ArchUnitNET.Loader;
using ArchUnitNET.xUnit;
using Xunit;
using static ArchUnitNET.Fluent.ArchRuleDefinition;
namespace BitzOrcas.Architecture.Tests;
public sealed class ModuleBoundaryTests
{
// 1. Load module assemblies into ArchUnit reflection model
private static readonly Architecture Architecture =
new ArchLoader().LoadAssemblies(
typeof(Legal.LegalModule).Assembly,
typeof(Legal.Domain.MatterIntake).Assembly).Build();
[Fact]
public void ExternalModules_MustNotDependOn_InternalModuleImplementations()
{
// 2. Enforce boundary rule: Billing must not depend on Legal.Domain
IArchRule rule = Types().That()
.ResideInNamespace("BitzOrcas.Modules.Billing..")
.ShouldNot()
.DependOnAny(Types().That().ResideInNamespace("BitzOrcas.Modules.Legal.Domain.."));
rule.Check(Architecture);
}
}

Summary

BitzOrcas.Modern’s modular monolith combines clean boundaries with high agility, guarded by automated ArchUnit tests in CI.

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%