runtime-role-matrix-live-20.../docs/adr/ADR-001-spring-boundary-architecture.md
2026-07-14 11:24:30 +00:00

6.8 KiB

ADR-001: Spring 경계 아키텍처 정의

Context

runtime-role-matrix-live 프로젝트는 역할(Role) 기반 접근 제어 시스템을 구현한다. 현재 계층화 아키텍처의 명확한 경계가 정의되어 있지 않아 다음과 같은 문제가 발생한다.

  • 응집도 부족: Controller에서 비즈니스 로직 직접 수행
  • 결합도 증가: Service 간 직접 의존으로 단위 테스트 어려움
  • 트랜잭션 범위 모호: Repository 호출 시 트랜잭션 전파 정책 불명확
  • 오류 처리 불일치: 각 계층별 예외 처리 방식 상이

현재 시스템 범위

계층 책임
Controller HTTP 요청/응답 변환, 입력 검증, 라우팅
Service 비즈니스 로직, 트랜잭션 경계, 도메인 조율
Repository 데이터 접근 추상화, 쿼리 실행

Decision

1. Controller-Service-Repository 경계 정의

┌─────────────────────────────────────────────────────────────┐
│                      Controller Layer                        │
│  - HTTP 요청 파라미터 바인딩 및 검증 (@Valid)                 │
│  - HTTP 응답 변환 (DTO → ResponseEntity)                     │
│  - 예외 → HTTP 상태码 매핑                                   │
│  - 트랜잭션 경계에 참여하지 않음                               │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                       Service Layer                          │
│  - @Transactional 메서드 단위 트랜잭션 경계                    │
│  - 비즈니스 규칙 및 도메인 로직 실행                           │
│  - 다중 Repository 조율                                       │
│  - 도메인 객체 생성 및 상태 관리                               │
│  -Checked Exception → Unchecked Exception 변환               │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                     Repository Layer                         │
│  - JPA Repository (JpaRepository<T, ID>) 상속                │
│  - @Query 기반 커스텀 쿼리                                    │
│  - 도메인 엔티티 직접 반환                                     │
│  - 트랜잭션 읽기 전용 (readOnly=true) 활용                    │
└─────────────────────────────────────────────────────────────┘

2. 오류 계약 (Error Contract)

예외 계층 구조

RuntimeException (java.lang)
    │
    ├── RoleNotFoundException        → HTTP 404
    ├── RoleAlreadyExistsException   → HTTP 409
    ├── InvalidRoleStateException    → HTTP 400
    └── PermissionDeniedException    → HTTP 403

오류 응답 형식

{
  "timestamp": "2026-07-14T11:23:01Z",
  "status": 404,
  "error": "Not Found",
  "code": "ROLE_NOT_FOUND",
  "message": "Role with id '123' does not exist",
  "path": "/api/v1/roles/123"
}

전역 예외 처리 규칙

예외 유형 HTTP 상태 응답 코드
RoleNotFoundException 404 ROLE_NOT_FOUND
RoleAlreadyExistsException 409 ROLE_ALREADY_EXISTS
InvalidRoleStateException 400 INVALID_ROLE_STATE
PermissionDeniedException 403 PERMISSION_DENIED
MethodArgumentNotValidException 400 VALIDATION_ERROR
기타 RuntimeException 500 INTERNAL_ERROR

3. 트랜잭션 경계 정책

기본 원칙

작업 유형 전파 정책 readOnly
조회 (Read) REQUIRED true
생성 (Create) REQUIRED false
수정 (Update) REQUIRED false
삭제 (Delete) REQUIRED false

Service 클래스 설계

@Service
@Transactional(readOnly = true)
public class RoleService {

    @Transactional(readOnly = false)
    public Role createRole(CreateRoleRequest request) {
        // 비즈니스 로직
    }

    @Transactional(readOnly = false)
    public Role updateRole(Long id, UpdateRoleRequest request) {
        // 비즈니스 로직
    }

    public Role findById(Long id) {
        // readOnly=true 상속
    }
}

격리 수준

  • 기본값: READ_COMMITTED
  • 필요 시: @Transactional(isolation = Isolation.SERIALIZABLE)

Alternatives

대안 1: Transactional死在 Controller

@RestController
@Transactional
public class RoleController { ... }
항목 결함
문제점 HTTP 요청/응답 스레드와 트랜잭션 결합
결과 롤백 시 응답 불가 상태 발생 가능

대안 2: Service 계층 생략 (Transaction Script)

@RestController
public class RoleController {
    @Autowired RoleRepository repository;
    public Role create(...) { ... }
}
항목 결함
문제점 복잡한 도메인 로직 축적 시 재사용 어려움
결과 Controller 비대화, 테스트 어려움

대안 3: Checked Exception 직접 전파

항목 결함
문제점 호출자에게 예외 처리 강제, 결합도 증가
결과 Service 교체 시 Caller 코드 수정 필요

Consequences

긍정적 결과

  • 단위 테스트 용이성: Service를 순수 Java로 테스트 가능
  • 일관된 오류 처리: 전역 @ControllerAdvice로 중앙화
  • 트랜잭션 명확성: 메서드 단위 경계로 디버깅 용이
  • 유지보수성: 계층별 책임 분리

부정적 결과

  • 추가 코드 작성: DTO, Exception, Mapper 클래스 증가
  • 학습 곡선: 개발자별 아키텍처 이해 필요
  • 성능 오버헤드: Proxy 기반 AOP 약간의 지연 (미미)

모니터링 필요 항목

  • 트랜잭션 롤백 빈도
  • 예외 발생 패턴 (ROLE_NOT_FOUND 등)
  • Service 메서드 응답 시간

참고

  • Java: 17+
  • Spring Boot: 3.2.x
  • JPA: Hibernate 6.x
  • 빌드 도구: Maven