# PRD: JSON DTO enum 난독화 안정화 ## 1. Overview Release minify 환경에서 Gson/Retrofit 기반 JSON DTO와 API query enum 값이 난독화 영향으로 흔들리지 않도록, 확인된 누락 annotation과 고위험 enum query 경계를 최소 범위로 안정화한다. --- ## 2. Problem - `minifyEnabled true`인 release 빌드에서 Gson reflection 기반 DTO 필드명과 enum 이름 의존이 깨질 수 있다. - 일부 Retrofit request/response DTO에 `@Keep` 또는 필드 `@SerializedName`이 없어 R8 최적화/난독화 시 직렬화 계약이 불안정하다. - `AudioRankingType` 등 일부 enum은 JSON 응답 필드와 Retrofit `@Query` 값에 직접 사용되고 있으나 enum entry `@SerializedName`이 없다. - Retrofit `@Query` enum 변환은 Gson `@SerializedName`을 사용하지 않고 기본적으로 `toString()` fallback에 의존하므로, query 값은 repository/API 경계에서 명시 문자열로 넘기는 방식이 더 안전하다. --- ## 3. Goals - 확정 DTO 누락 5개를 프로젝트 Gson 관례에 맞게 `@Keep` 및 필드 `@SerializedName`으로 보강한다. - 메인 콘텐츠 랭킹/전체/개요 및 관련 홈 랭킹/요일 enum의 JSON 이름과 query 값을 명시적으로 고정한다. - 이번 이슈와 직접 연결된 Retrofit `@Query` enum 전달 경계를 `String`/`String?` 기반으로 바꿔 release minify에서 API parameter 값이 안정적으로 전달되게 한다. - 변경 범위를 문서화하고, 테스트/grep/Gradle 검증으로 회귀 위험을 확인한다. --- ## 4. Non-Goals - Gson에서 Moshi 또는 Kotlin Serialization으로 마이그레이션하지 않는다. - 전역 Retrofit `Converter.Factory` 또는 app-wide enum 변환 정책을 새로 만들지 않는다. - 레거시 화면 전체 리팩터링이나 관련 없는 DTO/enum 일괄 수정을 하지 않는다. - 서버 API 스키마, query parameter 이름, response field 이름을 변경하지 않는다. - `ChatMessage.isGrouped`, `LiveRoomDonationChat.isSecret`처럼 클라이언트 전용 가능성이 있는 후보는 이번 확정 수정 범위에서 제외한다. --- ## 5. Target Users - release/minify 빌드에서 메인 콘텐츠 랭킹/전체/개요, 홈 랭킹/요일 기반 콘텐츠를 사용하는 앱 사용자. - Gson/Retrofit DTO와 R8 규칙을 유지보수하는 Android 개발자. --- ## 6. User Stories - 사용자는 release 앱에서도 랭킹 유형을 바꿀 때 선택한 타입의 API 결과가 안정적으로 표시되길 기대한다. - 사용자는 콘텐츠 전체/개요/홈 랭킹 화면에서 정렬, 타입, 요일 query가 debug/release 빌드 간 다르게 전달되지 않길 기대한다. - 개발자는 API DTO 필드명이 obfuscation 결과에 의존하지 않고 서버 계약 이름으로 고정되길 원한다. --- ## 7. Core Features ### DTO annotation 보강 확정된 Retrofit/Gson request/response DTO의 누락 annotation을 보강한다. #### Requirements - `OriginalWorkListResponse`와 `OriginalWorkListItemResponse`의 모든 constructor property에 `@SerializedName`을 추가한다. - `AuthResponse`에 `@Keep`과 `@SerializedName("gender")`를 추가한다. - `UpdatePlaylistRequest`에 `@Keep`을 추가한다. - `PayverseVerifyRequest`에 `@Keep`을 추가한다. #### Edge Cases - 기존 property type, nullability, 기본값은 변경하지 않는다. - 기존 `@Keep`이 있는 DTO는 유지하고 필드 annotation만 추가한다. ### Enum JSON 이름과 query 값 안정화 고위험 enum에 JSON 이름과 query 값을 명시한다. #### Requirements - `AudioRankingType`, `MainContentAllType`, `ContentSort`, `ContentOverviewType`, `SeriesPublishedDaysOfWeek`, `ContentRankingSortType`에 enum entry별 `@SerializedName`을 추가한다. - 위 enum에는 API wire 값과 같은 안정 문자열 `queryValue`를 제공한다. - 기존 enum 순서와 UI label mapping은 유지한다. #### Edge Cases - `AudioRankingType`의 기존 `queryValue`와 `label` 계약은 유지하되 `@SerializedName`만 보강한다. - `ContentSort`는 creator channel API에서도 사용되므로 query 경계 변경 시 기존 repository public API는 enum 타입을 유지하고 Retrofit API parameter만 문자열로 바꾼다. ### Retrofit query 경계 문자열화 Gson annotation에 의존하지 않도록 Retrofit API interface의 고위험 enum `@Query` parameter를 문자열로 바꾼다. #### Requirements - `AudioRankingsApi`, `MainContentAllTabApi`, `ContentOverviewApi`에서 enum `@Query` parameter를 `String`/`String?`로 변경한다. - 해당 repository에서는 기존 public method의 enum parameter를 유지하고, API 호출 직전에 `.queryValue` 또는 `?.queryValue`로 변환한다. - 홈/시리즈/크리에이터 채널 등 같은 enum을 직접 query로 넘기는 확인된 경계도 같은 방식으로 최소 변환한다. #### Edge Cases - nullable `dayOfWeek`는 null이면 query를 보내지 않도록 `dayOfWeek?.queryValue`를 사용한다. - `toString()` override는 전역 side effect가 있으므로 사용하지 않는다. --- ## 8. UX / UI Expectations - UI 변경은 없다. - debug/release 간 API query 값과 JSON mapping 동작 차이를 줄이는 내부 안정화 작업이다. --- ## 9. Technical Constraints - Kotlin, Retrofit, Gson, AndroidX `@Keep` 기존 스택을 유지한다. - DTO 필드명 안정화는 `com.google.gson.annotations.SerializedName`을 사용한다. - R8 제거/최적화 방지는 `androidx.annotation.Keep`을 사용한다. - 구현 전 `docs/20260709_JSON_DTO_enum_난독화_안정화/plan-task.md`를 작성하고, 범위 변경 시 계획 문서를 먼저 갱신한다. - 레거시 파일은 필요한 API query 경계 보강 외 리팩터링하지 않는다. --- ## 10. Metrics - 확정 DTO 5개가 필요한 `@Keep`/`@SerializedName`을 가진다. - 고위험 enum 6개가 entry별 `@SerializedName`과 `queryValue`를 가진다. - 확인된 고위험 enum이 Retrofit `@Query` parameter로 직접 전달되지 않는다. - 관련 unit test, grep 검증, Gradle compile/test가 통과하거나 환경 blocker가 문서에 기록된다. --- ## 11. Open Questions - 없음. Backend wire 값은 현재 enum constant name과 동일하다고 전제한다. --- ## 12. Verification Log - 2026-07-09: Gson/R8 공식 문서와 Retrofit Gson converter 동작을 확인했다. `@SerializedName`은 JSON body/response enum과 field 이름 안정화에는 필요하지만 Retrofit `@Query` enum 변환에는 적용되지 않으므로, query 경계에서는 명시 문자열 전달이 필요하다고 판단했다.