Skip to content

Conversation

@AyoungSe0
Copy link

@AyoungSe0 AyoungSe0 commented Nov 7, 2025

  1. 미션 요구 사항
    [v] 각 API 요청 성공 시 스낵바 띄우기

    1. 삭제하기 성공 시 스낵바 띄우기
    2. 게시글 수정 성공 시 스낵바 띄우기
  2. 설명
    게시글 작성 성공 시 스낵바 띄우기와 동일한 방법으로 미션 완료. snackBarState: SnackbarHostState와 val scope = rememberCoroutineScope() 활용.

  3. 실행 영상

KUITweek6.mp4

@coderabbitai
Copy link

coderabbitai bot commented Nov 7, 2025

📋 개요

API 클라이언트 인프라(Retrofit)를 통합하고, 하드코딩된 게시물 데이터 모델을 API 응답 모델로 교체하며, UI 화면 전체에 걸쳐 스낵바 상태 관리를 추가하고, 멀티파트 지원을 포함한 이미지 업로드 기능을 구현했습니다.

📝 변경 사항

그룹 / 파일(들) 변경 요약
빌드 설정
.idea/gradle.xml, app/build.gradle.kts
Gradle 모듈 경로를 단순화하고, BASE_URL buildConfigField를 추가하며, Retrofit, Gson, OkHttp 및 로깅 인터셉터 의존성을 구성했습니다.
API 계층
app/src/main/java/com/example/kuit6_android_api/data/api/ApiService.kt, app/src/main/java/com/example/kuit6_android_api/data/api/RetrofitClient.kt
게시물 CRUD 및 이미지 업로드 엔드포인트를 정의하는 Retrofit API 서비스 인터페이스와, 로깅 인터셉터 및 타임아웃이 구성된 OkHttpClient를 사용하는 싱글톤 RetrofitClient를 추가했습니다.
데이터 모델 - 요청/응답
app/src/main/java/com/example/kuit6_android_api/data/model/request/PostCreateRequest.kt, app/src/main/java/com/example/kuit6_android_api/data/model/response/AuthorResponse.kt, app/src/main/java/com/example/kuit6_android_api/data/model/response/BaseResponse.kt, app/src/main/java/com/example/kuit6_android_api/data/model/response/PostResponse.kt
API 요청 및 응답 페이로드 구조화를 위해 새로운 데이터 클래스들을 추가했습니다. 모든 필드는 @SerialName 어노테이션으로 JSON 매핑됩니다.
레거시 모델 제거
app/src/main/java/com/example/kuit6_android_api/data/model/Post.kt
기존 Post 및 Author 데이터 클래스를 제거했습니다.
UI 계층 - 스낵바 통합
app/src/main/java/com/example/kuit6_android_api/MainActivity.kt, app/src/main/java/com/example/kuit6_android_api/ui/navigation/NavGraph.kt, app/src/main/java/com/example/kuit6_android_api/ui/post/screen/PostDetailScreen.kt, app/src/main/java/com/example/kuit6_android_api/ui/post/screen/PostCreateScreen.kt, app/src/main/java/com/example/kuit6_android_api/ui/post/screen/PostEditScreen.kt
MainActivity에서 Surface를 Scaffold로 교체하고, SnackbarHostState를 NavGraph를 통해 모든 화면으로 전파하여 작업 완료 후 피드백을 표시합니다.
UI 컴포넌트
app/src/main/java/com/example/kuit6_android_api/ui/post/component/PostItem.kt
PostResponse 및 AuthorResponse 응답 타입을 사용하도록 업데이트했습니다.
ViewModel
app/src/main/java/com/example/kuit6_android_api/ui/post/viewmodel/PostViewModel.kt
하드코딩된 더미 데이터를 Retrofit API 호출로 교체하고, 이미지 업로드 지원을 추가하며, 데이터 모델을 PostResponse로 마이그레이션했습니다. 새로운 uploadImage() 메서드와 isUploading 상태를 도입했습니다.

🔄 시퀀스 다이어그램

sequenceDiagram
    participant User
    participant PostCreateScreen as PostCreateScreen
    participant PostViewModel as PostViewModel
    participant ApiService as ApiService
    
    rect rgb(200, 220, 255)
    Note over PostCreateScreen,ApiService: 이미지 선택 및 업로드
    User->>PostCreateScreen: 이미지 선택
    PostCreateScreen->>PostViewModel: uploadImage(context, uri)
    PostViewModel->>PostViewModel: uriToFile() 변환
    PostViewModel->>ApiService: uploadImage(multipart)
    ApiService-->>PostViewModel: 업로드된 imageUrl 반환
    PostViewModel->>PostViewModel: uploadedImageUrl 저장
    PostCreateScreen->>PostCreateScreen: 이미지 미리보기 표시
    end
    
    rect rgb(220, 255, 220)
    Note over PostCreateScreen,ApiService: 게시물 생성
    User->>PostCreateScreen: 게시물 생성 버튼 클릭
    PostCreateScreen->>PostViewModel: createPost(title, content, uploadedImageUrl)
    PostViewModel->>ApiService: createPost(author, request)
    ApiService-->>PostViewModel: BaseResponse<PostResponse>
    PostViewModel->>PostCreateScreen: 콜백 실행
    PostCreateScreen->>PostCreateScreen: 스낵바 표시 성공 메시지
    end
Loading
sequenceDiagram
    participant User
    participant PostDetailScreen as PostDetailScreen
    participant PostViewModel as PostViewModel
    participant ApiService as ApiService
    participant MainActivity as MainActivity
    
    rect rgb(255, 200, 200)
    Note over PostDetailScreen,MainActivity: 게시물 삭제 흐름
    User->>PostDetailScreen: 삭제 버튼 클릭
    PostDetailScreen->>PostViewModel: deletePost(postId)
    PostViewModel->>ApiService: deletePost(id)
    ApiService-->>PostViewModel: 성공 응답
    PostViewModel->>PostViewModel: postDetail 초기화
    PostViewModel->>PostViewModel: getPosts() 재호출
    PostViewModel->>PostDetailScreen: 콜백 실행
    PostDetailScreen->>MainActivity: SnackbarHostState.showSnackbar()
    MainActivity->>User: 삭제 성공 메시지 표시
    end
Loading

🎯 코드 리뷰 예상 난이도

🎯 4 (복잡함) | ⏱️ ~50분

세부 검토 항목:

  • PostViewModel.kt: API 통합, 상태 관리, 이미지 업로드 로직의 밀도가 높음. 특히 createPost/updatePost의 서명 변경과 콜백 체인 검증 필요
  • ApiService.kt 및 RetrofitClient.kt: 새로운 Retrofit 설정이 올바르게 초기화되는지 확인 필요. BASE_URL 주입 경로 추적 필수
  • 화면 간 스낵바 상태 전파: MainActivity → NavGraph → 각 화면으로의 snackBarState 전파 경로가 일관되게 적용되었는지 확인
  • 데이터 모델 마이그레이션: Post → PostResponse, Author → AuthorResponse 교체가 모든 사용처에서 완료되었는지 검증
  • PostEditScreen.kt: removeImage 플래그, 이미지 선택 시 즉시 업로드, finalImageUrl 계산 로직이 복잡하므로 엣지 케이스 검토 필요

📜 축하 시

🐰 Retrofit 바람이 불어와
데이터 흐르는 API의 강
이미지는 구름 위로 날고
스낵바는 축하 메시지 띄우네
더미는 안녕, 진짜 데이터 환영!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive 제목이 PR의 주요 변경사항을 명확하게 설명하지 못하고 있습니다. '6주차 미션 / 안드로이드 2조 서아영'은 주차 번호와 팀 정보만 포함하며, 실제 코드 변경의 핵심(Retrofit API 통합, Snackbar 추가, 이미지 업로드 기능 등)을 전혀 나타내지 않습니다. 제목을 더욱 구체적으로 작성하여 주요 변경사항을 명확히 표현하세요. 예: 'Retrofit API 통합 및 Snackbar 피드백 추가' 또는 '게시물 API 연동 및 이미지 업로드 기능 구현'으로 변경을 권장합니다.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

@alswlekk
Copy link
Contributor

alswlekk commented Nov 7, 2025

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.

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

✨ Finishing touches
🧪 Generate unit tests (beta)

  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.
@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Nov 7, 2025

@alswlekk: I'll review the changes in this PR now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

♻️ Duplicate comments (2)
app/src/main/java/com/example/kuit6_android_api/data/model/response/PostResponse.kt (1)

5-13: @serializable 어노테이션이 누락되었습니다.

다른 응답 모델들과 동일한 직렬화 불일치 문제입니다. AuthorResponseBaseResponse와 함께 수정이 필요합니다.

kotlinx-serialization 사용 시:

 package com.example.kuit6_android_api.data.model.response
 
 import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
 
+@Serializable
 data class PostResponse(
     @SerialName(value = "id") val id: Long,
     @SerialName(value = "title") val title: String,
     @SerialName(value = "content") val content: String,
     @SerialName(value = "imageUrl") val imageUrl: String?,
     @SerialName(value = "author") val author: AuthorResponse,
     @SerialName(value = "createdAt") val createdAt: String,
     @SerialName(value = "updatedAt") val updatedAt: String
 )
app/src/main/java/com/example/kuit6_android_api/data/model/request/PostCreateRequest.kt (1)

5-9: @serializable 어노테이션이 누락되었습니다.

요청 모델도 응답 모델들과 동일한 직렬화 불일치 문제가 있습니다. Retrofit의 Gson 컨버터가 @SerialName 어노테이션을 인식하지 못하므로 API 요청이 제대로 작동하지 않을 수 있습니다.

kotlinx-serialization 사용 시:

 package com.example.kuit6_android_api.data.model.request
 
 import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
 
+@Serializable
 data class PostCreateRequest(
     @SerialName(value = "title") val title: String,
     @SerialName(value = "content") val content: String,
     @SerialName(value = "imageUrl") val imageUrl: String?
 )

Gson 사용 시:

 package com.example.kuit6_android_api.data.model.request
 
-import kotlinx.serialization.SerialName
+import com.google.gson.annotations.SerializedName
 
 data class PostCreateRequest(
-    @SerialName(value = "title") val title: String,
-    @SerialName(value = "content") val content: String,
-    @SerialName(value = "imageUrl") val imageUrl: String?
+    @SerializedName("title") val title: String,
+    @SerializedName("content") val content: String,
+    @SerializedName("imageUrl") val imageUrl: String?
 )
🧹 Nitpick comments (4)
app/src/main/java/com/example/kuit6_android_api/data/api/RetrofitClient.kt (1)

12-14: 로깅 레벨을 빌드 타입에 따라 조정하는 것을 고려하세요.

현재 HttpLoggingInterceptorBODY 레벨로 설정되어 있어 개발 중에는 유용하지만, 프로덕션 빌드에서는 민감한 정보가 로그에 노출될 수 있습니다.

빌드 타입에 따라 로깅 레벨을 조정하는 것을 권장합니다:

     private val loggingInterceptor = HttpLoggingInterceptor().apply {
-        level = HttpLoggingInterceptor.Level.BODY
+        level = if (BuildConfig.DEBUG) {
+            HttpLoggingInterceptor.Level.BODY
+        } else {
+            HttpLoggingInterceptor.Level.NONE
+        }
     }
app/src/main/java/com/example/kuit6_android_api/data/api/ApiService.kt (1)

21-22: 코드 스타일 개선: 어노테이션에서 불필요한 value 파라미터 제거

Retrofit 어노테이션에서 value 파라미터명은 생략 가능합니다. 더 간결한 코드를 위해 제거를 권장합니다.

다음과 같이 수정할 수 있습니다:

-    @GET(value = "/api/posts")
+    @GET("/api/posts")
     suspend fun getPosts(): BaseResponse<List<PostResponse>>
     
-    @POST(value = "/api/posts")
+    @POST("/api/posts")
     suspend fun createPost(
-        @Query(value = "author") author: String = "anonymous",
+        @Query("author") author: String = "anonymous",
         @Body request: PostCreateRequest
     ): BaseResponse<PostResponse>
     
-    @GET(value = "/api/posts/{id}")
+    @GET("/api/posts/{id}")
     suspend fun getDetail(
         @Path("id") id: Long
     ): BaseResponse<PostResponse>
     
-    @PUT(value = "/api/posts/{id}")
+    @PUT("/api/posts/{id}")
     suspend fun updatePost(
-        @Path(value = "id") id: Long,
+        @Path("id") id: Long,
         @Body request: PostCreateRequest
     ): BaseResponse<PostResponse>
     
-    @DELETE(value = "/api/posts/{id}")
+    @DELETE("/api/posts/{id}")
     suspend fun deletePost(
         @Path("id") id: Long
     ): BaseResponse<Unit>

Also applies to: 26-26, 33-33, 39-39, 46-46

app/src/main/java/com/example/kuit6_android_api/ui/post/viewmodel/PostViewModel.kt (2)

122-152: 파일 변환 로직의 에러 처리 개선 가능

uriToFile() 함수는 예외 발생 시 null을 반환하지만, 구체적인 에러 원인이 로그에만 출력됩니다. 더 나은 에러 전파를 위해 예외를 다시 던지는 것을 고려해보세요.

현재 구현은 동작하지만, 다음과 같이 개선할 수 있습니다:

-    private fun uriToFile(context: Context, uri: Uri): File? {
-        return try {
+    private fun uriToFile(context: Context, uri: Uri): File {
             val contentResolver = context.contentResolver
             val fileName = getFileName(context, uri) ?: "image_${System.currentTimeMillis()}.jpg"
             val tempFile = File(context.cacheDir, fileName)

             contentResolver.openInputStream(uri)?.use { input ->
                 FileOutputStream(tempFile).use { output ->
                     input.copyTo(output)
                 }
-            }
+            } ?: throw IllegalStateException("URI로부터 InputStream을 열 수 없습니다")
+            
             tempFile
-        } catch (e: Exception) {
-            e.printStackTrace()
-            null
-        }
     }

그리고 uploadImage() 함수의 Line 165에서:

-                val file = uriToFile(context, uri)
-                if (file == null) {
-                    throw Exception("파일 변환 실패")
-                }
+                val file = uriToFile(context, uri)

32-33: 로딩 상태 관리 추가

isUploading 상태를 이미지 업로드에만 사용하고 있습니다. 일관성을 위해 다른 API 작업(게시글 생성, 수정, 삭제)에도 유사한 로딩 상태 관리를 고려해보세요.

예시:

var isLoading by mutableStateOf(false)
    private set

그리고 각 API 호출 전후로 상태를 업데이트하면 UI에서 통합된 로딩 표시가 가능합니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd77f9d and 00583d0.

📒 Files selected for processing (16)
  • .idea/gradle.xml (1 hunks)
  • app/build.gradle.kts (4 hunks)
  • app/src/main/java/com/example/kuit6_android_api/MainActivity.kt (5 hunks)
  • app/src/main/java/com/example/kuit6_android_api/data/api/ApiService.kt (1 hunks)
  • app/src/main/java/com/example/kuit6_android_api/data/api/RetrofitClient.kt (1 hunks)
  • app/src/main/java/com/example/kuit6_android_api/data/model/Post.kt (0 hunks)
  • app/src/main/java/com/example/kuit6_android_api/data/model/request/PostCreateRequest.kt (1 hunks)
  • app/src/main/java/com/example/kuit6_android_api/data/model/response/AuthorResponse.kt (1 hunks)
  • app/src/main/java/com/example/kuit6_android_api/data/model/response/BaseResponse.kt (1 hunks)
  • app/src/main/java/com/example/kuit6_android_api/data/model/response/PostResponse.kt (1 hunks)
  • app/src/main/java/com/example/kuit6_android_api/ui/navigation/NavGraph.kt (5 hunks)
  • app/src/main/java/com/example/kuit6_android_api/ui/post/component/PostItem.kt (2 hunks)
  • app/src/main/java/com/example/kuit6_android_api/ui/post/screen/PostCreateScreen.kt (5 hunks)
  • app/src/main/java/com/example/kuit6_android_api/ui/post/screen/PostDetailScreen.kt (5 hunks)
  • app/src/main/java/com/example/kuit6_android_api/ui/post/screen/PostEditScreen.kt (6 hunks)
  • app/src/main/java/com/example/kuit6_android_api/ui/post/viewmodel/PostViewModel.kt (1 hunks)
💤 Files with no reviewable changes (1)
  • app/src/main/java/com/example/kuit6_android_api/data/model/Post.kt
🔇 Additional comments (7)
.idea/gradle.xml (1)

12-13: LGTM!

프로젝트 루트와 app 모듈에 대한 Gradle 설정이 올바르게 업데이트되었습니다.

app/build.gradle.kts (1)

88-92: LGTM!

Retrofit 및 OkHttp 관련 의존성이 올바르게 추가되었습니다. 다만 RetrofitClient.kt에서 사용 중인 Gson 컨버터와 데이터 모델의 kotlinx.serialization 어노테이션 간 불일치 문제는 별도 코멘트를 참고해주세요.

app/src/main/java/com/example/kuit6_android_api/ui/navigation/NavGraph.kt (2)

3-3: LGTM!

Snackbar 상태 관리를 위한 SnackbarHostState 파라미터가 올바르게 추가되었습니다. PR 목표(삭제 성공, 수정 성공 시 Snackbar 표시)를 달성하기 위한 적절한 구현입니다.

Also applies to: 18-18


45-46: LGTM!

snackBarState가 필요한 세 개의 화면(PostDetailScreen, PostCreateScreen, PostEditScreen)에 올바르게 전달되고 있습니다.

Also applies to: 57-58, 72-73

app/src/main/java/com/example/kuit6_android_api/data/api/RetrofitClient.kt (1)

16-21: LGTM!

OkHttpClient 설정이 적절합니다. 로깅 인터셉터와 타임아웃 설정이 합리적입니다.

app/src/main/java/com/example/kuit6_android_api/ui/post/viewmodel/PostViewModel.kt (1)

155-187: 이미지 업로드 함수가 잘 구현되었습니다

이 함수는 다른 API 호출과 달리 onFailure 블록을 포함하여 에러를 적절히 처리하고 있으며, isUploading 상태를 통해 로딩 상태도 관리하고 있습니다. 좋은 구현입니다.

app/src/main/java/com/example/kuit6_android_api/data/api/ApiService.kt (1)

27-29: 원본 리뷰 댓글이 부정확합니다.

Retrofit 인터페이스의 기본 파라미터 동작에 대한 우려는 타당한 지적이지만, 이 코드베이스에서는 실제 문제가 되지 않습니다. 모든 호출 지점에서 author 파라미터가 명시적으로 전달되므로 기본값이 필요하지 않습니다:

  • ApiService.kt:74 - apiService.createPost(author, request): author 항상 명시적 전달
  • PostViewModel.kt:65 - author: String: 필수 파라미터 (기본값 없음)
  • PostCreateScreen.kt:279-280 - finalAuthor 생성 후 명시적 전달

ApiService의 기본값 = "anonymous"는 방어적 조치일 뿐 실제로 사용되지 않으며, 코드는 정상 동작합니다.

Likely an incorrect or invalid review comment.

Comment on lines +23 to +29
val properties = Properties()
val localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
properties.load(localPropertiesFile.inputStream())
}
val baseUrl = properties.getProperty("BASE_URL")// ?: "http://10.0.2.2:8080/"
buildConfigField("String", "BASE_URL", "\"$baseUrl\"")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

BASE_URL null 안전성 문제를 해결해야 합니다.

local.propertiesBASE_URL 속성이 없으면 baseUrl이 null이 되어 빌드 에러가 발생합니다. 주석 처리된 기본값을 보아 fallback 값을 고려했던 것으로 보입니다.

다음과 같이 수정하여 null 안전성을 확보하세요:

         val properties = Properties()
         val localPropertiesFile = rootProject.file("local.properties")
         if (localPropertiesFile.exists()) {
             properties.load(localPropertiesFile.inputStream())
         }
-        val baseUrl = properties.getProperty("BASE_URL")// ?: "http://10.0.2.2:8080/"
+        val baseUrl = properties.getProperty("BASE_URL") ?: "http://10.0.2.2:8080/"
         buildConfigField("String", "BASE_URL", "\"$baseUrl\"")

또는 더 명확하게 에러를 발생시키려면:

-        val baseUrl = properties.getProperty("BASE_URL")// ?: "http://10.0.2.2:8080/"
+        val baseUrl = properties.getProperty("BASE_URL") 
+            ?: throw GradleException("BASE_URL not found in local.properties")
         buildConfigField("String", "BASE_URL", "\"$baseUrl\"")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val properties = Properties()
val localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
properties.load(localPropertiesFile.inputStream())
}
val baseUrl = properties.getProperty("BASE_URL")// ?: "http://10.0.2.2:8080/"
buildConfigField("String", "BASE_URL", "\"$baseUrl\"")
val properties = Properties()
val localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
properties.load(localPropertiesFile.inputStream())
}
val baseUrl = properties.getProperty("BASE_URL") ?: "http://10.0.2.2:8080/"
buildConfigField("String", "BASE_URL", "\"$baseUrl\"")
🤖 Prompt for AI Agents
In app/build.gradle.kts around lines 23 to 29, BASE_URL may be null when
local.properties lacks that key; update the code to ensure null-safety by
reading the property with a fallback or explicit error: obtain baseUrl =
properties.getProperty("BASE_URL") ?: "http://10.0.2.2:8080/" (or throw
IllegalStateException("BASE_URL not set in local.properties") if you prefer
failing fast) and then pass that non-null value into buildConfigField so the
build never receives a null BASE_URL.

Comment on lines +23 to +27
private val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

직렬화 라이브러리 불일치 문제를 해결해야 합니다.

GsonConverterFactory를 사용하고 있지만, 모든 데이터 모델(AuthorResponse, PostResponse, BaseResponse, PostCreateRequest)은 kotlinx.serialization@SerialName 어노테이션을 사용합니다. Gson은 @SerialName을 인식하지 못하므로 직렬화/역직렬화가 제대로 작동하지 않습니다.

해결 방법 1 (권장): kotlinx-serialization 컨버터 사용

build.gradle.kts에 의존성 추가:

implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")

RetrofitClient 수정:

 package com.example.kuit6_android_api.data.api
 
 import com.example.kuit6_android_api.BuildConfig
+import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
+import kotlinx.serialization.json.Json
+import okhttp3.MediaType.Companion.toMediaType
 import okhttp3.OkHttpClient
 import okhttp3.logging.HttpLoggingInterceptor
 import retrofit2.Retrofit
-import retrofit2.converter.gson.GsonConverterFactory
 import java.util.concurrent.TimeUnit
 
 object RetrofitClient {
 
+    private val json = Json {
+        ignoreUnknownKeys = true
+        coerceInputValues = true
+    }
+
     private val loggingInterceptor = HttpLoggingInterceptor().apply {
         level = HttpLoggingInterceptor.Level.BODY
     }
 
     private val okHttpClient = OkHttpClient.Builder()
         .addInterceptor(loggingInterceptor)
         .connectTimeout(30, TimeUnit.SECONDS)
         .readTimeout(30, TimeUnit.SECONDS)
         .writeTimeout(30, TimeUnit.SECONDS)
         .build()
 
     private val retrofit: Retrofit = Retrofit.Builder()
         .baseUrl(BuildConfig.BASE_URL)
         .client(okHttpClient)
-        .addConverterFactory(GsonConverterFactory.create())
+        .addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
         .build()
 
     val apiService: ApiService = retrofit.create(ApiService::class.java)
 }

그리고 모든 데이터 클래스에 @Serializable 어노테이션 추가 필요 (다른 파일 코멘트 참조)

해결 방법 2: 모든 데이터 모델을 Gson 어노테이션으로 변경

모든 데이터 모델의 @SerialName@SerializedName으로 변경 (다른 파일 코멘트 참조)

🤖 Prompt for AI Agents
In app/src/main/java/com/example/kuit6_android_api/data/api/RetrofitClient.kt
around lines 23 to 27, the Retrofit instance uses GsonConverterFactory while
your models use kotlinx.serialization @SerialName, causing incorrect
serialization; switch to the kotlinx-serialization converter by adding the
retrofit2-kotlinx-serialization-converter dependency to build.gradle.kts and
replace GsonConverterFactory.create() with the kotlinx serialization converter
configured with your Json instance, and ensure all data classes are annotated
with @Serializable; alternatively (less recommended) convert all @SerialName
annotations to Gson’s @SerializedName and keep GsonConverterFactory.

Comment on lines +5 to +9
data class AuthorResponse(
@SerialName(value = "id") val id: Long,
@SerialName(value = "username") val username: String,
@SerialName(value = "profileImageUrl") val profileImageUrl: String? // nullable
) No newline at end of file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

@serializable 어노테이션이 누락되었습니다.

kotlinx.serialization@SerialName을 사용하고 있지만, 데이터 클래스에 @Serializable 어노테이션이 없습니다. 그런데 RetrofitClient.kt에서 GsonConverterFactory를 사용하고 있어서, 현재 설정으로는 @SerialName 어노테이션이 무시됩니다.

다음 중 하나를 선택하여 수정해야 합니다:

  1. 권장: Retrofit 컨버터를 kotlinx-serialization-converter로 변경하고 모든 데이터 클래스에 @Serializable 추가
  2. @SerialName 대신 Gson의 @SerializedName 사용

해결 방법 1 (권장): kotlinx-serialization 사용

build.gradle.kts에 의존성 추가:

implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")

데이터 클래스 수정:

 package com.example.kuit6_android_api.data.model.response
 
 import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
 
+@Serializable
 data class AuthorResponse(
     @SerialName(value = "id") val id: Long,
     @SerialName(value = "username") val username: String,
     @SerialName(value = "profileImageUrl") val profileImageUrl: String?
 )

그리고 RetrofitClient.kt도 수정 필요 (별도 코멘트 참조)

해결 방법 2: Gson 사용

 package com.example.kuit6_android_api.data.model.response
 
-import kotlinx.serialization.SerialName
+import com.google.gson.annotations.SerializedName
 
 data class AuthorResponse(
-    @SerialName(value = "id") val id: Long,
-    @SerialName(value = "username") val username: String,
-    @SerialName(value = "profileImageUrl") val profileImageUrl: String?
+    @SerializedName("id") val id: Long,
+    @SerializedName("username") val username: String,
+    @SerializedName("profileImageUrl") val profileImageUrl: String?
 )
🤖 Prompt for AI Agents
In
app/src/main/java/com/example/kuit6_android_api/data/model/response/AuthorResponse.kt
around lines 5 to 9, the data class uses kotlinx.serialization's @SerialName but
is missing the required @Serializable annotation and the project currently uses
Gson via Retrofit, so @SerialName is being ignored; fix by either (recommended)
adding @Serializable to this data class and switching Retrofit to the
kotlinx-serialization converter (add the kotlin serialization converter and
kotlinx-serialization-json dependencies, update RetrofitClient to use the
KotlinxSerializationConverterFactory) or alternatively replace @SerialName with
Gson's @SerializedName and keep the current Gson converter; apply the same
choice consistently across all models and update imports accordingly.

Comment on lines +5 to +10
data class BaseResponse<T>(
@SerialName(value = "success") val success: Boolean,
@SerialName(value = "message") val message: String?,
@SerialName(value = "data") val data: T?, //nullable
@SerialName(value = "timestamp") val timestamp: String
) No newline at end of file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

@serializable 어노테이션이 누락되었습니다.

AuthorResponse.kt와 동일한 문제입니다. @SerialName을 사용하고 있지만 @Serializable 어노테이션이 없고, Retrofit에서는 Gson을 사용하고 있어 직렬화가 제대로 작동하지 않습니다.

kotlinx-serialization 사용 시:

 package com.example.kuit6_android_api.data.model.response
 
 import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
 
+@Serializable
 data class BaseResponse<T>(
     @SerialName(value = "success") val success: Boolean,
     @SerialName(value = "message") val message: String?,
     @SerialName(value = "data") val data: T?,
     @SerialName(value = "timestamp") val timestamp: String
 )

Gson 사용 시:

 package com.example.kuit6_android_api.data.model.response
 
-import kotlinx.serialization.SerialName
+import com.google.gson.annotations.SerializedName
 
 data class BaseResponse<T>(
-    @SerialName(value = "success") val success: Boolean,
-    @SerialName(value = "message") val message: String?,
-    @SerialName(value = "data") val data: T?,
-    @SerialName(value = "timestamp") val timestamp: String
+    @SerializedName("success") val success: Boolean,
+    @SerializedName("message") val message: String?,
+    @SerializedName("data") val data: T?,
+    @SerializedName("timestamp") val timestamp: String
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
data class BaseResponse<T>(
@SerialName(value = "success") val success: Boolean,
@SerialName(value = "message") val message: String?,
@SerialName(value = "data") val data: T?, //nullable
@SerialName(value = "timestamp") val timestamp: String
)
package com.example.kuit6_android_api.data.model.response
import com.google.gson.annotations.SerializedName
data class BaseResponse<T>(
@SerializedName("success") val success: Boolean,
@SerializedName("message") val message: String?,
@SerializedName("data") val data: T?, //nullable
@SerializedName("timestamp") val timestamp: String
)
Suggested change
data class BaseResponse<T>(
@SerialName(value = "success") val success: Boolean,
@SerialName(value = "message") val message: String?,
@SerialName(value = "data") val data: T?, //nullable
@SerialName(value = "timestamp") val timestamp: String
)
package com.example.kuit6_android_api.data.model.response
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class BaseResponse<T>(
@SerialName(value = "success") val success: Boolean,
@SerialName(value = "message") val message: String?,
@SerialName(value = "data") val data: T?, //nullable
@SerialName(value = "timestamp") val timestamp: String
)
🤖 Prompt for AI Agents
In
app/src/main/java/com/example/kuit6_android_api/data/model/response/BaseResponse.kt
around lines 5-10, the data class uses @SerialName but is missing the
@Serializable annotation; add @Serializable above the data class and import
kotlinx.serialization.Serializable so kotlinx-serialization can process the
SerialName annotations (alternatively, if the project uses Gson/Retrofit,
replace @SerialName with Gson's @SerializedName and remove @Serializable to
match the Gson serializer).

Comment on lines +279 to 290
val finalAuthor = author//.ifBlank { "anonymous" }
viewModel.createPost(
finalAuthor,
title,
content,
imageUrl = viewModel.uploadedImageUrl
) {
onPostCreated()
// ViewModel 에서 멘트를 받아서 전달하는 식으로 많이 구성. flow 활용
// 현재: onSuccess 람다로 넣어주는 식으로 구현
scope.launch { snackBarState.showSnackbar("게시글이 작성되었습니다.") }
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

성공 스낵바가 네비게이션과 함께 사라집니다.

Line 286에서 onPostCreated()로 화면을 종료한 뒤, 동일 컴포저블의 rememberCoroutineScope()로 스낵바를 띄우고 있습니다. 화면이 pop되면 해당 scope가 즉시 cancel되어 스낵바가 표시되지 않으므로 미션 요구사항을 충족하지 못합니다. MainActivity 수준에서 유지되는 scope나 suspend (String) -> Unit 콜백을 내려받아 네비게이션 전에 호출하거나, 이전 화면(savedStateHandle 등)에서 스낵바를 처리하도록 리팩터링해 주세요.

🤖 Prompt for AI Agents
In
app/src/main/java/com/example/kuit6_android_api/ui/post/screen/PostCreateScreen.kt
around lines 279 to 290, the success snackbar is launched from the composable's
rememberCoroutineScope after calling onPostCreated(), but the composable's scope
is cancelled when the screen is popped so the snackbar never appears; fix by
moving snackbar emission out of the composable-local scope or firing it before
navigation: either (a) call snackBarState.showSnackbar(...) (suspending) before
invoking onPostCreated(), (b) accept a suspend (String) -> Unit successSnackbar
callback from the caller (MainActivity/host) and invoke that before popping, or
(c) have the destination write a message into savedStateHandle
(previousBackStackEntry) / ViewModel which the previous screen or MainActivity
observes and shows the snackbar from a lifecycle-safe, long-lived scope.

Comment on lines 36 to 48
fun getPosts() {
viewModelScope.launch {
delay(500) // 네트워크 시뮬레이션
posts = dummyPosts.toList()
runCatching {
apiService.getPosts()
}.onSuccess { response ->
response.data?.let {
if (response.success) {
posts = response.data
}
}
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

에러 처리 누락으로 인한 사용자 경험 저하

getPosts() 함수에서 API 호출 실패 시 에러를 처리하지 않아 사용자에게 피드백이 제공되지 않습니다. 네트워크 오류나 서버 에러 발생 시 사용자는 아무런 알림 없이 빈 목록만 보게 됩니다.

다음과 같이 에러 처리를 추가하세요:

     fun getPosts() {
         viewModelScope.launch {
             runCatching {
                 apiService.getPosts()
             }.onSuccess { response ->
                 response.data?.let {
                     if (response.success) {
                         posts = response.data
                     }
                 }
+            }.onFailure { error ->
+                // 에러 상태를 UI에 전달하거나 로깅
+                error.printStackTrace()
             }
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fun getPosts() {
viewModelScope.launch {
delay(500) // 네트워크 시뮬레이션
posts = dummyPosts.toList()
runCatching {
apiService.getPosts()
}.onSuccess { response ->
response.data?.let {
if (response.success) {
posts = response.data
}
}
}
}
}
fun getPosts() {
viewModelScope.launch {
runCatching {
apiService.getPosts()
}.onSuccess { response ->
response.data?.let {
if (response.success) {
posts = response.data
}
}
}.onFailure { error ->
// 에러 상태를 UI에 전달하거나 로깅
error.printStackTrace()
}
}
}
🤖 Prompt for AI Agents
In
app/src/main/java/com/example/kuit6_android_api/ui/post/viewmodel/PostViewModel.kt
around lines 36 to 48, getPosts() currently ignores failures from the API call;
add error handling to improve UX by handling runCatching failures and updating
observable state. Specifically, add an onFailure block to runCatching to capture
the exception, set an error LiveData/StateFlow (or update a UI-visible
error/message property) and/or clear/loading state appropriately, and optionally
log the exception; ensure you also handle non-success responses inside onSuccess
by setting an error state when response.success is false so the UI can show a
message or retry option.

Comment on lines 50 to 62
fun getPostDetail(postId: Long) {
viewModelScope.launch {
delay(300)
postDetail = dummyPosts.find { it.id == postId }
runCatching {
apiService.getDetail(postId)
}.onSuccess { response ->
response.data?.let {
if (response.success) {
postDetail = response.data
}
}
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

에러 처리 누락으로 인한 사용자 경험 저하

getPostDetail() 함수에서도 API 호출 실패 시 에러를 처리하지 않아 사용자가 문제를 인지할 수 없습니다.

다음과 같이 에러 처리를 추가하세요:

     fun getPostDetail(postId: Long) {
         viewModelScope.launch {
             runCatching {
                 apiService.getDetail(postId)
             }.onSuccess { response ->
                 response.data?.let {
                     if (response.success) {
                         postDetail = response.data
                     }
                 }
+            }.onFailure { error ->
+                error.printStackTrace()
             }
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fun getPostDetail(postId: Long) {
viewModelScope.launch {
delay(300)
postDetail = dummyPosts.find { it.id == postId }
runCatching {
apiService.getDetail(postId)
}.onSuccess { response ->
response.data?.let {
if (response.success) {
postDetail = response.data
}
}
}
}
}
fun getPostDetail(postId: Long) {
viewModelScope.launch {
runCatching {
apiService.getDetail(postId)
}.onSuccess { response ->
response.data?.let {
if (response.success) {
postDetail = response.data
}
}
}.onFailure { error ->
error.printStackTrace()
}
}
}
🤖 Prompt for AI Agents
In
app/src/main/java/com/example/kuit6_android_api/ui/post/viewmodel/PostViewModel.kt
around lines 50-62, the getPostDetail() call uses runCatching but lacks error
handling; add an onFailure block to runCatching to capture the throwable and
handle API failures, and also handle the case when response.success is false by
setting an error state. Specifically, in onFailure { throwable -> ... } log the
error (e.g., Timber/Log) and update a ViewModel-exposed observable error holder
(LiveData/StateFlow/Event) so the UI can show an error message; also change the
onSuccess branch to set the error state when response.success is false (with an
appropriate message) instead of silently ignoring it.

Comment on lines 64 to 83
fun createPost(
author: String = "anonymous",
author: String,// = "anonymous",
title: String,
content: String,
imageUrl: String? = null,
imageUrl: String? = uploadedImageUrl,
onSuccess: () -> Unit = {}
) {
viewModelScope.launch {
delay(500)
val newPost = Post(
id = nextId++,
title = title,
content = content,
imageUrl = imageUrl,
author = Author(nextId, author, null),
createdAt = getCurrentDateTime(),
updatedAt = getCurrentDateTime()
)
dummyPosts.add(0, newPost)
posts = dummyPosts.toList()
onSuccess()
runCatching {
val request = PostCreateRequest(title, content, imageUrl)
apiService.createPost(author, request)
}.onSuccess { response ->
if (response.success) {
// 이미지 업로드 관련 코드
clearUploadedImageUrl()
onSuccess()
}
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

기본 파라미터 값이 예상과 다르게 동작할 수 있음

Line 68의 imageUrl: String? = uploadedImageUrl는 함수 호출 시점이 아닌 파라미터 선언 시점의 uploadedImageUrl 값을 캡처합니다. 이는 의도한 동작이 아닐 가능성이 높습니다. 또한 에러 처리가 누락되어 있습니다.

다음과 같이 수정하세요:

     fun createPost(
         author: String,
         title: String,
         content: String,
-        imageUrl: String? = uploadedImageUrl,
+        imageUrl: String? = null,
         onSuccess: () -> Unit = {}
     ) {
         viewModelScope.launch {
             runCatching {
-                val request = PostCreateRequest(title, content, imageUrl)
+                val request = PostCreateRequest(title, content, imageUrl ?: uploadedImageUrl)
                 apiService.createPost(author, request)
             }.onSuccess { response ->
                 if (response.success) {
                     clearUploadedImageUrl()
                     onSuccess()
                 }
+            }.onFailure { error ->
+                error.printStackTrace()
             }
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fun createPost(
author: String = "anonymous",
author: String,// = "anonymous",
title: String,
content: String,
imageUrl: String? = null,
imageUrl: String? = uploadedImageUrl,
onSuccess: () -> Unit = {}
) {
viewModelScope.launch {
delay(500)
val newPost = Post(
id = nextId++,
title = title,
content = content,
imageUrl = imageUrl,
author = Author(nextId, author, null),
createdAt = getCurrentDateTime(),
updatedAt = getCurrentDateTime()
)
dummyPosts.add(0, newPost)
posts = dummyPosts.toList()
onSuccess()
runCatching {
val request = PostCreateRequest(title, content, imageUrl)
apiService.createPost(author, request)
}.onSuccess { response ->
if (response.success) {
// 이미지 업로드 관련 코드
clearUploadedImageUrl()
onSuccess()
}
}
}
}
fun createPost(
author: String,// = "anonymous",
title: String,
content: String,
imageUrl: String? = null,
onSuccess: () -> Unit = {}
) {
viewModelScope.launch {
runCatching {
val request = PostCreateRequest(title, content, imageUrl ?: uploadedImageUrl)
apiService.createPost(author, request)
}.onSuccess { response ->
if (response.success) {
// 이미지 업로드 관련 코드
clearUploadedImageUrl()
onSuccess()
}
}.onFailure { error ->
error.printStackTrace()
}
}
}
🤖 Prompt for AI Agents
In
app/src/main/java/com/example/kuit6_android_api/ui/post/viewmodel/PostViewModel.kt
around lines 64 to 83, the parameter default imageUrl: String? =
uploadedImageUrl captures uploadedImageUrl at declaration time (not call time)
and there is no error handling; change the signature to accept imageUrl: String?
= null and inside the function compute val finalImageUrl = imageUrl ?:
uploadedImageUrl, use finalImageUrl when building the request, and add
runCatching.onFailure { /* log or notify error */ } and handle non-success
responses (else branch) to clear the uploaded image only on success and report
or log errors appropriately.

Comment on lines 85 to 104
fun updatePost(
postId: Long,
title: String,
content: String,
imageUrl: String? = null,
imageUrl: String?,
onSuccess: () -> Unit = {}
) {
// 수정 후 게시글 상세가 나오게
viewModelScope.launch {
delay(500)
val index = dummyPosts.indexOfFirst { it.id == postId }
if (index != -1) {
val oldPost = dummyPosts[index]
val updatedPost = oldPost.copy(
title = title,
content = content,
imageUrl = imageUrl,
updatedAt = getCurrentDateTime()
)
dummyPosts[index] = updatedPost
postDetail = updatedPost
posts = dummyPosts.toList()
onSuccess()
runCatching {
val request = PostCreateRequest(title, content, imageUrl)
apiService.updatePost(postId, request)
}.onSuccess { response ->
if (response.success && response.data != null) {
postDetail = response.data
onSuccess()
}
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

에러 처리 추가 필요 (수정 기능 관련)

게시글 수정 성공 시 onSuccess 콜백이 호출되어 스낵바가 표시될 것으로 보입니다 (6주차 미션). 하지만 실패 시 사용자에게 피드백이 제공되지 않습니다.

다음과 같이 에러 처리를 추가하세요:

     fun updatePost(
         postId: Long,
         title: String,
         content: String,
         imageUrl: String?,
         onSuccess: () -> Unit = {}
     ) {
         viewModelScope.launch {
             runCatching {
                 val request = PostCreateRequest(title, content, imageUrl)
                 apiService.updatePost(postId, request)
             }.onSuccess { response ->
                 if (response.success && response.data != null) {
                     postDetail = response.data
                     onSuccess()
                 }
+            }.onFailure { error ->
+                error.printStackTrace()
+                // UI에 에러 전달 필요
             }
         }
     }
🤖 Prompt for AI Agents
In
app/src/main/java/com/example/kuit6_android_api/ui/post/viewmodel/PostViewModel.kt
around lines 85-104, the updatePost function only handles success and provides
no user feedback on failure; add error handling by using runCatching().onFailure
{ ... } to catch network/exception errors and handle responses where
response.success is false by invoking a provided error callback or setting an
error LiveData/StateFlow (e.g., errorMessage) so the UI can show a
Snackbar/Toast; ensure you propagate meaningful error text (exception.message or
response.message) to the UI and call onSuccess only on true success.

Comment on lines 106 to +119
fun deletePost(postId: Long, onSuccess: () -> Unit = {}) {
// 삭제 후 게시글 목록 나오게
viewModelScope.launch {
runCatching {
apiService.deletePost(postId)
}.onSuccess { response ->
if (response.success) {
postDetail = null
getPosts()
onSuccess()
}
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

에러 처리 추가 필요 (삭제 기능 관련)

게시글 삭제 성공 시 onSuccess 콜백이 호출되어 스낵바가 표시될 것으로 보입니다 (6주차 미션). 하지만 실패 시 사용자에게 피드백이 제공되지 않습니다.

다음과 같이 에러 처리를 추가하세요:

     fun deletePost(postId: Long, onSuccess: () -> Unit = {}) {
         viewModelScope.launch {
             runCatching {
                 apiService.deletePost(postId)
             }.onSuccess { response ->
                 if (response.success) {
                     postDetail = null
                     getPosts()
                     onSuccess()
                 }
+            }.onFailure { error ->
+                error.printStackTrace()
+                // UI에 에러 전달 필요
             }
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fun deletePost(postId: Long, onSuccess: () -> Unit = {}) {
// 삭제 후 게시글 목록 나오게
viewModelScope.launch {
runCatching {
apiService.deletePost(postId)
}.onSuccess { response ->
if (response.success) {
postDetail = null
getPosts()
onSuccess()
}
}
}
}
fun deletePost(postId: Long, onSuccess: () -> Unit = {}) {
// 삭제 후 게시글 목록 나오게
viewModelScope.launch {
runCatching {
apiService.deletePost(postId)
}.onSuccess { response ->
if (response.success) {
postDetail = null
getPosts()
onSuccess()
}
}.onFailure { error ->
error.printStackTrace()
// UI에 에러 전달 필요
}
}
}
🤖 Prompt for AI Agents
In
app/src/main/java/com/example/kuit6_android_api/ui/post/viewmodel/PostViewModel.kt
around lines 106 to 119, the deletePost function only handles the success path
and provides no feedback on failure; add proper error handling by extending the
function to accept an optional onError callback (e.g., onError: (String) -> Unit
= {}) or use an existing LiveData/Event to surface errors, check the response
when response.success is false and call onError with a meaningful message, and
add a .onFailure block on the runCatching to capture exceptions and call onError
with the exception message so the UI can show a snackbar or error state.

@rbqks529 rbqks529 merged commit cf712a2 into Konkuk-KUIT:AyoungSe0 Nov 11, 2025
1 check passed
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.

3 participants