runtime-role-matrix-live-20.../docs/adr/ADR-001-spring-architecture-boundaries.md

5.8 KiB

ADR-001: Spring MVC 경계, 오류 계약 및 트랜잭션 경계

상태

수용됨 — 2026-07-14

컨텍스트

본 프로젝트는 역할 기반 접근 제어(RBAC) 매트릭스를 런타임에 관리하는 Spring Boot 애플리케이션이다. 복잡한 도메인 로직과 다중 데이터 소스를 다루며, 명확한 계층 경계와 일관된 오류 처리가 필수적이다.

현재 문제점

  • Controller에서 직접 Repository 호출 → 테스트 불가능한 구조
  • 예외 처리가 각 계층에 산재 → 일관된 API 응답 불가
  • 트랜잭션 경계가 불명확 → 데이터 불일치 위험

결정

1. Controller-Service-Repository 경계

┌─────────────────────────────────────────────────────────────┐
│                      Controller Layer                        │
│  • HTTP 요청/응답 변환                                        │
│  • 입력 검증 (Bean Validation)                                │
│  • HTTP 상태 코드 결정                                        │
│  • DTO 변환 (Request → Command, Response ← Result)           │
│  ❌ 비즈니스 로직 금지                                         │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                       Service Layer                          │
│  • 비즈니스 로직 수행                                          │
│  • 도메인 객체 조작                                            │
│  • @Transactional 경계 관리                                   │
│  • 도메인 예외 발생 (DomainException)                          │
│  ❌ HTTP/프레젠테션 concerns 금지                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                     Repository Layer                         │
│  • 데이터 접근 추상화 (JPA Repository)                         │
│  • 엔티티 ↔ 도메인 객체 변환                                   │
│  • 쿼리 메서드 정의                                           │
│  ❌ 비즈니스 로직 금지                                         │
└─────────────────────────────────────────────────────────────┘

경계 규칙:

  • Controller → Service: Command/DTO 전달, Result/DTO 수신
  • Service → Repository: 도메인 객체 또는 ID 전달, 도메인 객체 수신
  • 하위 계층이 상위 계층을 직접 참조 금지 (의존성 역전)

2. 오류 계약 (Error Contract)

2.1 표준 오류 응답 형식

{
  "timestamp": "2026-07-14T15:22:00Z",
  "status": 400,
  "error": "Bad Request",
  "code": "ROLE_MATRIX_001",
  "message": "역할 매트릭스 이름은 필수입니다",
  "path": "/api/v1/role-matrices",
  "traceId": "abc123"
}

2.2 예외 계층 구조

Throwable
└── RuntimeException
    └── GlobalException (공통 기반 예외)
        ├── DomainException (도메인业务 예외)
        │   ├── RoleMatrixNotFoundException
        │   ├── RoleNotFoundException
        │   └── DuplicateRoleMatrixException
        ├── ValidationException (검증 예외)
        └── InfrastructureException (인프라 예외)
            ├── DataAccessException
            └── ExternalServiceException

2.3 예외-상태코드 매핑

예외 클래스 HTTP 상태 오류 코드 접두사
ValidationException 400 VAL_
DomainException 400/409 DOM_
RoleMatrixNotFoundException 404 NOT_FOUND_
DuplicateRoleMatrixException 409 CONFLICT_
InfrastructureException 500/503 SYS_

3. 트랜잭션 경계

작업 유형 트랜잭션 전파 격리 수준 읽기 전용
조회 (SELECT) REQUIRED READ_COMMITTED true
단일 생성/수정/삭제 REQUIRED READ_COMMITTED false
다중 변경 (배치) REQUIRED_NEW READ_COMMITTED false

롤백 규칙:

  • RuntimeException → 자동 롤백
  • Checked Exception → 명시적 rollbackFor 필요
  • DomainException (RuntimeException 하위) → 자동 롤백

대안들

대안 1: 트랜잭션 스크립트 패턴

  • 모든 로직을 Controller에서 처리
  • 단점: 테스트 불가능, 결합도 높음
  • 기각 이유: 본 프로젝트 복잡도에서 유지보수 불가

결과

긍정적 결과

  • 테스트 용이성: Mock 기반 단위 테스트 가능
  • 일관된 오류 처리: 모든 API에서 동일한 오류 응답 형식
  • 트랜잭션 명확성: 어디서 롤백/커밋되는지 예측 가능

부정적 결과

  • 추가 코드: DTO, Mapper, Exception 클래스 증가
  • 학습 곡선: 개발자 교육 필요