Skip to content

refactor: 기반 코드가 사용자 도메인을 알던 자리를 끊는다 - #147

Merged
RosieOh merged 1 commit into
mainfrom
refactor/core-off-domain
Oct 23, 2026
Merged

RosieOh merged 1 commit into
mainfrom
refactor/core-off-domain

Conversation

@RosieOh

@RosieOh RosieOh commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Refs #132 (8단계)

"core 기반 패키지는 domain 을 의존하지 않는다" 위반 50건은 전부 인증·인가 기반 코드였습니다. 다섯 덩어리였고, 각각 원인이 달랐습니다.

어디 무엇을 알고 있었나 어떻게 끊었나
CurrentUserFacade (15) User, UserRepository 이 클래스가 곧 사용자 도메인의 입구다 → domain/user/app
KakaoUtil (11) KakaoOAuthToken, KakaoProfile … 카카오 응답 형식이 우리 API 응답 패키지에 있었다 → 클라이언트와 DTO 6개를 external/kakao 로
전역 예외 핸들러 (10) ConsentGuard ConsentRequiredException 이 서비스 안의 중첩 클래스여서, 예외를 가리키려면 서비스를 import 해야 했다
CustomUserDetailsService (8) User, UserRepository domain/user/security 로 옮기고 SecurityConfig 는 스프링의 UserDetailsService 인터페이스로 받는다
JwtAuthenticationFilter (6) JwtService 필터는 토큰 검증만 필요한데 그 서비스는 로그인 응답 DTO 까지 다룬다 → AccessTokenVerifier 포트

옮기는 방향이 중요했습니다

셋은 core → 도메인으로 옮겼고, 둘은 반대로 핸들러·필터가 도메인을 보지 않도록 경계를 세웠습니다.

기준은 "누가 그 규칙의 주인인가" 였습니다. 자격 증명으로 사용자를 찾는 일과 현재 사용자를 꺼내는 일은 사용자 도메인의 규칙입니다. 반대로 토큰 서명 검증과 예외 → HTTP 상태 변환은 기반 코드의 일이고, 그쪽이 도메인 타입을 알 필요가 없습니다.

카카오 DTO 가 잘못된 자리에 있던 것이 실제 문제였습니다

KakaoProfile·KakaoAccount·KakaoProperties·KakaoProfileInfo·KakaoOAuthToken 은 카카오가 주는 JSON 모양입니다 — 필드명이 connected_at, thumbnail_image_url 처럼 snake_case 인 것이 그 증거입니다. 그것이 domain/user/dto/response(우리가 프런트에 주는 응답을 모아 둔 패키지)에 섞여 있었습니다. 카카오가 응답을 바꾸면 우리 API 응답 패키지가 바뀌는 셈입니다.

규칙도 한 줄 고쳤습니다

CurrentUserFacade 가 도메인으로 들어오자 "도메인은 SecurityContextHolder 를 직접 쓰지 않는다" 에 걸렸습니다 — 그 클래스의 존재 이유가 바로 그 접근을 혼자 하는 것인데도요. 규칙의 because 가 이미 "현재 사용자는 CurrentUserFacade 로만 얻는다" 라고 적고 있으므로 파사드 자신만 예외로 두었습니다. 남은 1건(CommunityService 가 직접 꺼내는 곳)은 계속 추적합니다.

규칙 문구를 고치면 ArchUnit 이 새 키로 baseline 을 만들고 옛 파일은 고아로 남습니다. 자동으로 지워지지 않아 손으로 정리했습니다(stored.rules 의 줄 + 해당 파일).

숫자

  • core 기반 → 도메인 참조 50 → 0
  • ArchUnit baseline 291 → 241 (고아 baseline 1개 정리 포함)
  • 남은 241건 중 237건이 도메인 경계 한 규칙입니다

검증 범위 — 읽어 주세요

compileJava·compileTestJava 통과, ArchitectureRulesTest 통과. 전체 스위트는 로컬에서 끝까지 돌리지 못했습니다 — 다른 세션이 같은 저장소에서 테스트를 돌리고 있어 build/test-results 가 잠겨 있었습니다. CI 가 깨끗한 체크아웃에서 돌리므로 그 결과로 확인해 주세요.

같은 이유로 이 브랜치에는 그 세션의 작업 파일 3개(CareFacilityRepository, AdmissionCandidateService, PolicyInitializationService)를 의도적으로 담지 않았습니다.

"core 기반 패키지는 domain 을 의존하지 않는다" 위반 50건은 전부 인증·인가 기반
코드였다. 다섯 덩어리였고 각각 원인이 달랐다.

- CurrentUserFacade (15): 이 클래스가 곧 사용자 도메인의 입구다 → domain/user/app
- KakaoUtil (11): 카카오 응답 형식(KakaoProfile·KakaoAccount·KakaoProperties·
  KakaoProfileInfo·KakaoOAuthToken)이 우리 API 응답 패키지에 있었다 → external/kakao
- 전역 예외 핸들러 (10): ConsentRequiredException 이 ConsentGuard 안의 중첩 클래스여서
  예외를 가리키려면 서비스를 import 해야 했다 → core/exception 으로 꺼내고 동의 종류를
  문자열로 담는다(열거형이면 핸들러가 다시 도메인을 알아야 한다)
- CustomUserDetailsService (8): → domain/user/security, SecurityConfig 는 스프링의
  UserDetailsService 인터페이스로 받는다
- JwtAuthenticationFilter (6): 필터는 토큰 검증만 필요한데 JwtService 는 로그인 응답
  DTO 까지 다룬다 → AccessTokenVerifier 포트로 필요한 만큼만 끊었다

옮기는 방향이 중요했다. 셋은 core 에서 도메인으로 옮겼고(자격 증명으로 사용자를 찾는
일과 현재 사용자를 꺼내는 일은 사용자 도메인의 규칙이다), 둘은 반대로 핸들러·필터가
도메인을 보지 않도록 경계를 세웠다(토큰 서명 검증과 예외→HTTP 변환은 기반 코드의 일이고
도메인 타입을 알 필요가 없다).

카카오 DTO 가 잘못된 자리에 있던 것이 실제 문제였다. 필드명이 connected_at,
thumbnail_image_url 처럼 snake_case 인 것이 카카오의 와이어 포맷이라는 증거인데,
그것이 우리가 프런트에 주는 응답을 모아 둔 domain/user/dto/response 에 섞여 있었다.

규칙도 한 줄 고쳤다. CurrentUserFacade 가 도메인으로 들어오자 "도메인은
SecurityContextHolder 를 직접 쓰지 않는다" 에 걸렸다 — 그 클래스의 존재 이유가 바로 그
접근을 혼자 하는 것인데도. 규칙의 because 가 이미 "현재 사용자는 CurrentUserFacade 로만
얻는다" 라고 적고 있으므로 파사드 자신만 예외로 뒀다. 남은 1건(CommunityService)은 계속
추적한다. 규칙 문구를 고치면 ArchUnit 이 새 키로 baseline 을 만들고 옛 파일이 고아로
남는데 자동으로 지워지지 않아 손으로 정리했다.

- core 기반 → 도메인 참조 50 → 0
- ArchUnit baseline 291 → 241 (고아 baseline 1개 정리 포함)
- 남은 241건 중 237건이 도메인 경계 한 규칙이다

검증: compileJava·compileTestJava 통과, ArchitectureRulesTest 통과. 전체 스위트는 다른
세션이 같은 저장소에서 테스트를 돌리는 중이라(build 디렉터리 잠금) 로컬에서 끝까지
돌리지 못했다. CI 가 깨끗한 체크아웃에서 돌린다.

Refs #132
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant