Files

12 KiB

JSON DTO enum 난독화 안정화 구현 계획/TASK

For agentic workers: 각 단계는 체크박스(- [ ])로 추적하고, 완료 즉시 - [x]로 갱신한다. 구현 범위 변경이 생기면 이 문서를 먼저 수정한 뒤 코드에 반영한다.

Goal: release minify 환경에서 Gson DTO 필드/enum JSON 이름과 Retrofit query 값이 obfuscation에 흔들리지 않도록 확정 범위를 최소 수정한다.

Architecture: DTO는 기존 class/property 계약을 유지하고 annotation만 보강한다. Enum은 wire 값과 동일한 queryValue를 명시하고, Retrofit API interface는 String/String? query를 받도록 바꾸며 repository public API는 enum 타입을 유지한다.

Tech Stack: Kotlin, AndroidX @Keep, Gson @SerializedName, Retrofit, RxJava3, JUnit4 local unit test.


전제와 성공 기준

  • PRD: docs/20260709_JSON_DTO_enum_난독화_안정화/prd.md
  • Backend wire 값은 현재 enum constant name과 동일하다.
  • @SerializedName은 Gson JSON body/response mapping 안정화에 사용한다.
  • Retrofit @Query enum 변환은 Gson @SerializedName에 의존하지 않고 repository에서 .queryValue로 문자열화한다.
  • 기존 public ViewModel/Repository 호출부에는 enum 타입 계약을 최대한 유지한다.
  • 구현 완료 후 최소 다음 명령을 실행한다.
    • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.json.*"
    • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"
    • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"
    • rg '@Query\("(type|sort|dayOfWeek)"\).*: (AudioRankingType|MainContentAllType|ContentSort|ContentOverviewType|SeriesPublishedDaysOfWeek|ContentRankingSortType)' app/src/main/java
    • ./gradlew :app:compileDebugKotlin
    • ./gradlew :app:ktlintCheck

파일 구조

  • Modify: app/src/main/java/kr/co/vividnext/sodalive/chat/original/OriginalWorkListResponse.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/mypage/auth/AuthResponse.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/audio_content/playlist/modify/UpdatePlaylistRequest.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/mypage/can/payment/payverse/PayverseChargeDto.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/data/AudioRankingsModels.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/data/AudioRankingsApi.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/data/AudioRankingsRepository.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/data/MainContentAllTabModels.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/data/MainContentAllTabApi.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/data/MainContentAllTabRepository.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/common/data/ContentSort.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/data/ContentOverviewModels.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/data/ContentOverviewApi.kt
  • Modify: app/src/main/java/kr/co/vividnext/sodalive/v2/main/content/overview/data/ContentOverviewRepository.kt
  • Modify as needed for direct query boundary: app/src/main/java/kr/co/vividnext/sodalive/home/HomeApi.kt, HomeRepository.kt, audio_content/series/main/SeriesMainApi.kt, SeriesMainRepository.kt, v2/creator/channel/data/CreatorChannelApi.kt, CreatorChannelRepository.kt
  • Create: app/src/test/java/kr/co/vividnext/sodalive/json/DtoObfuscationStabilityTest.kt
  • Create: app/src/test/java/kr/co/vividnext/sodalive/json/EnumObfuscationStabilityTest.kt

Phase 1: 문서와 작업 경계 고정

  • Task 1.1: 문서 템플릿과 검증 규칙 확인

    • 확인:
      • docs/prd/sample-prd.md
      • docs/agent-guides/build-test-style.md
      • docs/agent-guides/code-style.md
      • docs/agent-guides/work-plan-docs.md
    • 검증 기록:
      • 2026-07-09: 위 문서를 읽고 신규 문서는 docs/20260709_JSON_DTO_enum_난독화_안정화/prd.md, plan-task.md에 작성해야 하며, 구현 전 계획 문서가 필요함을 확인했다.
  • Task 1.2: 대상 DTO/enum/API 경계 확인

    • 확인:
      • 확정 DTO 5개와 고위험 enum 6개 파일
      • rg@Query("type"|"sort"|"dayOfWeek") 직접 enum parameter 사용처 확인
    • 검증 기록:
      • 2026-07-09: OriginalWorkListResponse, AuthResponse, UpdatePlaylistRequest, PayverseVerifyRequest, AudioRankingType, MainContentAllType, ContentSort, ContentOverviewType, SeriesPublishedDaysOfWeek, ContentRankingSortType의 현재 annotation 누락 상태를 확인했다.

Phase 2: DTO/enum 안정성 테스트 추가

  • Task 2.1: DTO annotation 테스트 추가

    • 생성:
      • app/src/test/java/kr/co/vividnext/sodalive/json/DtoObfuscationStabilityTest.kt
    • 검증:
      • AuthResponse, UpdatePlaylistRequest, PayverseVerifyRequest@Keep
      • 확정 DTO field의 @SerializedName
    • 검증 명령:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.json.DtoObfuscationStabilityTest"
    • 기대 결과:
      • production 수정 전 RED, 수정 후 GREEN.
    • 검증 기록:
      • 2026-07-09: DtoObfuscationStabilityTest를 추가해 확정 DTO의 @Keep source 계약과 field별 @SerializedName 값을 검증하도록 했다. androidx.annotation.Keep은 런타임 reflection 조회 대상이 아니어서 source-level 확인으로 고정했다.
  • Task 2.2: Enum JSON/query value 테스트 추가

    • 생성:
      • app/src/test/java/kr/co/vividnext/sodalive/json/EnumObfuscationStabilityTest.kt
    • 검증:
      • 고위험 enum 6개의 entry별 @SerializedName
      • queryValue가 backend wire 값과 일치
    • 검증 명령:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.json.EnumObfuscationStabilityTest"
    • 기대 결과:
      • production 수정 전 RED, 수정 후 GREEN.
    • 검증 기록:
      • 2026-07-09: EnumObfuscationStabilityTest를 추가해 고위험 enum 6개의 entry별 @SerializedNamequeryValue가 backend wire 값과 일치하는지 검증하도록 했다.

Phase 3: DTO annotation 보강

  • Task 3.1: 확정 DTO @Keep/@SerializedName 보강
    • 수정:
      • OriginalWorkListResponse.kt
      • AuthResponse.kt
      • UpdatePlaylistRequest.kt
      • PayverseChargeDto.kt
    • 구현:
      • 확정 누락 annotation만 추가하고 type/nullability/default는 유지한다.
    • 검증 명령:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.json.DtoObfuscationStabilityTest"
    • 기대 결과:
      • DTO annotation 테스트 통과.
    • 검증 기록:
      • 2026-07-09: OriginalWorkListResponse, OriginalWorkListItemResponse, AuthResponse, UpdatePlaylistRequest, PayverseVerifyRequest에 확정 누락 annotation을 보강했다. ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.json.*" 실행 결과 BUILD SUCCESSFUL.

Phase 4: Enum JSON 이름과 query 값 보강

  • Task 4.1: 고위험 enum entry @SerializedNamequeryValue 추가
    • 수정:
      • AudioRankingsModels.kt
      • MainContentAllTabModels.kt
      • ContentSort.kt
      • ContentOverviewModels.kt
      • SeriesPublishedDaysOfWeek.kt
      • ContentRankingSortType.kt
    • 구현:
      • enum 순서를 유지한다.
      • @Keep@SerializedName("...")을 추가한다.
      • queryValue는 현재 enum constant name과 동일한 wire 값으로 둔다.
    • 검증 명령:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.json.EnumObfuscationStabilityTest"
    • 기대 결과:
      • enum 안정성 테스트 통과.
    • 검증 기록:
      • 2026-07-09: AudioRankingType, MainContentAllType, ContentSort, ContentOverviewType, SeriesPublishedDaysOfWeek, ContentRankingSortType@Keep, entry별 @SerializedName, queryValue를 필요한 범위로 추가했다. enum 순서와 기존 label mapping은 유지했다.

Phase 5: Retrofit query 경계 문자열화

  • Task 5.1: content/ranking/overview query API parameter 문자열화

    • 수정:
      • AudioRankingsApi.kt, AudioRankingsRepository.kt
      • MainContentAllTabApi.kt, MainContentAllTabRepository.kt
      • ContentOverviewApi.kt, ContentOverviewRepository.kt
    • 구현:
      • API interface의 enum @Query parameter를 String/String?로 변경한다.
      • repository에서 .queryValue로 변환한다.
    • 검증:
      • 관련 content package 테스트와 compile 통과.
    • 검증 기록:
      • 2026-07-09: AudioRankingsApi, MainContentAllTabApi, ContentOverviewApi의 고위험 enum query parameter를 String/String?로 바꾸고 repository에서 .queryValue로 변환하도록 했다. ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*" 실행 결과 BUILD SUCCESSFUL.
  • Task 5.2: 같은 enum을 직접 쓰는 추가 query 경계 최소 보강

    • 수정:
      • HomeApi.kt, HomeRepository.kt
      • SeriesMainApi.kt, SeriesMainRepository.kt
      • CreatorChannelApi.kt, CreatorChannelRepository.kt
    • 구현:
      • public 호출부 enum 타입은 유지하고 Retrofit query만 문자열로 전달한다.
    • 검증 명령:
      • rg '@Query\("(type|sort|dayOfWeek)"\).*: (AudioRankingType|MainContentAllType|ContentSort|ContentOverviewType|SeriesPublishedDaysOfWeek|ContentRankingSortType)' app/src/main/java
    • 기대 결과:
      • grep 결과가 없다.
    • 검증 기록:
      • 2026-07-09: HomeApi, SeriesMainApi, CreatorChannelApiSeriesPublishedDaysOfWeek, ContentRankingSortType, ContentSort query parameter를 문자열로 바꾸고 repository에서 .queryValue로 변환하도록 했다. rg '@Query\("(type|sort|dayOfWeek)"\).*: (AudioRankingType|MainContentAllType|ContentSort|ContentOverviewType|SeriesPublishedDaysOfWeek|ContentRankingSortType)' app/src/main/java 실행 결과 출력 없음.

Phase 6: 통합 검증과 기록

  • Task 6.1: 대상 테스트와 compile 실행

    • 실행:
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.json.*"
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*"
      • ./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.overview.*"
      • ./gradlew :app:compileDebugKotlin
      • ./gradlew :app:ktlintCheck
    • 기대 결과:
      • 모두 통과하거나 기존/환경 이슈를 이 문서에 기록한다.
    • 검증 기록:
      • 2026-07-09: ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.json.*" 실행 결과 BUILD SUCCESSFUL.
      • 2026-07-09: ./gradlew --no-daemon :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.v2.main.content.*" 실행 결과 BUILD SUCCESSFUL.
      • 2026-07-09: ./gradlew --no-daemon :app:compileDebugKotlin 실행 결과 BUILD SUCCESSFUL.
      • 2026-07-09: git diff --check 실행 결과 출력 없음.
      • 2026-07-09: ./gradlew :app:ktlintCheck는 기존 전역 위반으로 실패했다. 확인된 항목은 기존 underscore package 경고(audio_content...)와 기존 long line(ContentCommentedAudioAdapter.kt:29)이며, 이번 변경으로 발생한 HomeRepository.kt 줄바꿈 위반은 수정했다.
  • Task 6.2: 최종 Verification Log 누적

    • 수정:
      • docs/20260709_JSON_DTO_enum_난독화_안정화/plan-task.md
    • 구현:
      • 실행 명령, 결과, blocker를 한국어로 누적 기록한다.

Verification Log

  • 2026-07-09: PRD와 계획 문서를 생성했다. 구현 범위는 확정 DTO annotation 보강, 고위험 enum JSON/query value 보강, Retrofit query 경계 문자열화로 제한했다.
  • 2026-07-09: 확정 DTO와 고위험 enum 보강 및 Retrofit query 문자열화를 완료했다. JSON 안정성 테스트, V2 main content 테스트, compileDebugKotlin, 직접 enum @Query grep, git diff --check는 통과했다. ktlintCheck는 기존 전역 위반이 남아 실패 상태로 기록한다.