ADR-0009: Anti-Corruption Layer per module for bounded context isolation
Status
AcceptedTags
architecture, ddd, bounded-context, acl, microservice, modulesDecision
Each module defines its own local domain model for any external entity it needs (e.g.,leave/domain/user.go — not imported from the user module). An Anti-Corruption Layer adapter in the outbound persistence layer converts the external/shared model into the module’s local representation. The module’s port interface is the only contract; the implementation can be swapped between PostgreSQL and HTTP without touching business logic.
Why
Direct imports of another module’s domain package create tight coupling: schema changes in the user module break the leave module, circular imports become possible, and independent deployment is blocked. Giving each module its own bounded view of external entities means:- The leave module defines what “User” means for leave purposes (ID, Name, ManagerID, DepartmentID) — independent of the user module’s full model
- The ACL adapter handles translation; the module never sees the external schema
- Swapping from a shared PostgreSQL query to a remote HTTP call requires only a new adapter implementation — zero business logic changes
Structure
Rules for agents
- Each module must have its own domain representation of any external entity it needs — do not import from another module’s
domain/package - The ACL conversion function (
convertToLeaveUser, etc.) lives in the outbound adapter, not in the domain layer - Module wiring (
NewModule) selects the adapter based on config (MicroserviceMode); business logic does not branch on this - The port interface must be defined in the module’s own
application/port/— not in shared packages - Adding a new module that needs user data: create
{module}/domain/user.go+{module}/application/port/interface + PostgreSQL adapter; do not reuse leave’s domain model