Skip to content

T-07 관리자 트랙 CRUD - #61

Open
ff1451 wants to merge 1 commit into
feat/t06-track-domainfrom
feat/t07-admin-track-crud
Open

T-07 관리자 트랙 CRUD#61
ff1451 wants to merge 1 commit into
feat/t06-track-domainfrom
feat/t07-admin-track-crud

Conversation

@ff1451

@ff1451 ff1451 commented Aug 19, 2026

Copy link
Copy Markdown

Refs #19
Base: feat/t06-track-domain (#60)

변경

트랙 마스터(/v1/admin/tracks, 부원 소속용)와 홈페이지 프로필(/v1/admin/track-pages)을 경로·서비스 클래스 모두 분리했다(ADR-002) — 서로 다른 리소스라 한 컨트롤러에 욱여넣지 않았다.

  • AdminTrackMasterService — 목록(홈페이지 프로필 유무 포함) / 생성(code 중복 409) / 수정(이름·활성 여부만, code는 불변)
  • AdminTrackPageService — 목록 / 생성(slug는 displayName에서 자동 생성, AC-1.1) / 상세 / 헤더 수정 / slug 수동 변경 / 공개-숨김 / 순서 / soft delete
  • SlugGenerator — 소문자 변환 + 비영숫자를 하이픈으로 뭉침
  • PublishRequest/OrderRequestglobal/controller/dto/request에 공용으로 뺐다05-api-spec.md의 공통 규약(PATCH .../publish, PATCH .../order)을 여기서 한 번만 정의하고, 앞으로 T-10(커리큘럼)·T-14/T-15(활동)가 그대로 재사용한다.
  • SecurityConfig 변경 없음 — /v1/admin/**이 이미 SCOPE_FULL+ROLE_ADMIN을 요구하므로 새 경로가 자동으로 보호된다.
  • 트랙 페이지 생성 시 "이미 프로필이 있는 트랙"은 uq_track_page_track DB 제약이 이미 막고 있지만, 도메인 예외(TRACK_PAGE_ALREADY_EXISTS, 409)로 먼저 잡아서 일반적인 "제약조건에 위배되는 값입니다" 대신 명확한 응답을 준다.

부수 발견 및 수정 — 공유 컨테이너 테스트의 함정

IntegrationTestSupport(T-01)로 컨테이너/컨텍스트를 공유하는 테스트가 늘면서 두 가지 교차 오염을 발견했다.

  1. TrackPromotionIntegrationTest(T-35, T-35 트랙 필드 승격 (member.track enum → 참조 테이블) #58)에 refreshTokenRepository.deleteAll()이 빠져 있었다. 이 PR의 AdminTrackIntegrationTest가 로그인 플로우를 쓰면서 남긴 refresh_token 행이 그 테스트의 memberRepository.deleteAll()을 FK 위반으로 막았다. T-35 PR이 아직 머지되지 않았고 원인이 이 PR에서 드러난 테스트 상호작용이라, 여기서 함께 고쳤다.
  2. track 테이블을 "고정 시드"로 취급하는 단언이 깨졌다. AdminTrackIntegrationTest의 트랙 마스터 생성 테스트가 새 TrackMaster 행을 만들고 정리하지 않아서, TrackPromotionIntegrationTest의 "정확히 11행" 단언이 테스트 실행 순서에 따라 흔들렸다. 처음 전체 실행은 통과했지만 반복 실행에서 드러나서, 3회 연속 재실행으로 재현 후 테스트 안에서 직접 정리하도록 고쳤다.

교훈(다음 티켓에도 적용): IntegrationTestSupport 하위 테스트가 "고정 시드"로 취급되는 테이블(track 등)에 행을 만들면 반드시 그 테스트가 직접 치워야 한다.

테스트

AdminTrackIntegrationTest(신규):

  • AC-6.1/6.2 토큰 없음 401, MEMBER 권한 403
  • AC-1.1 "Data Analyst" → slug "data-analyst"
  • AC-1.2 중복 slug 409
  • AC-1.4 순서 변경이 공개 목록(GET /v1/tracks)에 즉시 반영
  • AC-1.5 id 집합 불일치 시 400이고 아무것도 안 바뀜
  • 트랙 마스터 코드 중복 409, 이름/활성 여부 수정

./gradlew test3회 연속 돌려 전체 통과(50개, 실패 0) 확인 — 위 플레이키니스 때문에 이번엔 1회로 끝내지 않았다.

트랙 마스터(/v1/admin/tracks)와 홈페이지 프로필(/v1/admin/track-pages)을 각각
관리한다 — 경로와 서비스 클래스를 리소스별로 분리했다(ADR-002).

- AdminTrackMasterService — 목록(홈페이지 프로필 유무 포함)/생성(code 중복 409)/
  수정(이름·활성 여부만, code는 불변)
- AdminTrackPageService — 목록/생성(slug는 displayName에서 자동 생성, AC-1.1)/
  상세/헤더 수정/slug 수동 변경/공개-숨김/순서/soft delete
- SlugGenerator — 소문자 변환 + 비영숫자를 하이픈으로
- PublishRequest/OrderRequest(global/controller/dto/request) — 공개/숨김과
  순서 변경 규약을 여기서 한 번만 정의한다. T-10/T-14/T-15가 그대로 재사용한다
- SecurityConfig 변경 없음 — /v1/admin/**이 이미 SCOPE_FULL+ROLE_ADMIN을 요구한다
- TrackPage에 header/slug/publish/order mutation 메서드, TrackMaster에 update
  메서드 추가

트랙 페이지 생성 시 "이미 프로필이 있는 트랙"은 uq_track_page_track DB 제약이
이미 막고 있지만, 도메인 예외(TRACK_PAGE_ALREADY_EXISTS, 409)로 먼저 잡아
일반적인 "제약조건 위배" 메시지 대신 명확한 응답을 준다.

테스트: AdminTrackIntegrationTest(신규) —
- AC-6.1/6.2 토큰 없음 401, MEMBER 권한 403
- AC-1.1 slug 자동 생성 ("Data Analyst" -> "data-analyst")
- AC-1.2 중복 slug 409
- AC-1.4 순서 변경이 공개 목록에 즉시 반영
- AC-1.5 id 집합 불일치 시 400이고 아무것도 안 바뀜
- 트랙 마스터 코드 중복 409, 이름/활성 여부 수정

부수 수정: TrackPromotionIntegrationTest(T-35)에 refreshTokenRepository.deleteAll()
누락 — IntegrationTestSupport로 컨테이너를 공유하는 다른 테스트가 로그인해서
남긴 refresh_token이 member 삭제를 막는 문제를 여기서 발견해 고쳤다.

발견한 것: 컨테이너/컨텍스트를 공유하는 IntegrationTestSupport 하위 테스트는
"고정 시드"로 취급되는 테이블(track 등)에 행을 만들면 반드시 직접 정리해야
한다 — 안 그러면 다른 테스트의 카운트 단언이 실행 순서에 따라 흔들린다. 처음
전체 실행은 통과했지만 반복 실행에서 이 문제가 드러났다(AdminTrackIntegrationTest가
만든 트랙 마스터가 TrackPromotionIntegrationTest의 "11개" 단언을 깨뜨림) —
같은 이유로 3회 연속 재실행해 재현 후 고쳤다.

./gradlew test 3회 연속 전체 통과(50개, 실패 0).

Refs #19
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8390f4f7-44a0-4ab9-a089-ad4de75116b9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ff1451 ff1451 mentioned this pull request Aug 19, 2026
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