fix(api): 콘텐츠 설정 PATCH 제외 API 파라미터를 제거한다

This commit is contained in:
Yu Sung
2026-03-27 22:28:21 +09:00
parent f542191d46
commit d369bc11f7
17 changed files with 234 additions and 379 deletions

View File

@@ -9,7 +9,7 @@ import Foundation
import Moya
enum ContentApi {
case getAudioContentList(userId: Int, categoryId: Int, isAdultContentVisible: Bool, page: Int, size: Int, sort: ContentListViewModel.Sort)
case getAudioContentList(userId: Int, categoryId: Int, page: Int, size: Int, sort: ContentListViewModel.Sort)
case getAudioContentDetail(audioContentId: Int)
case likeContent(request: PutAudioContentLikeRequest)
case registerComment(request: RegisterAudioContentCommentRequest)
@@ -25,51 +25,51 @@ enum ContentApi {
case getNewContentUploadCreatorList
case getMainBannerList
case getMainOrderList
case getNewContentOfTheme(theme: String, isAdultContentVisible: Bool, contentType: ContentType)
case getCurationList(isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case getNewContentOfTheme(theme: String)
case getCurationList(page: Int, size: Int)
case donation(request: AudioContentDonationRequest)
case modifyComment(request: ModifyCommentRequest)
case getNewContentThemeList(isAdultContentVisible: Bool, contentType: ContentType)
case getNewContentAllOfTheme(isFree: Bool, theme: String, isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case getAudioContentListByCurationId(curationId: Int, isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int, sort: ContentCurationViewModel.Sort)
case getContentRanking(isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int, sortType: String)
case getNewContentThemeList
case getNewContentAllOfTheme(isFree: Bool, theme: String, page: Int, size: Int)
case getAudioContentListByCurationId(curationId: Int, page: Int, size: Int, sort: ContentCurationViewModel.Sort)
case getContentRanking(page: Int, size: Int, sortType: String)
case getContentRankingSortType
case pinContent(contentId: Int)
case unpinContent(contentId: Int)
case getAudioContentByTheme(themeId: Int, isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int, sort: ContentAllByThemeViewModel.Sort)
case getAudioContentByTheme(themeId: Int, page: Int, size: Int, sort: ContentAllByThemeViewModel.Sort)
case generateUrl(contentId: Int)
case getContentMainHome(isAdultContentVisible: Bool, contentType: ContentType)
case getPopularContentByCreator(creatorId: Int, isAdultContentVisible: Bool, contentType: ContentType)
case getContentMainHomeContentRanking(isAdultContentVisible: Bool, contentType: ContentType, sortType: String)
case getContentMainHome
case getPopularContentByCreator(creatorId: Int)
case getContentMainHomeContentRanking(sortType: String)
case getContentMainSeries(isAdultContentVisible: Bool, contentType: ContentType)
case getRecommendSeriesListByGenre(genreId: Int, isAdultContentVisible: Bool, contentType: ContentType)
case getRecommendSeriesByCreator(creatorId: Int, isAdultContentVisible: Bool, contentType: ContentType)
case getCompletedSeries(isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case getContentMainSeries
case getRecommendSeriesListByGenre(genreId: Int)
case getRecommendSeriesByCreator(creatorId: Int)
case getCompletedSeries(page: Int, size: Int)
case getContentMainContent(isAdultContentVisible: Bool, contentType: ContentType)
case getContentMainNewContentOfTheme(theme: String, isAdultContentVisible: Bool, contentType: ContentType)
case getDailyContentRanking(sortType: String, isAdultContentVisible: Bool, contentType: ContentType)
case getRecommendContentByTag(tag: String, contentType: ContentType)
case getContentMainContentPopularContentByCreator(creatorId: Int, isAdultContentVisible: Bool, contentType: ContentType)
case getContentMainContent
case getContentMainNewContentOfTheme(theme: String)
case getDailyContentRanking(sortType: String)
case getRecommendContentByTag(tag: String)
case getContentMainContentPopularContentByCreator(creatorId: Int)
case getContentMainAlarm(isAdultContentVisible: Bool, contentType: ContentType)
case getContentMainAlarmAll(theme: String, isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case getContentMainAlarm
case getContentMainAlarmAll(theme: String, page: Int, size: Int)
case getContentMainAsmr(isAdultContentVisible: Bool, contentType: ContentType)
case getPopularAsmrContentByCreator(creatorId: Int, isAdultContentVisible: Bool, contentType: ContentType)
case getContentMainAsmr
case getPopularAsmrContentByCreator(creatorId: Int)
case getContentMainReplay(isAdultContentVisible: Bool, contentType: ContentType)
case getPopularReplayContentByCreator(creatorId: Int, isAdultContentVisible: Bool, contentType: ContentType)
case getContentMainReplay
case getPopularReplayContentByCreator(creatorId: Int)
case getContentMainFree(isAdultContentVisible: Bool, contentType: ContentType)
case getIntroduceCreatorList(isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case getNewFreeContentOfTheme(theme: String, isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case getPopularFreeContentByCreator(creatorId: Int, isAdultContentVisible: Bool, contentType: ContentType)
case getContentMainFree
case getIntroduceCreatorList(page: Int, size: Int)
case getNewFreeContentOfTheme(theme: String, page: Int, size: Int)
case getPopularFreeContentByCreator(creatorId: Int)
case getAllAudioContents(isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int, isFree: Bool?, isPointAvailableOnly: Bool?, sortType: ContentAllViewModel.Sort = .NEWEST, theme: String? = nil)
case getAudioContentActiveThemeList(isAdultContentVisible: Bool, contentType: ContentType, isFree: Bool?, isPointAvailableOnly: Bool?)
case getAllAudioContents(page: Int, size: Int, isFree: Bool?, isPointAvailableOnly: Bool?, sortType: ContentAllViewModel.Sort = .NEWEST, theme: String? = nil)
case getAudioContentActiveThemeList(isFree: Bool?, isPointAvailableOnly: Bool?)
}
extension ContentApi: TargetType {
@@ -145,7 +145,7 @@ extension ContentApi: TargetType {
case .getNewContentAllOfTheme:
return "/audio-content/main/new/all"
case .getAudioContentListByCurationId(let curationId, _, _, _, _, _):
case .getAudioContentListByCurationId(let curationId, _, _, _):
return "/audio-content/curation/\(curationId)"
case .getContentRanking:
@@ -160,7 +160,7 @@ extension ContentApi: TargetType {
case .unpinContent(let contentId):
return "/audio-content/unpin-at-the-top/\(contentId)"
case .getAudioContentByTheme(let themeId, _, _, _, _, _):
case .getAudioContentByTheme(let themeId, _, _, _):
return "/audio-content/theme/\(themeId)/content"
case .generateUrl(let contentId):
@@ -273,11 +273,10 @@ extension ContentApi: TargetType {
var task: Moya.Task {
switch self {
case .getAudioContentList(let userId, let categoryId, let isAdultContentVisible, let page, let size, let sort):
case .getAudioContentList(let userId, let categoryId, let page, let size, let sort):
let parameters = [
"creator-id": userId,
"category-id": categoryId,
"isAdultContentVisible": isAdultContentVisible,
"page": page - 1,
"size": size,
"sort-type": sort
@@ -339,11 +338,9 @@ extension ContentApi: TargetType {
case .deleteAudioContent:
return .requestPlain
case .getNewContentOfTheme(let theme, let isAdultContentVisible, let contentType):
case .getNewContentOfTheme(let theme):
let parameters = [
"theme": theme,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"theme": theme
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
@@ -354,30 +351,21 @@ extension ContentApi: TargetType {
case .modifyComment(let request):
return .requestJSONEncodable(request)
case .getNewContentThemeList(let isAdultContentVisible, let contentType):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
] as [String : Any]
case .getNewContentThemeList:
return .requestPlain
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getNewContentAllOfTheme(let isFree, let theme, let isAdultContentVisible, let contentType, let page, let size):
case .getNewContentAllOfTheme(let isFree, let theme, let page, let size):
let parameters = [
"isFree": isFree,
"theme": theme,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getAudioContentListByCurationId(_, let isAdultContentVisible, let contentType, let page, let size, let sort):
case .getAudioContentListByCurationId(_, let page, let size, let sort):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size,
"sort-type": sort
@@ -385,10 +373,8 @@ extension ContentApi: TargetType {
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getContentRanking(let isAdultContentVisible, let contentType, let page, let size, let sortType):
case .getContentRanking(let page, let size, let sortType):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size,
"sort-type": sortType
@@ -399,10 +385,8 @@ extension ContentApi: TargetType {
case .getContentRankingSortType:
return .requestPlain
case .getCurationList(let isAdultContentVisible, let contentType, let page, let size):
case .getCurationList(let page, let size):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size
] as [String : Any]
@@ -412,10 +396,8 @@ extension ContentApi: TargetType {
case .pinContent, .unpinContent:
return .requestPlain
case .getAudioContentByTheme(_, let isAdultContentVisible, let contentType, let page, let size, let sort):
case .getAudioContentByTheme(_, let page, let size, let sort):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size,
"sort-type": sort
@@ -423,141 +405,109 @@ extension ContentApi: TargetType {
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getContentMainHome(let isAdultContentVisible, let contentType),
.getContentMainSeries(let isAdultContentVisible, let contentType),
.getContentMainContent(let isAdultContentVisible, let contentType),
.getContentMainAlarm(let isAdultContentVisible, let contentType),
.getContentMainAsmr(let isAdultContentVisible, let contentType),
.getContentMainReplay(let isAdultContentVisible, let contentType),
.getContentMainFree(let isAdultContentVisible, let contentType):
case .getContentMainHome,
.getContentMainSeries,
.getContentMainContent,
.getContentMainAlarm,
.getContentMainAsmr,
.getContentMainReplay,
.getContentMainFree:
return .requestPlain
case .getRecommendSeriesListByGenre(let genreId):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"genreId": genreId
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getRecommendSeriesListByGenre(let genreId, let isAdultContentVisible, let contentType):
case .getPopularContentByCreator(let creatorId):
let parameters = [
"genreId": genreId,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"creatorId": creatorId
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getPopularContentByCreator(let creatorId, let isAdultContentVisible, let contentType):
case .getContentMainHomeContentRanking(let sortType):
let parameters = [
"creatorId": creatorId,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"sort-type": sortType
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getContentMainHomeContentRanking(let isAdultContentVisible, let contentType, let sortType):
case .getRecommendSeriesByCreator(let creatorId):
let parameters = [
"sort-type": sortType,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"creatorId": creatorId
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getRecommendSeriesByCreator(let creatorId, let isAdultContentVisible, let contentType):
case .getContentMainNewContentOfTheme(let theme):
let parameters = [
"creatorId": creatorId,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"theme": theme
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getDailyContentRanking(let sortType):
let parameters = [
"sort-type": sortType
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getRecommendContentByTag(let tag):
let parameters = [
"tag": tag
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getContentMainContentPopularContentByCreator(let creatorId):
let parameters = [
"creatorId": creatorId
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getContentMainNewContentOfTheme(let theme, let isAdultContentVisible, let contentType):
case .getNewFreeContentOfTheme(let theme, let page, let size):
let parameters = [
"theme": theme,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"page": page - 1,
"size": size
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getDailyContentRanking(let sortType, let isAdultContentVisible, let contentType):
let parameters = [
"sort-type": sortType,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getRecommendContentByTag(let tag, let contentType):
let parameters = [
"tag": tag,
"contentType": contentType
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getContentMainContentPopularContentByCreator(let creatorId, let isAdultContentVisible, let contentType):
let parameters = [
"creatorId": creatorId,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getNewFreeContentOfTheme(let theme, let isAdultContentVisible, let contentType, let page, let size):
case .getContentMainAlarmAll(let theme, let page, let size):
let parameters = [
"theme": theme,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getContentMainAlarmAll(let theme, let isAdultContentVisible, let contentType, let page, let size):
case .getIntroduceCreatorList(let page, let size):
let parameters = [
"theme": theme,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getIntroduceCreatorList(let isAdultContentVisible, let contentType, let page, let size):
case .getPopularAsmrContentByCreator(let creatorId),
.getPopularReplayContentByCreator(let creatorId),
.getPopularFreeContentByCreator(let creatorId):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size
"creatorId": creatorId
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getPopularAsmrContentByCreator(let creatorId, let isAdultContentVisible, let contentType),
.getPopularReplayContentByCreator(let creatorId, let isAdultContentVisible, let contentType),
.getPopularFreeContentByCreator(let creatorId, let isAdultContentVisible, let contentType):
case .getCompletedSeries(let page, let size):
let parameters = [
"creatorId": creatorId,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getCompletedSeries(let isAdultContentVisible, let contentType, let page, let size):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getAllAudioContents(let isAdultContentVisible, let contentType, let page, let size, let isFree, let isPointAvailableOnly, let sortType, let theme):
case .getAllAudioContents(let page, let size, let isFree, let isPointAvailableOnly, let sortType, let theme):
var parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"sort-type": sortType,
"page": page - 1,
"size": size
@@ -577,11 +527,8 @@ extension ContentApi: TargetType {
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getAudioContentActiveThemeList(let isAdultContentVisible, let contentType, let isFree, let isPointAvailableOnly):
var parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
] as [String : Any]
case .getAudioContentActiveThemeList(let isFree, let isPointAvailableOnly):
var parameters = [String : Any]()
if let isFree = isFree {
parameters["isFree"] = isFree

View File

@@ -20,7 +20,6 @@ final class ContentRepository {
.getAudioContentList(
userId: userId,
categoryId: categoryId,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
page: page,
size: size,
sort: sort)
@@ -89,19 +88,13 @@ final class ContentRepository {
func getNewContentOfTheme(theme: String) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getNewContentOfTheme(
theme: theme,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
.getNewContentOfTheme(theme: theme)
)
}
func getCurationList(page: Int, size: Int) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getCurationList(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size
)
@@ -117,12 +110,7 @@ final class ContentRepository {
}
func getNewContentThemeList() -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getNewContentThemeList(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
)
return api.requestPublisher(.getNewContentThemeList)
}
func getNewContentAllOfTheme(isFree: Bool, theme: String, page: Int, size: Int) -> AnyPublisher<Response, MoyaError> {
@@ -130,8 +118,6 @@ final class ContentRepository {
.getNewContentAllOfTheme(
isFree: isFree,
theme: theme,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size
)
@@ -142,8 +128,6 @@ final class ContentRepository {
return api.requestPublisher(
.getAudioContentListByCurationId(
curationId: curationId,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size,
sort: sort
@@ -158,8 +142,6 @@ final class ContentRepository {
func getContentRanking(page: Int, size: Int, sortType: String = "매출") -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getContentRanking(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size,
sortType: sortType
@@ -183,8 +165,6 @@ final class ContentRepository {
return api.requestPublisher(
.getAudioContentByTheme(
themeId: themeId,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size,
sort: sort
@@ -206,8 +186,6 @@ final class ContentRepository {
) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getAllAudioContents(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size,
isFree: isFree,
@@ -221,8 +199,6 @@ final class ContentRepository {
func getAudioContentActiveThemeList(isFree: Bool, isPointAvailableOnly: Bool) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getAudioContentActiveThemeList(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
isFree: isFree,
isPointAvailableOnly: isPointAvailableOnly
)

View File

@@ -9,11 +9,11 @@ import Foundation
import Moya
enum SeriesMainApi {
case fetchHome(isAdultContentVisible: Bool, contentType: ContentType)
case getRecommendSeriesList(isAdultContentVisible: Bool, contentType: ContentType)
case getDayOfWeekSeriesList(dayOfWeek: SeriesPublishedDaysOfWeek, isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case getGenreList(isAdultContentVisible: Bool, contentType: ContentType)
case getSeriesListByGenre(genreId: Int, isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case fetchHome
case getRecommendSeriesList
case getDayOfWeekSeriesList(dayOfWeek: SeriesPublishedDaysOfWeek, page: Int, size: Int)
case getGenreList
case getSeriesListByGenre(genreId: Int, page: Int, size: Int)
}
extension SeriesMainApi: TargetType {
@@ -39,46 +39,27 @@ extension SeriesMainApi: TargetType {
var task: Moya.Task {
switch self {
case .fetchHome(let isAdultContentVisible, let contentType):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
] as [String : Any]
case .fetchHome:
return .requestPlain
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getRecommendSeriesList:
return .requestPlain
case .getRecommendSeriesList(let isAdultContentVisible, let contentType):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getDayOfWeekSeriesList(let dayOfWeek, let isAdultContentVisible, let contentType, let page, let size):
case .getDayOfWeekSeriesList(let dayOfWeek, let page, let size):
let parameters = [
"dayOfWeek": dayOfWeek,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getGenreList(let isAdultContentVisible, let contentType):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
] as [String : Any]
case .getGenreList:
return .requestPlain
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getSeriesListByGenre(let genreId, let isAdultContentVisible, let contentType, let page, let size):
case .getSeriesListByGenre(let genreId, let page, let size):
let parameters = [
"genreId": genreId,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size
] as [String : Any]

View File

@@ -14,29 +14,17 @@ class SeriesMainRepository {
private let api = MoyaProvider<SeriesMainApi>()
func fetchHome() -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.fetchHome(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
)
return api.requestPublisher(.fetchHome)
}
func getRecommendSeriesList() -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getRecommendSeriesList(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
)
return api.requestPublisher(.getRecommendSeriesList)
}
func getDayOfWeekSeriesList(dayOfWeek: SeriesPublishedDaysOfWeek, page: Int, size: Int) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getDayOfWeekSeriesList(
dayOfWeek: dayOfWeek,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size
)
@@ -44,20 +32,13 @@ class SeriesMainRepository {
}
func getGenreList() -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getGenreList(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
)
)
return api.requestPublisher(.getGenreList)
}
func getSeriesListByGenre(genreId: Int, page: Int, size: Int) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getSeriesListByGenre(
genreId: genreId,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size
)

View File

@@ -9,10 +9,10 @@ import Foundation
import Moya
enum SeriesApi {
case getSeriesList(creatorId: Int?, isOriginal: Bool, isCompleted: Bool, sortType: SeriesListAllViewModel.SeriesSortType, isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case getSeriesDetail(seriesId: Int, isAdultContentVisible: Bool)
case getSeriesContentList(seriesId: Int, isAdultContentVisible: Bool, page: Int, size: Int, sortType: SeriesListAllViewModel.SeriesSortType)
case getRecommendSeriesList(isAdultContentVisible: Bool, contentType: ContentType)
case getSeriesList(creatorId: Int?, isOriginal: Bool, isCompleted: Bool, sortType: SeriesListAllViewModel.SeriesSortType, page: Int, size: Int)
case getSeriesDetail(seriesId: Int)
case getSeriesContentList(seriesId: Int, page: Int, size: Int, sortType: SeriesListAllViewModel.SeriesSortType)
case getRecommendSeriesList
}
extension SeriesApi: TargetType {
@@ -25,10 +25,10 @@ extension SeriesApi: TargetType {
case .getSeriesList:
return "/audio-content/series"
case .getSeriesDetail(let seriesId, _):
case .getSeriesDetail(let seriesId):
return "/audio-content/series/\(seriesId)"
case .getSeriesContentList(let seriesId, _, _, _, _):
case .getSeriesContentList(let seriesId, _, _, _):
return "/audio-content/series/\(seriesId)/content"
case .getRecommendSeriesList:
@@ -45,11 +45,9 @@ extension SeriesApi: TargetType {
var task: Moya.Task {
switch self {
case .getSeriesList(let creatorId, let isOriginal, let isCompleted, let sortType, let isAdultContentVisible, let contentType, let page, let size):
case .getSeriesList(let creatorId, let isOriginal, let isCompleted, let sortType, let page, let size):
var parameters = [
"sortType": sortType,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"isOriginal": isOriginal,
"isCompleted": isCompleted,
"page": page - 1,
@@ -62,21 +60,14 @@ extension SeriesApi: TargetType {
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getSeriesDetail(_, let isAdultContentVisible):
let parameters = ["isAdultContentVisible": isAdultContentVisible] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getSeriesDetail:
return .requestPlain
case .getRecommendSeriesList(let isAdultContentVisible, let contentType):
case .getRecommendSeriesList:
return .requestPlain
case .getSeriesContentList(_, let page, let size, let sortType):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getSeriesContentList(_, let isAdultContentVisible, let page, let size, let sortType):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"page": page - 1,
"size": size,
"sortType": sortType

View File

@@ -20,8 +20,6 @@ class SeriesRepository {
isOriginal: isOriginal,
isCompleted: isCompleted,
sortType: sortType,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size
)
@@ -29,19 +27,13 @@ class SeriesRepository {
}
func getSeriesDetail(seriesId: Int) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getSeriesDetail(
seriesId: seriesId,
isAdultContentVisible: UserDefaults.isAdultContentVisible()
)
)
return api.requestPublisher(.getSeriesDetail(seriesId: seriesId))
}
func getSeriesContentList(seriesId: Int, page: Int, size: Int, sortType: SeriesListAllViewModel.SeriesSortType) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getSeriesContentList(
seriesId: seriesId,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
page: page,
size: size,
sortType: sortType
@@ -50,11 +42,6 @@ class SeriesRepository {
}
func getRecommendSeriesList() -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getRecommendSeriesList(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
)
return api.requestPublisher(.getRecommendSeriesList)
}
}

View File

@@ -12,7 +12,7 @@ enum ExplorerApi {
case getCreatorRank
case getExplorer
case searchChannel(channel: String)
case getCreatorProfile(userId: Int, isAdultContentVisible: Bool)
case getCreatorProfile(userId: Int)
case getCreatorDetail(userId: Int)
case getFollowerList(userId: Int, page: Int, size: Int)
case getCreatorProfileCheers(userId: Int, page: Int, size: Int)
@@ -40,7 +40,7 @@ extension ExplorerApi: TargetType {
case .searchChannel:
return "/explorer/search/channel"
case .getCreatorProfile(let userId, _):
case .getCreatorProfile(let userId):
return "/explorer/profile/\(userId)"
case .getCreatorDetail(let userId):
@@ -90,8 +90,8 @@ extension ExplorerApi: TargetType {
case .searchChannel(let channel):
return .requestParameters(parameters: ["channel" : channel], encoding: URLEncoding.queryString)
case .getCreatorProfile(_, let isAdultContentVisible):
let parameters = ["isAdultContentVisible": isAdultContentVisible, "timezone": TimeZone.current.identifier] as [String: Any]
case .getCreatorProfile:
let parameters = ["timezone": TimeZone.current.identifier] as [String: Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getFollowerList(_, let page, let size):

View File

@@ -22,12 +22,7 @@ final class ExplorerRepository {
}
func getCreatorProfile(id: Int) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getCreatorProfile(
userId: id,
isAdultContentVisible: UserDefaults.isAdultContentVisible()
)
)
return api.requestPublisher(.getCreatorProfile(userId: id))
}
func getCreatorDetail(id: Int) -> AnyPublisher<Response, MoyaError> {

View File

@@ -9,11 +9,11 @@ import Foundation
import Moya
enum HomeApi {
case getHomeData(isAdultContentVisible: Bool, contentType: ContentType)
case getLatestContentByTheme(theme: String, isAdultContentVisible: Bool, contentType: ContentType)
case getDayOfWeekSeriesList(dayOfWeek: SeriesPublishedDaysOfWeek, isAdultContentVisible: Bool, contentType: ContentType)
case getRecommendContents(isAdultContentVisible: Bool, contentType: ContentType)
case getContentRankingBySort(sort: ContentRankingSortType, isAdultContentVisible: Bool, contentType: ContentType)
case getHomeData
case getLatestContentByTheme(theme: String)
case getDayOfWeekSeriesList(dayOfWeek: SeriesPublishedDaysOfWeek)
case getRecommendContents
case getContentRankingBySort(sort: ContentRankingSortType)
}
extension HomeApi: TargetType {
@@ -46,46 +46,33 @@ extension HomeApi: TargetType {
var task: Moya.Task {
switch self {
case .getHomeData(let isAdultContentVisible, let contentType):
case .getHomeData:
let parameters = [
"timezone": TimeZone.current.identifier,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"timezone": TimeZone.current.identifier
] as [String: Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getLatestContentByTheme(let theme, let isAdultContentVisible, let contentType):
case .getLatestContentByTheme(let theme):
let parameters = [
"theme": theme,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"theme": theme
] as [String: Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getDayOfWeekSeriesList(let dayOfWeek, let isAdultContentVisible, let contentType):
case .getDayOfWeekSeriesList(let dayOfWeek):
let parameters = [
"dayOfWeek": dayOfWeek,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"dayOfWeek": dayOfWeek
] as [String: Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getRecommendContents(let isAdultContentVisible, let contentType):
let parameters = [
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
] as [String: Any]
case .getRecommendContents:
return .requestPlain
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .getContentRankingBySort(let sort, let isAdultContentVisible, let contentType):
case .getContentRankingBySort(let sort):
let parameters = [
"sort": sort,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"sort": sort
] as [String: Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)

View File

@@ -14,50 +14,22 @@ class HomeTabRepository {
private let api = MoyaProvider<HomeApi>()
func fetchData() -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getHomeData(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
)
return api.requestPublisher(.getHomeData)
}
func getLatestContentByTheme(theme: String) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getLatestContentByTheme(
theme: theme,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
)
return api.requestPublisher(.getLatestContentByTheme(theme: theme))
}
func getDayOfWeekSeriesList(dayOfWeek: SeriesPublishedDaysOfWeek) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getDayOfWeekSeriesList(
dayOfWeek: dayOfWeek,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
)
return api.requestPublisher(.getDayOfWeekSeriesList(dayOfWeek: dayOfWeek))
}
func getRecommendContents() -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getRecommendContents(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
)
return api.requestPublisher(.getRecommendContents)
}
func getContentRankingBySort(sort: ContentRankingSortType) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getContentRankingBySort(
sort: sort,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
)
return api.requestPublisher(.getContentRankingBySort(sort: sort))
}
}

View File

@@ -41,7 +41,7 @@ enum LiveApi {
case likeHeart(request: LiveRoomLikeHeartRequest)
case getTotalHeartCount(roomId: Int)
case heartStatus(roomId: Int)
case getLiveMain(isAdultContentVisible: Bool, contentType: ContentType)
case getLiveMain
}
extension LiveApi: TargetType {
@@ -260,11 +260,9 @@ extension LiveApi: TargetType {
case .likeHeart(let request):
return .requestJSONEncodable(request)
case .getLiveMain(let isAdultContentVisible, let contentType):
case .getLiveMain:
let parameters = [
"timezone": TimeZone.current.identifier,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"timezone": TimeZone.current.identifier
] as [String: Any]
return .requestParameters(

View File

@@ -145,11 +145,6 @@ final class LiveRepository {
}
func getLiveMain() -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.getLiveMain(
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
)
return api.requestPublisher(.getLiveMain)
}
}

View File

@@ -210,7 +210,6 @@ final class LiveViewModel: ObservableObject {
timezone: TimeZone.current.identifier,
dateString: nil,
status: .NOW,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
page: page,
size: pageSize
)
@@ -268,7 +267,6 @@ final class LiveViewModel: ObservableObject {
timezone: TimeZone.current.identifier,
dateString: selectedDateString,
status: .RESERVATION,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
page: page,
size: pageSize
)

View File

@@ -11,7 +11,6 @@ struct GetRoomListRequest {
let timezone: String
let dateString: String?
let status: LiveRoomStatus
let isAdultContentVisible: Bool
let page: Int
let size: Int
}

View File

@@ -9,10 +9,10 @@ import Foundation
import Moya
enum SearchApi {
case searchUnified(keyword: String, isAdultContentVisible: Bool, contentType: ContentType)
case searchCreatorList(keyword: String, isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case searchContentList(keyword: String, isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case searchSeriesList(keyword: String, isAdultContentVisible: Bool, contentType: ContentType, page: Int, size: Int)
case searchUnified(keyword: String)
case searchCreatorList(keyword: String, page: Int, size: Int)
case searchContentList(keyword: String, page: Int, size: Int)
case searchSeriesList(keyword: String, page: Int, size: Int)
}
extension SearchApi: TargetType {
@@ -42,42 +42,34 @@ extension SearchApi: TargetType {
var task: Moya.Task {
switch self {
case .searchUnified(let keyword, let isAdultContentVisible, let contentType):
case .searchUnified(let keyword):
let parameters = [
"keyword": keyword,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType
"keyword": keyword
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .searchCreatorList(let keyword, let isAdultContentVisible, let contentType, let page, let size):
case .searchCreatorList(let keyword, let page, let size):
let parameters = [
"keyword": keyword,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .searchContentList(let keyword, let isAdultContentVisible, let contentType, let page, let size):
case .searchContentList(let keyword, let page, let size):
let parameters = [
"keyword": keyword,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size
] as [String : Any]
return .requestParameters(parameters: parameters, encoding: URLEncoding.queryString)
case .searchSeriesList(let keyword, let isAdultContentVisible, let contentType, let page, let size):
case .searchSeriesList(let keyword, let page, let size):
let parameters = [
"keyword": keyword,
"isAdultContentVisible": isAdultContentVisible,
"contentType": contentType,
"page": page - 1,
"size": size
] as [String : Any]

View File

@@ -14,21 +14,13 @@ final class SearchRepository {
private let api = MoyaProvider<SearchApi>()
func searchUnified(keyword: String) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.searchUnified(
keyword: keyword,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL
)
)
return api.requestPublisher(.searchUnified(keyword: keyword))
}
func searchCreatorList(keyword: String, page: Int, size: Int) -> AnyPublisher<Response, MoyaError> {
return api.requestPublisher(
.searchCreatorList(
keyword: keyword,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size
)
@@ -39,8 +31,6 @@ final class SearchRepository {
return api.requestPublisher(
.searchContentList(
keyword: keyword,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size
)
@@ -51,8 +41,6 @@ final class SearchRepository {
return api.requestPublisher(
.searchSeriesList(
keyword: keyword,
isAdultContentVisible: UserDefaults.isAdultContentVisible(),
contentType: ContentType(rawValue: UserDefaults.string(forKey: .contentPreference)) ?? ContentType.ALL,
page: page,
size: size
)

View File

@@ -0,0 +1,68 @@
# 20260327 제외 API 콘텐츠 설정 파라미터 제거
## 개요
- `PATCH /member/content-preference`를 제외한 모든 API 요청에서 `isAdultContentVisible`, `contentType` 파라미터를 제거한다.
- 콘텐츠 설정 동기화 API(`PATCH /member/content-preference`)의 요청/응답 구조와 호출 흐름은 유지한다.
## 요구사항 요약
- 유지 대상 API: `PATCH /member/content-preference`
- 제거 대상: 유지 대상 API를 제외한 나머지 API 요청 파라미터의 `isAdultContentVisible`, `contentType`
## 완료 기준 (Acceptance Criteria)
- [x] AC1: `PATCH /member/content-preference` 외 API 정의에서 `isAdultContentVisible`/`contentType` 요청 파라미터가 제거된다.
- [x] AC2: 제거에 따라 연쇄되는 Repository/Request 모델 시그니처가 정합성 있게 정리된다.
- [x] AC3: `PATCH /member/content-preference` 요청/응답 필드(`isAdultContentVisible`, `contentType`)는 유지된다.
- [x] AC4: 정적 진단/빌드/수동 QA(검색 검증) 결과가 통과 또는 사유와 함께 기록된다.
## 구현 체크리스트
- [x] API 타깃(`HomeApi`, `LiveApi`, `SearchApi`, `ContentApi`, `SeriesApi`, `SeriesMainApi`, `ExplorerApi`) 파라미터 제거
- [x] 연관 Repository 메서드 시그니처 및 호출부 인자 정리
- [x] `PATCH /member/content-preference` 체인(`UserApi`, `UpdateContentPreferenceRequest/Response`, `ContentSettingsViewModel`) 유지 확인
- [x] 진단/빌드/수동 QA 실행
- [x] 검증 기록 문서화
## 검증 계획
- [x] 정적 진단:
- `lsp_diagnostics` on modified Swift files
- [x] 빌드:
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build`
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build`
- [x] 테스트 시도:
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" test`
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" test`
- [x] 수동 QA:
- `grep` 기반으로 `/member/content-preference` PATCH 외 API 요청 파라미터 잔존 여부 확인
## 검증 기록
- 일시: 2026-03-27
- 무엇: 제외 API 콘텐츠 설정 파라미터 제거 작업 계획 문서 작성
- 왜: 변경 범위와 완료 기준을 선행 고정해 요청사항을 정확히 반영하기 위함
- 어떻게: docs 규칙에 맞춰 완료 기준/체크리스트/검증 계획 수립
- 실행 명령/도구: `apply_patch(문서 생성)`
- 결과: 구현 계획 문서 생성 완료
- 일시: 2026-03-27
- 무엇: `PATCH /member/content-preference` 제외 API의 `isAdultContentVisible`/`contentType` 요청 파라미터 제거
- 왜: 콘텐츠 설정 PATCH API를 제외한 다른 API에서 두 파라미터를 전송하지 않도록 하기 위함
- 어떻게:
- API 타깃(`HomeApi`, `LiveApi`, `SearchApi`, `ContentApi`, `SeriesApi`, `SeriesMainApi`, `ExplorerApi`) case 시그니처와 `task` 파라미터 딕셔너리에서 두 필드를 제거
- 연관 Repository 호출부에서 `UserDefaults` 기반 인자 전달 제거
- `GetRoomListRequest``isAdultContentVisible` 필드 및 `LiveViewModel` 생성 인자 제거
- `PATCH /member/content-preference` 체인(`UserApi.updateContentPreference`, `UpdateContentPreferenceRequest/Response`) 유지 검증
- 실행 명령/도구:
- 정적 진단: `lsp_diagnostics` (수정 파일 전체)
- 빌드:
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build`
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build`
- 테스트 시도:
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" test`
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" test`
- 수동 QA(검색 검증):
- `grep("isAdultContentVisible\\s*:", path="SodaLive/Sources")`
- `grep("contentType\\s*:", path="SodaLive/Sources")`
- `grep("updateContentPreference|member/content-preference", path="SodaLive/Sources/User/UserApi.swift")`
- 결과:
- 빌드: `SodaLive`, `SodaLive-dev` Debug 빌드 모두 `BUILD SUCCEEDED`
- 테스트: 두 스킴 모두 `Scheme ... is not currently configured for the test action`으로 실행 불가(테스트 액션 미구성)
- `lsp_diagnostics`: SourceKit 환경에서 외부 모듈(`Moya`, `CombineMoya`) 해석 한계로 모듈 미해결 에러가 반환됨
- 수동 QA: `isAdultContentVisible`/`contentType`는 설정 동기화 체인과 응답 모델/화면 상태에만 남고, `/member/content-preference` PATCH 외 API 요청 파라미터에서는 제거됨