Files
sodalive-backend-spring-boot/docs/20260507_콘텐츠관리자권한및관리자로그인API추가.md

6.0 KiB

콘텐츠 관리자 권한 및 관리자 로그인 API 추가

작업 항목

  • MemberRole에 콘텐츠 관리자 권한을 추가한다.
  • 관리자 로그인 API 테스트를 먼저 추가하고 RED를 확인한다.
  • 관리자와 콘텐츠 관리자만 로그인 가능한 관리자 전용 로그인 API를 구현한다.
  • 응답을 token, role만 포함하도록 구현한다.
  • focused test, 관련 테스트, 스타일 검사를 실행하고 결과를 기록한다.
  • 콘텐츠 관리자가 GET /menu를 호출할 수 있도록 메뉴 조회 권한을 확장한다.
  • 콘텐츠 관리자가 관리자 콘텐츠 목록/조회 보조 API를 호출할 수 있도록 읽기 권한만 확장한다.
  • 콘텐츠 관리자가 관리자 콘텐츠 수정 API를 호출할 수 없도록 수정 권한은 관리자 전용으로 유지한다.
  • focused security test, 관련 테스트, 스타일 검사를 실행하고 결과를 기록한다.

설계

  • 새 권한은 기존 MemberRole enum에 CONTENT_MANAGER로 추가한다.
  • 새 API는 관리자 도메인의 /admin/member/login으로 추가하고 인증 없이 호출 가능하도록 보안 설정에 permitAll을 추가한다.
  • 서비스는 기존 이메일/비밀번호 인증 흐름과 JWT 생성 방식을 재사용하되, ADMIN, CONTENT_MANAGER 외 역할은 common.error.bad_credentials 예외로 거부한다.
  • 응답 DTO는 관리자 로그인 전용으로 분리해 token, role만 노출한다.

후속 설계: 콘텐츠 관리자 메뉴 및 콘텐츠 읽기 권한

  • CONTENT_MANAGER는 이미 관리자 로그인 API로 토큰을 받을 수 있으므로 새 역할이나 새 권한 타입을 추가하지 않는다.
  • 메뉴 조회는 기존 GET /menuMenuRepository.getMenu(member.role) 구조를 그대로 사용한다. 컨트롤러의 @PreAuthorizeCONTENT_MANAGER만 추가해 콘텐츠 관리자가 자신의 역할에 매핑된 메뉴를 받을 수 있게 한다.
  • /content/list는 서버 코드 상수가 아니라 Menu.route DB 값으로 내려가는 구조이므로, 서버에서는 별도 라우트 상수를 추가하지 않는다. 실제 메뉴 노출은 roles = CONTENT_MANAGER, route = /content/list, isActive = true 데이터가 존재할 때 가능하다.
  • 관리자 콘텐츠 API는 기존 hasRole('ADMIN') 클래스 권한을 메서드 단위로 분리한다. GET /admin/audio-content/list, GET /admin/audio-content/search, GET /admin/audio-content/main/tabADMINCONTENT_MANAGER를 허용하고, PUT /admin/audio-contentADMIN만 허용한다.
  • 콘텐츠 재생은 기존 사용자 콘텐츠 API의 GET /audio-content/{id}/generate-url 흐름을 변경하지 않는다. 이 API는 로그인 사용자와 구매/접근 조건으로 재생 URL을 제어하므로 콘텐츠 관리자 전용 우회 권한은 추가하지 않는다.

구현 계획

  • MenuController 보안 테스트를 추가해 CONTENT_MANAGERGET /menu에 접근 가능하고 일반 사용자는 거부되는지 확인한다.
  • AdminContentController 보안 테스트를 추가해 CONTENT_MANAGER는 목록/검색/메인탭 조회가 가능하고 수정은 거부되는지 확인한다.
  • 테스트가 실패하는 것을 확인한다.
  • MenuController@PreAuthorizeCONTENT_MANAGER를 추가한다.
  • AdminContentController의 클래스 단위 @PreAuthorize를 제거하고 각 메서드에 읽기/수정 권한을 분리한다.
  • focused test, 관련 test, ktlint를 실행해 검증한다.

검증 기록

  • 2026-05-07: RED 확인: ./gradlew test --tests 'kr.co.vividnext.sodalive.admin.member.AdminMemberLoginServiceTest' --tests 'kr.co.vividnext.sodalive.admin.member.AdminMemberLoginControllerTest' 실행 시 AdminMemberLoginService, AdminMemberLoginController, AdminMemberLoginResponse, CONTENT_MANAGER, findByEmail 미구현으로 compileTestKotlin이 실패함을 확인했다.
  • 2026-05-07: GREEN 확인: 동일 focused test가 BUILD SUCCESSFUL로 통과해 관리자/콘텐츠 관리자 로그인 허용 및 일반 사용자 거부를 확인했다.
  • 2026-05-07: API 응답 확인: ./gradlew test --tests 'kr.co.vividnext.sodalive.admin.member.AdminMemberLoginControllerTest.shouldReturnTokenAndRoleJson'BUILD SUCCESSFUL로 통과해 POST /admin/member/login JSON 응답의 data.token, data.role을 확인했다.
  • 2026-05-07: 회귀 확인: ./gradlew test --tests 'kr.co.vividnext.sodalive.admin.member.*'BUILD SUCCESSFUL로 통과했다.
  • 2026-05-07: 스타일 확인: ./gradlew ktlintCheckBUILD SUCCESSFUL로 통과했다.
  • 2026-05-07: Kotlin LSP는 현재 환경에 .kt 서버가 설정되어 있지 않아 lsp_diagnostics 실행이 불가했다. 대신 Gradle 컴파일 포함 focused/관련 test와 ktlint로 검증했다.
  • 2026-05-07: RED 확인: ./gradlew test --tests 'kr.co.vividnext.sodalive.menu.MenuControllerSecurityTest' --tests 'kr.co.vividnext.sodalive.admin.content.AdminContentControllerSecurityTest' 실행 시 CONTENT_MANAGERGET /menu, GET /admin/audio-content/list, GET /admin/audio-content/search, GET /admin/audio-content/main/tab 허용 기대 테스트 4건이 실패함을 확인했다.
  • 2026-05-07: GREEN 확인: 동일 focused security test가 BUILD SUCCESSFUL로 통과해 콘텐츠 관리자 메뉴 조회, 관리자 콘텐츠 목록/검색/메인탭 조회 허용과 관리자 콘텐츠 수정 거부를 확인했다.
  • 2026-05-07: 관련 테스트 확인: ./gradlew test --tests 'kr.co.vividnext.sodalive.admin.content.AdminContentServiceTest' --tests 'kr.co.vividnext.sodalive.admin.member.AdminMemberLoginServiceTest' --tests 'kr.co.vividnext.sodalive.admin.member.AdminMemberLoginControllerTest'BUILD SUCCESSFUL로 통과했다.
  • 2026-05-07: 스타일 확인: ./gradlew ktlintCheckBUILD SUCCESSFUL로 통과했다.
  • 2026-05-07: Kotlin LSP는 현재 환경에 .kt 서버가 설정되어 있지 않아 lsp_diagnostics 실행이 불가했다. 대신 Gradle 컴파일 포함 focused/관련 test와 ktlint로 검증했다.