3.7 KiB
3.7 KiB
ADR-003: AGENTS 기준 레이어 경계 리팩토링
Status
Accepted
Date
2026-04-14
Context
AGENTS.md와 standards/examples는 레이어별 소유 책임을 명확히 나누지만, 일부 구현은 편의상 경계 관심사를 직접 들고 있었다.
presentation응답 모델이 MDC와 현재 시각을 직접 읽었다.- OAuth2 callback controller와 mapper가 Spring Security 타입과 provider registration 해석을 직접 다뤘다.
- repository adapter가 transaction boundary를 소유했다.
- Vault Transit client가 ad-hoc JSON/URL/header 조립을 핵심 로직 안에 섞고 있었다.
이 결정은 기능을 바꾸기보다, 같은 인증 플로우를 유지하면서 경계 위반 가능성을 줄이기 위한 것이다.
Decision Drivers
- 응답 DTO/model은 순수 transport 계약이어야 한다.
- 현재 사용자와 provider registration 해석은 web/security boundary에서 끝나야 한다.
- transaction은 application use case 작업 단위에서 소유해야 한다.
- infrastructure adapter는 기술 번역을 담당하되 business workflow를 소유하지 않아야 한다.
- 같은 위반이 재발하지 않도록 ArchUnit 테스트로 구조를 검증해야 한다.
Considered Options
Option 1: 기존 구조 유지 후 국소 수정
- 장점: 수정 파일 수가 적다.
- 단점:
ApiResult, controller, mapper, repository adapter에 섞인 책임이 남아 같은 문제가 반복된다. - 트레이드오프: 단기 변경은 작지만 standards/examples와 계속 어긋난다.
Option 2: 경계별 소유자를 다시 지정
- 장점:
presentation은 HTTP 계약,bootstrap은 request/security context,application은 transaction,infrastructure는 기술 번역에 집중한다. - 단점: 조립 코드와 테스트 fixture 수정이 필요하다.
- 트레이드오프: 초기 변경량은 늘지만 이후 기능 추가 시 경계 판단 비용이 줄어든다.
Decision
Option 2를 선택해 request metadata, OAuth2 provider mapping, transaction boundary, external integration DTO/translation의 소유 위치를 각 레이어 기준에 맞게 재배치한다.
Consequences
긍정적 결과
ApiResult는 MDC나 clock을 모르는 순수 envelope가 되었다.- OAuth2 controller는 Spring Security
Authentication대신 presentation 전용 principal을 받는다. - provider registration ID와 redirect path는 bootstrap security configuration에서 조립한다.
- repository adapter의 transaction annotation을 제거하고 application collaborator가 transaction boundary를 가진다.
- Vault Transit client는 typed request/response와 명시적 infrastructure exception translation을 사용한다.
- ArchUnit이 presentation의 SecurityContext 직접 접근, ApiResult의 시간/MDC 의존, infrastructure transaction 소유를 막는다.
부정적 결과
- controller/advice 생성자에
ApiResultFactory의존성이 추가된다. - use case 내부 collaborator가 늘어나면서 bootstrap bean wiring이 길어졌다.
- OAuth2 callback 테스트는 Spring Security token 대신 전용 principal fixture를 사용한다.
위험 완화
- 외부 API 응답 shape와 endpoint path는 유지한다.
./gradlew test로 application, presentation, infrastructure, bootstrap 테스트를 모두 통과시킨다.- DB provider별 필수 필드는 Flyway constraint로 한 번 더 보호한다.
후속 정리
본 ADR 시점에 정리된 Vault Transit client 는 이후 ADR-002 Keycloak 전환 에서 자체 JWT 발급 책임이 사라지면서 통째로 제거됨. 자세한 제거 범위는 04-adr-token-ownership-cleanup.md.