# How to Integrate DDDplus Architecture Enforcement Rules into a CI Pipeline

> Easily integrate DDDplus architecture enforcement rules into your CI pipeline. Learn how to use dddplus maven plugin and ArchUnit to validate DDD constraints automatically on every build.

- Repository: [Funky Gao/cp-ddd-framework](https://github.com/funkygao/cp-ddd-framework)
- Tags: how-to-guide
- Published: 2026-03-02

---

**Integrating DDDplus architecture enforcement rules into a CI pipeline requires configuring the `dddplus-maven-plugin` to execute ArchUnit-based checks during the Maven `verify` phase, ensuring that domain-driven design constraints are validated on every build.**

The **DDDplus** framework (available at `funkygao/cp-ddd-framework`) provides a comprehensive enforcement layer built on ArchUnit that guards against architectural drift in domain-driven design projects. By integrating these rules into your continuous integration pipeline, you automatically prevent violations—such as incorrect layer dependencies or improper service naming—from reaching production code.

## Understanding the DDDplus ArchUnit Enforcement Components

The enforcement system consists of three coordinated components that work together to validate your architecture:

- **EnforcerMojo**: The Maven plugin entry point that bridges the build lifecycle with the enforcement engine.
- **DDDPlusEnforcer**: The core orchestrator that scans compiled classes and executes rule collections.
- **ArchitectureEnforcer**: A static repository of predefined ArchUnit rules covering DDDplus-specific conventions.

## Step-by-Step: Integrating DDDplus Architecture Enforcement into Your CI Pipeline

### Step 1: Configure the Maven Enforcer Plugin

Add the `dddplus-maven-plugin` to your root [`pom.xml`](https://github.com/funkygao/cp-ddd-framework/blob/main/pom.xml) and bind it to the `verify` phase. This ensures the check runs after compilation but before packaging.

```xml
<build>
  <plugins>
    <plugin>
      <groupId>io.github.dddplus</groupId>
      <artifactId>dddplus-maven-plugin</artifactId>
      <version>2.1.0</version>
      <executions>
        <execution>
          <id>archunit-enforce</id>
          <phase>verify</phase>
          <goals>
            <goal>enforce</goal>
          </goals>
          <configuration>
            <rootPackage>com.mycompany.myapp</rootPackage>
            <rootDir>target/classes:target/test-classes</rootDir>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

```

The `EnforcerMojo` (located at [`dddplus-maven-plugin/src/main/java/io/github/dddplus/maven/EnforcerMojo.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-maven-plugin/src/main/java/io/github/dddplus/maven/EnforcerMojo.java)) reads these parameters and instantiates the enforcement engine.

### Step 2: Execute the Enforcer in CI

In your CI configuration, invoke the Maven `verify` phase. The plugin automatically triggers during this phase.

```bash
mvn clean verify -DrootPackage=com.mycompany.myapp -DrootDir=target/classes:target/test-classes

```

Alternatively, run the goal directly:

```bash
mvn io.github.dddplus:dddplus-maven-plugin:enforce \
  -DrootPackage=com.mycompany.myapp \
  -DrootDir=target/classes:target/test-classes

```

The `DDDPlusEnforcer` (defined in [`dddplus-enforce/src/main/java/io/github/dddplus/DDDPlusEnforcer.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-enforce/src/main/java/io/github/dddplus/DDDPlusEnforcer.java)) uses ArchUnit's `ClassFileImporter` to scan the specified packages, excluding test sources via `ImportOption.Predefined.DO_NOT_INCLUDE_TESTS`.

### Step 3: Configure Build Failure on Violations

The enforcement mechanism relies on ArchUnit's `AssertionError` throwing capability. When `DDDPlusEnforcer.enforce()` detects a violation, it propagates the error, causing Maven to exit with a non-zero status.

CI systems interpret this exit code as a failure, blocking the merge or deployment. The detailed violation report appears in the build logs, specifying which rule was broken (e.g., `serviceRule()`, `routerRule()`, or `optionalInterfaceNameStartsWithI()` from [`ArchitectureEnforcer.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/ArchitectureEnforcer.java)) and the offending class.

## Alternative: Direct JUnit Integration for CI

If you prefer test-based enforcement over Maven plugin configuration, instantiate the enforcer directly in a JUnit test. This approach works with any CI system that runs `mvn test`.

```java
import io.github.dddplus.DDDPlusEnforcer;
import org.junit.Test;

public class ArchitectureComplianceTest {

    @Test
    public void enforceArchitecture() {
        new DDDPlusEnforcer()
                .scanPackages("com.mycompany.myapp")
                .enforce();
    }
}

```

Place this in `src/test/java`. The `enforce()` method throws `AssertionError` on violation, failing the test and consequently the CI build.

For extended rule sets, use `ArchitectureEnforcer.requiredRules`:

```java
import io.github.dddplus.ArchitectureEnforcer;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import org.junit.Test;

public class DDDplusArchitectureTest {

    @Test
    public void requiredArchitectureRules() {
        ArchitectureEnforcer.requiredRules.forEach(rule -> 
            rule.check(new ClassFileImporter().importPackages("com.mycompany.myapp")));
    }
}

```

## Key Source Files and Rule Definitions

| File | Purpose | Location |
|------|---------|----------|
| [`EnforcerMojo.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/EnforcerMojo.java) | Maven plugin Mojo that parses `rootPackage` and `rootDir`, then invokes the enforcer. | [`dddplus-maven-plugin/src/main/java/io/github/dddplus/maven/EnforcerMojo.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-maven-plugin/src/main/java/io/github/dddplus/maven/EnforcerMojo.java) |
| [`DDDPlusEnforcer.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/DDDPlusEnforcer.java) | Core API that scans packages via ArchUnit's `ClassFileImporter` and executes the rule collection. | [`dddplus-enforce/src/main/java/io/github/dddplus/DDDPlusEnforcer.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-enforce/src/main/java/io/github/dddplus/DDDPlusEnforcer.java) |
| [`ArchitectureEnforcer.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/ArchitectureEnforcer.java) | Static repository of ArchUnit rules including `serviceRule()`, `routerRule()`, and naming conventions. | [`dddplus-enforce/src/main/java/io/github/dddplus/ArchitectureEnforcer.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-enforce/src/main/java/io/github/dddplus/ArchitectureEnforcer.java) |
| [`DDDPlusEnforcerTest.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/DDDPlusEnforcerTest.java) | Reference implementation showing JUnit integration for CI environments. | [`dddplus-test/src/test/java/io/github/dddplus/DDDPlusEnforcerTest.java`](https://github.com/funkygao/cp-ddd-framework/blob/main/dddplus-test/src/test/java/io/github/dddplus/DDDPlusEnforcerTest.java) |

## Summary

- **Integrating DDDplus architecture enforcement rules into a CI pipeline** involves configuring the `dddplus-maven-plugin` to validate ArchUnit rules during the Maven `verify` phase.
- The `EnforcerMojo` bridges Maven with the `DDDPlusEnforcer`, which scans compiled classes using ArchUnit's `ClassFileImporter`.
- Violations trigger `AssertionError`, causing non-zero Maven exit codes that fail CI builds and prevent non-compliant code from merging.
- Alternative integration via direct JUnit tests allows `mvn test` to serve as the enforcement trigger, utilizing `ArchitectureEnforcer.requiredRules` for comprehensive rule coverage.

## Frequently Asked Questions

### What is the difference between DDDPlusEnforcer and ArchitectureEnforcer?

**DDDPlusEnforcer** serves as the primary orchestration API that handles package scanning and rule execution. It maintains an internal collection of ArchUnit rules specific to DDDplus core concepts like `IIdentityResolver` and `Router`. **ArchitectureEnforcer**, conversely, is a static utility class that exposes a broader set of architectural constraints—including `serviceRule()`, `routerRule()`, and naming conventions like `optionalInterfaceNameStartsWithI()`—via the `requiredRules` list. While `DDDPlusEnforcer` is designed for direct API usage, `ArchitectureEnforcer` provides reusable rules for custom test implementations.

### How do I configure the rootPackage and rootDir parameters?

The `rootPackage` parameter specifies the base Java package of your application code (e.g., `com.mycompany.myapp`), which `DDDPlusEnforcer.scanPackages()` uses to limit ArchUnit's class import scope. The `rootDir` parameter defines the colon-separated list of compiled class directories (e.g., `target/classes:target/test-classes`) that the `ClassFileImporter` scans. In the Maven plugin configuration, these map to the `<rootPackage>` and `<rootDir>` XML elements within the `EnforcerMojo` execution block.

### Can I run DDDplus architecture checks without Maven?

Yes, you can execute DDDplus architecture enforcement independently of Maven by using the JUnit integration approach. Instantiate `DDDPlusEnforcer` directly in a test class, call `scanPackages()` with your base package, and invoke `enforce()`. Alternatively, iterate over `ArchitectureEnforcer.requiredRules` and apply them to classes imported via ArchUnit's `ClassFileImporter`. This method works with Gradle, Bazel, or standalone JUnit runners, provided the `dddplus-enforce` dependency is on the classpath.

### What happens when an ArchUnit rule violation is detected in CI?

When the `DDDPlusEnforcer.enforce()` method detects a violation, ArchUnit throws an `AssertionError` containing a detailed description of which rule was violated (such as `serviceRule()` or `routerRule()`) and the specific class or dependency that caused the breach. This error propagates to the Maven process, causing it to exit with a non-zero status code. Consequently, the CI pipeline interprets this as a build failure, halting the workflow and preventing the merge or deployment of the non-compliant code. The detailed violation report appears in the CI logs, allowing developers to identify and fix the architectural drift.