NestJS DDD

도메인 경계는 폴더 이름이 아니라 규칙이 새는 지점으로 나눈다

bounded context는 module 이름을 예쁘게 나누는 일이 아니다. aggregate가 지키는 불변식, use case가 여는 명령, repository contract가 숨기는 저장소 세부사항을 기준으로 NestJS 경계를 잡는다.

경계 지도

controller to domain
NestJS module, use case, aggregate, repository adapter 경계 Controller DTO가 use case command로 변환되고, aggregate가 불변식을 검사한 뒤 domain event를 남긴다. Repository contract는 domain 안에 있고 adapter와 ORM entity는 infrastructure 쪽에 있다. Interface layer Controller DTO / auth Mapper DTO -> command Application layer Use case transaction boundary Port repository contract Domain layer Aggregate invariant 검사 Domain event 정책 변경 흔적 Infrastructure Adapter ORM / API Entity persistence shape DTO, ORM entity, HTTP error는 domain 안으로 들어오지 않는다 aggregate 불변식과 event가 경계의 증거가 된다
interface Controller DTO

인증, 입력 검증, HTTP 모양을 다루고 command로 변환한다.

application Use case + repository port

트랜잭션 경계와 호출 순서를 정하고 domain contract에만 의존한다.

domain Aggregate invariant

주문 취소 가능 여부처럼 비즈니스 규칙을 직접 판정한다.

infra Adapter + ORM entity

저장소, 외부 API, ORM 모양은 contract 뒤에 숨긴다.

NestJS 계층 책임

module boundary
controller
프로토콜과 인증 컨텍스트를 command로 변환 HTTP status, guard, DTO shape는 여기서 끝낸다.
orders.controller
use case
트랜잭션과 호출 순서를 조율 도메인 규칙을 대신 판단하지 않고 aggregate에 묻는다.
cancel-order.usecase
aggregate
상태 전이와 불변식을 직접 보호 배송 시작 후 취소 불가 같은 규칙이 aggregate에 남는다.
Order.cancel()
adapter
contract를 DB/API 세부 구현으로 연결 Prisma, TypeORM, 외부 결제 API 의존은 여기서 격리한다.
order.repo.prisma

경계 계약

contract test
ubiquitous language module, command, event 이름이 사용자 업무 언어와 맞아야 한다.
repository contract domain은 저장 방식이 아니라 필요한 조회/저장 행위만 안다.
domain event 정책 변경 영향이 다른 context로 넘어갈 때 기록과 테스트가 남는다.
anti-corruption 외부 API 응답과 ORM entity를 domain model로 직접 쓰지 않는다.
anemic model 규칙이 service if문에 흩어짐 aggregate method 없이 use case가 상태 전이를 직접 조립한다.
language drift 같은 용어가 context마다 다른 뜻 주문/결제/정산의 “취소”가 서로 다른 상태 전이를 가진다.
infra leak Prisma model이 domain을 결정 DB 컬럼 변화가 도메인 규칙 테스트를 깨뜨리는 구조가 된다.
event fog 이벤트가 로그인지 정책인지 불명확 다른 bounded context가 무엇을 믿고 반응해야 하는지 흐려진다.
검증 질문

DDD 적용 여부는 폴더명보다 규칙, 언어, 의존 방향이 증명한다.

  • controller나 ORM entity를 보지 않고 aggregate 규칙을 테스트할 수 있는가?
  • repository contract 누락 시 domain 테스트가 아니라 adapter 테스트만 깨지는가?
  • domain event 이름만 봐도 어떤 정책 변화가 일어났는지 설명되는가?