Skip to content

fix: 관리자 탈퇴가 개인정보를 남기고, 비로그인 클릭이 집계되지 않았다 - #146

Merged
RosieOh merged 1 commit into
mainfrom
refactor/controllers-off-repositories
Oct 22, 2026
Merged

RosieOh merged 1 commit into
mainfrom
refactor/controllers-off-repositories

Conversation

@RosieOh

@RosieOh RosieOh commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Refs #132 (7단계)

컨트롤러의 리포지토리 직접 사용 37건을 옮기면서, 6단계와 같이 먼저 각 컨트롤러 안을 봤습니다. 둘 나왔습니다.

1. 관리자가 처리한 탈퇴는 개인정보를 파기하지 않았다

같은 "탈퇴 처리" 에 두 구현이 있었습니다.

경로 결과
DELETE /users/account (본인) 이름·이메일·전화·주소·프로필·소셜 ID·좌표를 지우거나 익명화 + 비활성 + deletedAt
DELETE /api/admin/users/{id} (관리자, "사용자 탈퇴 처리") deletedAt·isActive 만. 개인정보는 그대로 남는다

이용자가 고객센터로 탈퇴를 요청하면 운영자가 후자를 누릅니다. 그 경우 이름과 이메일이 계속 남아 있으므로 "파기했다" 고 말할 수 없습니다.

[이메일]
Expecting actual: "d14eb045@example.com"
not to be equal to: "d14eb045@example.com"

"무엇을 지우는가" 는 그 테이블의 규칙이라 User.withdraw() 로 엔티티에 올렸고, 본인 탈퇴와 관리자 탈퇴가 같은 메서드를 씁니다. userId(가입 시 발급한 코드)는 남깁니다 — 게시글·알림이 그 값으로 작성자를 가리키므로 지우면 참조가 끊깁니다.

2. 비로그인 클릭은 한 건도 집계되지 않았다

BenefitLinkController 는 비로그인 클릭을 집계하도록 쓰여 있었습니다(인증 실패를 삼키고 null 로 집계). 그런데 필터가 먼저 401 을 돌려주고 있었습니다.

.requestMatchers("/policies/*").permitAll()   // 한 세그먼트만 잡는다
// → /policies/{id}/apply 는 anyRequest().authenticated() 에 걸린다

정책 상세는 공개이고 프런트가 그 화면에 "신청하기" 를 띄우므로, 로그인하지 않은 방문자는 그 버튼에서 401 을 만났습니다. 이 전환율은 코드 주석이 "서비스가 실제로 돈을 찾아줬는지 증명하는 유일한 지표" 라고 적어 둔 값인데, 비로그인 클릭은 집계되지 않았습니다.

/notifications/{id}/open 도 같은 모양이었습니다(/notifications/** authenticated). 푸시·메일 링크를 눌렀을 때 로그인이 만료돼 있으면 딥링크가 통째로 실패합니다. 응답은 쿼리 파라미터로 만든 딥링크로의 302 뿐이고 알림 내용을 돌려주지 않으므로 둘 다 공개로 바꿨습니다.

알림 ID 의 존재 여부가 404 로 드러나는 것은 받아들였습니다 — 내용·수신자는 알 수 없습니다. 이 교환이 아니라고 보시면 알려주세요.

세그먼트 와일드카드 범위를 잘못 읽어 생긴 문제는 이 저장소에서 세 번째입니다 (/health/hospitals/likes, /community/posts/liked, 그리고 이번 둘).

함께 고친 것

온라인 신청 경로가 없는 정책이 CareServiceException(500)이었습니다. 정상적인 데이터 상태이므로 404 로 바꿨습니다. 잘못된 스킴이 저장된 경우는 우리 데이터가 틀린 것이라 서버 오류로 남깁니다.

옮긴 것

컨트롤러 새/기존 서비스
AdminDashboardController AdminDashboardService (user·health·policy 집계)
AdminUserController AdminUserService (탈퇴는 User.withdraw())
AdminPolicyVerificationController PolicyVerificationService
AdminPolicyController 기존 PolicyAdminService 에 list·detail 추가
NotificationLinkController NotificationLinkService
BenefitLinkController BenefitLinkService

숫자

  • 컨트롤러→리포지토리 37 → 0. 이 규칙은 이제 baseline 이 비었습니다
  • ArchUnit baseline 331 → 291 (도메인 경계 240 → 237)
  • 전체 테스트 647개, 실패 0
  • OpenAPI 경로·스키마 수 변화 없음 (226 / 158)

동작이 바뀌는 지점

  • DELETE /api/admin/users/{id} 가 개인정보를 파기합니다. 어드민 화면이 탈퇴 후 이름·이메일을 보여 준다면 "탈퇴한 사용자" 로 바뀝니다
  • /policies/{id}/apply, /notifications/{id}/open 이 비로그인에도 열립니다

컨트롤러의 리포지토리 직접 사용 37건을 옮기면서 6단계와 같이 먼저 각 컨트롤러 안을
봤다. 둘 나왔다.

1) 관리자가 처리한 탈퇴는 개인정보를 파기하지 않았다

  DELETE /users/account (본인)        이름·이메일·전화·주소·프로필·소셜ID·좌표 파기
  DELETE /api/admin/users/{id} (관리자)  deletedAt·isActive 만

이용자가 고객센터로 탈퇴를 요청하면 운영자가 후자를 누른다. 그 경우 이름과 이메일이
계속 남아 있으므로 "파기했다" 고 말할 수 없다. 테스트로 먼저 확인했다 —
  [이메일] Expecting actual: "d14eb045@example.com" not to be equal to: 같은 값

"무엇을 지우는가" 는 그 테이블의 규칙이라 User.withdraw() 로 엔티티에 올렸고 본인 탈퇴와
관리자 탈퇴가 같은 메서드를 쓴다. userId(가입 시 발급한 코드)는 남긴다 — 게시글·알림이
그 값으로 작성자를 가리키므로 지우면 참조가 끊긴다.

2) 비로그인 클릭은 한 건도 집계되지 않았다

BenefitLinkController 는 비로그인 클릭을 집계하도록 쓰여 있었다(인증 실패를 삼키고 null
로 집계). 그런데 필터가 먼저 401 을 돌려주고 있었다.

  .requestMatchers("/policies/*").permitAll()   // 한 세그먼트만 잡는다
  → /policies/{id}/apply 는 anyRequest().authenticated() 에 걸린다

정책 상세는 공개이고 프런트가 그 화면에 "신청하기" 를 띄우므로, 로그인하지 않은 방문자는
그 버튼에서 401 을 만났다. 이 전환율은 문서가 "서비스가 실제로 돈을 찾아줬는지 증명하는
유일한 지표" 라고 적어 둔 값인데 비로그인 클릭은 집계되지 않았다.

/notifications/{id}/open 도 같은 모양이었다(/notifications/** authenticated). 푸시·메일
링크를 눌렀을 때 로그인이 만료돼 있으면 딥링크가 통째로 실패한다. 응답은 쿼리 파라미터로
만든 딥링크로의 302 뿐이고 알림 내용을 돌려주지 않으므로 둘 다 공개로 바꿨다. 알림 ID 의
존재 여부가 404 로 드러나는 것은 받아들였다 — 내용·수신자는 알 수 없다.

세그먼트 와일드카드 범위를 잘못 읽어 생긴 문제는 이 저장소에서 세 번째다
(/health/hospitals/likes, /community/posts/liked, 그리고 이번 둘).

함께: 온라인 신청 경로가 없는 정책이 CareServiceException(500)이었다. 정상적인 데이터
상태이므로 404 로 바꿨다. 잘못된 스킴이 저장된 경우는 우리 데이터가 틀린 것이라 서버
오류로 남긴다.

옮긴 것
- AdminDashboardController          → AdminDashboardService
- AdminUserController               → AdminUserService (탈퇴는 User.withdraw())
- AdminPolicyVerificationController → PolicyVerificationService
- AdminPolicyController             → 기존 PolicyAdminService 에 list·detail 추가
- NotificationLinkController        → NotificationLinkService
- BenefitLinkController             → BenefitLinkService

- 컨트롤러→리포지토리 37 → 0. 이 규칙은 baseline 이 비었다
- ArchUnit baseline 331 → 291 (도메인 경계 240 → 237)
- 전체 테스트 647개, 실패 0
- OpenAPI 경로·스키마 수 변화 없음(226 / 158)

Refs #132
@RosieOh
RosieOh merged commit 04975fc into main Oct 22, 2026
7 checks passed
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