Repository navigation
test: 구조 규칙을 테스트로 고정 (ArchUnit, 현재 위반은 baseline) - #133
Merged
Merged
Conversation
`CorsPolicy` 의 기본값에는 넣어 뒀지만, docker-compose 가 `CORS_ALLOWED_ORIGINS` 를 명시해 그 기본값을 덮어쓴다. 그래서 `docker compose up` 으로 띄운 백엔드에는 앱 출처가 빠져 있었다. 앱을 기기에 올려 붙여 보려는 사람이 가장 먼저 만나는 벽이고, 증상이 "앱은 켜지는데 데이터만 안 나온다" 라서 원인을 찾기 어렵다. 왜 필요한지도 함께 적었다.
토큰이 알림 설정 행의 한 칸(DEVICE_TOKEN)에 들어 있었다. 사용자당 하나뿐이라 휴대폰에서
알림을 켜면 웹에서 켜 둔 토큰을 덮어썼고, 덮인 쪽은 **아무 말 없이** 알림을 받지 못했다.
사용자는 "알림이 안 와요" 라고만 말할 수 있고, 어느 기기인지도 왜인지도 모른다.
토큰은 사용자의 성질이 아니라 기기의 성질이다. 기존 코드도 그걸 알고 있었다 —
리포지터리 주석에 "토큰은 기기의 성질이지 알림 유형의 성질이 아닌데" 라고 적혀 있고,
조회 메서드는 이미 List 를 돌려주고 있었다. 디스패처에서만 하나로 좁히고 있었다.
■ 기기마다 행을 둔다
`TBL_PUSH_DEVICE` (V21). 토큰에 유일 제약을 건다 — 같은 토큰이 두 사용자에게 달릴 수
없다. 기기를 넘겨주거나 다른 계정으로 로그인하면 주인만 옮겨 간다. 그러지 않으면
이전 사용자에게 알림이 계속 간다.
■ 옛 자리도 함께 읽는다
설정 행의 `deviceToken` 은 그 전에 쓰던 자리다. 예전에 등록해 둔 사용자가 앱을 다시 열어
토큰을 새로 올리기 전까지는 그 값으로 계속 받아야 하므로 양쪽을 합쳐 보낸다(중복 제거).
설정 행 쪽 로직은 건드리지 않았다 — 알림 켜짐/꺼짐이 그 행에 달려 있다.
■ 죽은 토큰은 지운다
앱을 지우거나 데이터를 초기화하면 토큰이 죽는다. 그대로 두면 그 사용자에게 알림을 보낼
때마다 헛호출이 쌓이고 로그가 실패로 가득 차 진짜 문제를 덮는다. FCM 이 UNREGISTERED /
INVALID_ARGUMENT 로 답한 토큰만 지운다 — UNAVAILABLE 같은 일시적 실패로 지우면 그 기기는
영영 알림을 못 받는다.
한 대가 실패해도 나머지는 계속 보낸다. 기기 하나가 앱을 지웠다고 다른 기기까지 알림을
못 받을 이유가 없다.
■ 검증
- 전체 테스트 통과(발송 7개 신규). 마이그레이션과 엔티티 매핑은 `ddl-auto=validate` 로 함께 검증된다
- 로컬에 띄워 Flyway 적용 확인(version 21, success)
- 같은 계정으로 WEB·ANDROID 토큰을 등록해 **두 행이 모두 남는 것**을 확인.
이전에는 두 번째가 첫 번째를 덮어썼다
이 저장소가 지저분해진 방식은 로직이 엉킨 게 아니라 같은 일을 여러 방식으로 하게 된 것이다.
예외 체계가 셋(CareServiceException 96 / BusinessException 51 / 도메인 전용 94),
소유권 검증 구현이 셋, 도메인 컨트롤러가 core 에 있고, 다른 도메인 리포지토리를 그냥 쓴다.
한 번 정리해도 다음 기능에서 다시 섞이면 의미가 없다. 그래서 규칙을 먼저 고정한다.
FreezingArchRule 로 현재 위반(489건)을 baseline 에 묶어 커밋하고, 새 위반만 실패시킨다.
기존 위반을 고치면 목록에서 자동으로 빠지므로 baseline 줄 수가 진척도가 된다.
규칙 9개 중 2개는 이미 위반 0 이다 — 층 방향(서비스→컨트롤러 금지)과 매핑 경계(엔티티→DTO 금지)는
지켜지고 있다. 문제는 같은 층 안의 경계다.
271 다른 도메인의 리포지토리 직접 참조
96 careFacility 패키지 소문자 아님
66 컨트롤러 → 리포지토리 직접
50 core 기반 패키지 → domain
3 매퍼 → 리포지토리
2 core 에 컨트롤러 (CareFacilityApiController 373줄)
1 도메인에서 SecurityContextHolder 직접 사용
core/scheduler·client·devtools 는 공공데이터 동기화·배치처럼 원래 도메인을 조합하는 코드라
"기반은 도메인을 모른다" 규칙의 대상에서 뺐다. 처음 규칙으로는 373건이 잡혔는데, 그건 규칙이
코드 구조와 맞지 않았던 것이다. 그 코드가 공통 기반 자리에 있는 문제는 1단계에서 다룬다.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #132 (0단계. 1~5단계는 이어서 올린다)
왜 규칙부터인가
한 번 정리해도 다음 기능에서 다시 섞이면 의미가 없다. 그래서 고치기 전에 규칙을 먼저 고정한다.
FreezingArchRule로 현재 위반 489건을 baseline 에 묶어 커밋했다. 새 위반만 빌드를 실패시키고, 기존 위반을 고치면 목록에서 자동으로 빠진다 — baseline 줄 수가 진척도다.규칙과 현재 위반
careFacility)마지막 둘이 0 인 게 중요하다 — 층 방향 자체는 맞다. 문제는 같은 층 안의 경계다.
규칙을 한 번 고쳤다
처음에는 "core 는 domain 을 의존하지 않는다" 로 썼더니 373건이 잡혔다. 보니
core/scheduler·client·devtools는 공공데이터 동기화·배치처럼 원래 여러 도메인을 조합하는 코드였다. 규칙이 코드와 맞지 않았던 것이라, 기반 패키지(보안·웹·설정·저장소·유틸)만 대상으로 좁혔다. 그 코드가 "공통 기반" 자리에 있는 문제는 1단계에서 조합 계층으로 분리한다.테스트
전체 600 tests(구조 규칙 9개 포함), 실패 0, skip 0