Feature/#69 home api response model - #73
Conversation
- 홈 화면 구성에 필요한 api 응답 model 추가
- 홈 화면 구성에 필요한 api 응답 model을 UI 데이터 Model로 변환하는 함수 추가
개요이 PR은 학적 기록(AcademicRecord), 학적 요약(AcademicSummary), 졸업 프로세스(GraduationProcess), 프로필(Profile), 학기 정보(Semester)에 대한 도메인 모델과 API 응답 DTO를 추가합니다. 각 API 응답 모델은 도메인 모델로 변환하기 위한 매퍼 메서드를 포함합니다. 변경 사항
예상 코드 리뷰 노력🎯 3 (Moderate) | ⏱️ ~25 분 관련 가능성 있는 이슈
시
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/academic/AcademicRecord.kt`:
- Around line 24-56: Replace the duplicated Major and Liberal models with a
single shared data class named Course that contains the common fields (areaType,
courseCode, courseName, credits, grade, id, isOnline, isRetake, isRetakeDelete,
originalScore, professor, score, semester, year), then update the file to either
typealias Major = Course and typealias Liberal = Course or change usages to
List<Course> (and adjust any callers expecting Major/Liberal accordingly) so
only one canonical model holds the fields and lists distinguish the roles.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicRecordResponse.kt`:
- Around line 9-13: AcademicRecordResponse에 루트 수준 변환 진입점을 추가해 호출 패턴을 일관화하세요:
AcademicRecordResponse 클래스(또는 확장 함수)에 toAcademicRecord() 메서드를 추가하여 내부적으로 현재의
AcademicRecordResponseData.toAcademicRecord()를 호출하고 필요한 메타(success/message)가 있다면
함께 매핑하도록 위임하도록 구현하세요; 이렇게 하면 기존 호출자들이 data.toAcademicRecord() 대신
AcademicRecordResponse.toAcademicRecord()를 사용하도록 변경할 수 있습니다.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicSummaryResponse.kt`:
- Around line 5-9: AcademicSummaryResponse 및 그 내부 데이터 클래스
AcademicSummaryResponseData에 kotlinx.serialization용 `@Serializable` 어노테이션을 추가하세요:
파일의 data class AcademicSummaryResponse과 해당 AcademicSummaryResponseData 선언 위에 각각
`@Serializable을` 붙여 JSON 역직렬화가 가능하도록 하고, 다른 모델(OpenLecture, Timetable 등)과 동일한 직렬화
규칙을 따르도록 만드세요.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/graduation/GraduationProcessResponse.kt`:
- Around line 6-10: The GraduationProcessResponse declaration uses 4-space
indentation while the rest of the file uses 2-space indentation; update the
class block so each property line (data: GraduationProcessResponseData, message:
String, success: Boolean) and the closing parenthesis are indented with 2 spaces
to match the project's style and other classes in this file (look for the
GraduationProcessResponse class and its properties to adjust).
- Around line 6-51: Add kotlinx.serialization support by annotating each
response model with `@Serializable`: GraduationProcessResponse,
GraduationProcessResponseData, GraduationProgressData, and
GraduationProcessCourseData; also add the import for
kotlinx.serialization.Serializable where these classes are declared so the JSON
(de)serializer can recognize and parse instances of these classes at runtime.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/profile/ProfileResponse.kt`:
- Around line 23-31: toProfile() currently omits lastUpdatedAt, lastSyncedAt,
and reconnectionRequired from the Profile conversion; update the toProfile()
function to map these fields into the Profile constructor (e.g., lastUpdatedAt =
lastUpdatedAt, lastSyncedAt = lastSyncedAt, reconnectionRequired =
reconnectionRequired), handling any nullable/format conversions required to
match Profile's property types and preserving existing behavior for defaults if
fields are absent.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/semester/SemesterGradesListResponse.kt`:
- Around line 11-13: toSemesterGradesList currently converts response->model
without verifying the response succeeded, allowing error responses to flow to
the UI; update the toSemesterGradesList function to first check the response's
success boolean (the success property on this response) and if it's false stop
conversion—e.g. throw an IllegalStateException (or return null/Result as your
codebase prefers) instead of mapping data; reference the toSemesterGradesList
function, the success property, data collection and the target
SemesterGradesList model when making the change.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/semester/SemesterListResponse.kt`:
- Around line 11-13: toSemesterList() currently ignores response success/message
and always maps data to a SemesterList, risking propagation of failure
responses; update the toSemesterList() implementation to check the response's
success (and/or message) first and only map data when success is true—otherwise
return a nullable (SemesterList?) or a Result/Failure (or throw) to make the
contract explicit; reference the toSemesterList() function, the SemesterList
type, and the response properties (data, success, message) and update callers
accordingly to handle the nullable/Result/exception return.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/semester/SemesterList.kt`:
- Around line 3-7: The common model currently depends on the presentation type
Semester; create an independent domain model data class Semester in package
com.chukchukhaksa.mobile.common.model.semester and update the existing
SemesterList data class to use that new Semester type instead of
com.chukchukhaksa.mobile.presentation.timetable.semesterselect.Semester; ensure
imports are adjusted and presentation-layer Semester is only mapped to/from the
common.model.semester.Semester at the UI boundary (e.g., via a mapper).
ℹ️ Review info
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (12)
composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/academic/AcademicRecord.ktcomposeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/academic/AcademicSummary.ktcomposeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/graduation/GraduationProcess.ktcomposeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/profile/Profile.ktcomposeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicRecordResponse.ktcomposeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicSummaryResponse.ktcomposeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/graduation/GraduationProcessResponse.ktcomposeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/profile/ProfileResponse.ktcomposeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/semester/SemesterGradesListResponse.ktcomposeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/semester/SemesterListResponse.ktcomposeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/semester/SemesterGradesList.ktcomposeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/semester/SemesterList.kt
| data class Major( | ||
| val areaType: String, | ||
| val courseCode: String, | ||
| val courseName: String, | ||
| val credits: Int, | ||
| val grade: String, | ||
| val id: String, | ||
| val isOnline: Boolean, | ||
| val isRetake: Boolean, | ||
| val isRetakeDelete: Boolean, | ||
| val originalScore: Int, | ||
| val professor: String, | ||
| val score: Int, | ||
| val semester: Int, | ||
| val year: Int | ||
| ) | ||
|
|
||
| data class Liberal( | ||
| val areaType: String, | ||
| val courseCode: String, | ||
| val courseName: String, | ||
| val credits: Int, | ||
| val grade: String, | ||
| val id: String, | ||
| val isOnline: Boolean, | ||
| val isRetake: Boolean, | ||
| val isRetakeDelete: Boolean, | ||
| val originalScore: Int, | ||
| val professor: String, | ||
| val score: Int, | ||
| val semester: Int, | ||
| val year: Int | ||
| ) |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Major/Liberal 모델 중복을 줄이는 리팩터링이 필요합니다.
Line 24-56은 필드가 100% 동일해서 변경 누락 위험이 큽니다. 공통 Course 모델로 통합하고 리스트만 구분하는 구조가 유지보수에 유리합니다.
♻️ 구조 단순화 예시
data class AcademicRecordCourses(
- val liberal: List<Liberal>,
- val major: List<Major>
+ val liberal: List<Course>,
+ val major: List<Course>
)
-data class Major(
+data class Course(
val areaType: String,
val courseCode: String,
val courseName: String,
val credits: Int,
val grade: String,
val id: String,
val isOnline: Boolean,
val isRetake: Boolean,
val isRetakeDelete: Boolean,
val originalScore: Int,
val professor: String,
val score: Int,
val semester: Int,
val year: Int
)
-
-data class Liberal(
- ...
-)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/academic/AcademicRecord.kt`
around lines 24 - 56, Replace the duplicated Major and Liberal models with a
single shared data class named Course that contains the common fields (areaType,
courseCode, courseName, credits, grade, id, isOnline, isRetake, isRetakeDelete,
originalScore, professor, score, semester, year), then update the file to either
typealias Major = Course and typealias Liberal = Course or change usages to
List<Course> (and adjust any callers expecting Major/Liberal accordingly) so
only one canonical model holds the fields and lists distinguish the roles.
| data class AcademicRecordResponse( | ||
| val data: AcademicRecordResponseData, | ||
| val message: String, | ||
| val success: Boolean | ||
| ) |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
응답 모델 변환 진입점을 루트에도 맞춰주는 것이 좋습니다.
현재는 data.toAcademicRecord()만 가능해서 호출 패턴이 분산됩니다. 루트(AcademicRecordResponse)에 변환 함수를 추가하면 사용성이 일관됩니다.
🔧 제안 수정안
data class AcademicRecordResponse(
val data: AcademicRecordResponseData,
val message: String,
val success: Boolean
-)
+) {
+ fun toAcademicRecord() = data.toAcademicRecord()
+}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicRecordResponse.kt`
around lines 9 - 13, AcademicRecordResponse에 루트 수준 변환 진입점을 추가해 호출 패턴을 일관화하세요:
AcademicRecordResponse 클래스(또는 확장 함수)에 toAcademicRecord() 메서드를 추가하여 내부적으로 현재의
AcademicRecordResponseData.toAcademicRecord()를 호출하고 필요한 메타(success/message)가 있다면
함께 매핑하도록 위임하도록 구현하세요; 이렇게 하면 기존 호출자들이 data.toAcademicRecord() 대신
AcademicRecordResponse.toAcademicRecord()를 사용하도록 변경할 수 있습니다.
| data class AcademicSummaryResponse( | ||
| val data: AcademicSummaryResponseData, | ||
| val message: String, | ||
| val success: Boolean | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Search for `@Serializable` usage in Response models
echo "=== Checking for `@Serializable` in Response models ==="
rg -n "@Serializable" --type=kt composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile -A 2 | head -50
# Check other Response models in the same academic directory
echo -e "\n=== Response models in academic directory ==="
fd "Response\.kt$" composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/
# Check general Response model directory
echo -e "\n=== Response files in response directory ==="
find composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response -name "*.kt" -type f | head -20Repository: cchaksa/cchaksa-app
Length of output: 1174
🏁 Script executed:
# Let's examine a few Response model files to understand the pattern
echo "=== Examining AcademicSummaryResponse ==="
cat -n composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicSummaryResponse.kt
echo -e "\n=== Examining AcademicSummaryResponseData ==="
fd "AcademicSummaryResponseData\.kt$" -x cat -nRepository: cchaksa/cchaksa-app
Length of output: 944
🏁 Script executed:
# Check if there's a serialization configuration file or setup
echo "=== Checking for serialization setup ==="
rg -n "kotlinx.serialization|Json|Serializable" --type=kt composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response -A 1 | head -40Repository: cchaksa/cchaksa-app
Length of output: 147
🏁 Script executed:
# Examine other Response models
echo "=== ProfileResponse ==="
cat -n composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/profile/ProfileResponse.kt
echo -e "\n=== SemesterListResponse ==="
cat -n composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/semester/SemesterListResponse.kt
echo -e "\n=== AcademicRecordResponse ==="
cat -n composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicRecordResponse.ktRepository: cchaksa/cchaksa-app
Length of output: 5817
🏁 Script executed:
# Check for serialization library setup in build files
echo "=== Checking gradle for serialization ==="
find composeApp -name "build.gradle*" -o -name "*.gradle.kts" | xargs grep -l "serialization\|json" 2>/dev/null | head -5
# Check where API responses are deserialized
echo -e "\n=== Searching for Json parsing/deserialization logic ==="
rg "Json\.|Json\.decode\|parseJson\|fromJson" --type-add="kt:*.kt" composeApp/src/commonMain/kotlin -A 2 | head -50Repository: cchaksa/cchaksa-app
Length of output: 5412
🏁 Script executed:
# Check for HTTP client usage and serialization
echo "=== Checking for HTTP client setup ==="
rg "HttpClient\|Ktor\|Retrofit" --type-add="kt:*.kt" composeApp/src/commonMain/kotlin -B 1 -A 1 | head -40Repository: cchaksa/cchaksa-app
Length of output: 101
🏁 Script executed:
# Check the build.gradle.kts for serialization configuration
cat -n composeApp/build.gradle.kts | head -100Repository: cchaksa/cchaksa-app
Length of output: 3981
🏁 Script executed:
# Check if there's a custom Json setup that might handle serialization without `@Serializable`
echo "=== Checking common Json configuration ==="
cat -n composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/ui/Json.kt
# Check for `@Serializable` in common/ui directory
echo -e "\n=== Checking for `@Serializable` setup ==="
find composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common -name "*.kt" | xargs grep -l "@Serializable" | head -10Repository: cchaksa/cchaksa-app
Length of output: 1590
🏁 Script executed:
# Check how API responses are deserialized - look for HTTP client/API service
echo "=== Searching for API service or HTTP client configuration ==="
fd "Api.kt|Service.kt|Client.kt" composeApp/src/commonMain/kotlin -x cat -n
echo -e "\n=== Checking for Ktor HTTP client ==="
rg "HttpClient|createHttpClient|httpClient" --type-add="kt:*.kt" composeApp/src/commonMain -B 2 -A 5 | head -60Repository: cchaksa/cchaksa-app
Length of output: 850
🏁 Script executed:
# Check one of the models that has `@Serializable` to see the pattern
echo "=== Checking OpenLecture.kt with `@Serializable` ==="
cat -n composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/OpenLecture.kt
echo -e "\n=== Checking Timetable.kt with `@Serializable` ==="
head -20 composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/Timetable.ktRepository: cchaksa/cchaksa-app
Length of output: 1328
Response 모델에 @Serializable 어노테이션이 누락되었습니다.
이 프로젝트는 kotlinx.serialization을 사용하며, API 응답을 JSON에서 역직렬화하려면 @Serializable 어노테이션이 필요합니다. OpenLecture, Timetable 등 다른 직렬화 대상 모델들은 모두 이 어노테이션을 포함하고 있으므로, AcademicSummaryResponse와 AcademicSummaryResponseData도 추가해야 합니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicSummaryResponse.kt`
around lines 5 - 9, AcademicSummaryResponse 및 그 내부 데이터 클래스
AcademicSummaryResponseData에 kotlinx.serialization용 `@Serializable` 어노테이션을 추가하세요:
파일의 data class AcademicSummaryResponse과 해당 AcademicSummaryResponseData 선언 위에 각각
`@Serializable을` 붙여 JSON 역직렬화가 가능하도록 하고, 다른 모델(OpenLecture, Timetable 등)과 동일한 직렬화
규칙을 따르도록 만드세요.
| data class GraduationProcessResponse( | ||
| val data: GraduationProcessResponseData, | ||
| val message: String, | ||
| val success: Boolean | ||
| ) |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
들여쓰기 불일치
GraduationProcessResponse 클래스는 4칸 들여쓰기를 사용하고 있지만, 파일 내 다른 클래스들은 2칸 들여쓰기를 사용하고 있습니다. 일관성을 위해 통일해 주세요.
♻️ 들여쓰기 수정 제안
data class GraduationProcessResponse(
- val data: GraduationProcessResponseData,
- val message: String,
- val success: Boolean
+ val data: GraduationProcessResponseData,
+ val message: String,
+ val success: Boolean
)📝 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.
| data class GraduationProcessResponse( | |
| val data: GraduationProcessResponseData, | |
| val message: String, | |
| val success: Boolean | |
| ) | |
| data class GraduationProcessResponse( | |
| val data: GraduationProcessResponseData, | |
| val message: String, | |
| val success: Boolean | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/graduation/GraduationProcessResponse.kt`
around lines 6 - 10, The GraduationProcessResponse declaration uses 4-space
indentation while the rest of the file uses 2-space indentation; update the
class block so each property line (data: GraduationProcessResponseData, message:
String, success: Boolean) and the closing parenthesis are indented with 2 spaces
to match the project's style and other classes in this file (look for the
GraduationProcessResponse class and its properties to adjust).
| data class GraduationProcessResponse( | ||
| val data: GraduationProcessResponseData, | ||
| val message: String, | ||
| val success: Boolean | ||
| ) | ||
|
|
||
| data class GraduationProcessResponseData( | ||
| val graduationProgress: List<GraduationProgressData>, | ||
| val hasDifferentGraduationRequirement: Boolean | ||
| ) | ||
|
|
||
| data class GraduationProgressData( | ||
| val areaType: String, | ||
| val completedElectiveCourses: Int, | ||
| val courses: List<GraduationProcessCourseData>, | ||
| val earnedCredits: Int, | ||
| val requiredCredits: Int, | ||
| val requiredElectiveCourses: Int, | ||
| val totalElectiveCourses: Int | ||
| ) { | ||
| fun toGraduationProcess() = GraduationProcess( | ||
| areaType = areaType, | ||
| completedElectiveCourses = completedElectiveCourses, | ||
| courses = courses.map { it.toGraduationProcessCourse() }, | ||
| earnedCredits = earnedCredits, | ||
| requiredCredits = requiredCredits, | ||
| requiredElectiveCourses = requiredElectiveCourses, | ||
| totalElectiveCourses = totalElectiveCourses, | ||
| ) | ||
| } | ||
|
|
||
| data class GraduationProcessCourseData( | ||
| val courseName: String, | ||
| val credits: Int, | ||
| val grade: String, | ||
| val semester: Int, | ||
| val year: Int | ||
| ) { | ||
| fun toGraduationProcessCourse() = GraduationProcessCourse( | ||
| courseName = courseName, | ||
| credits = credits, | ||
| grade = grade, | ||
| semester = semester, | ||
| year = year, | ||
| ) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's check the full content of the file in question
cat -n "composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/graduation/GraduationProcessResponse.kt"Repository: cchaksa/cchaksa-app
Length of output: 1905
🏁 Script executed:
# Search for `@Serializable` annotations in other response models
rg -l "@Serializable" --type=kotlin "composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/" | head -20Repository: cchaksa/cchaksa-app
Length of output: 799
🏁 Script executed:
# Check for other response model patterns
fd "Response\.kt$" "composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/" | head -10Repository: cchaksa/cchaksa-app
Length of output: 752
🏁 Script executed:
# Check for serialization library setup in build files
fd "build\.gradle|build\.gradle\.kts" | xargs grep -l "serialization\|gson\|moshi" 2>/dev/nullRepository: cchaksa/cchaksa-app
Length of output: 90
🏁 Script executed:
# Search for actual serialization annotations in the project
rg "@Serializable|@SerializedName|@Json" --type=kotlin "composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/" | head -20Repository: cchaksa/cchaksa-app
Length of output: 1134
🏁 Script executed:
# Check if other response models have `@Serializable` annotations
cat -n "composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/profile/ProfileResponse.kt" 2>/dev/null | head -30Repository: cchaksa/cchaksa-app
Length of output: 1044
🏁 Script executed:
# Check another response model
cat -n "composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/academic/AcademicRecordResponse.kt" 2>/dev/null | head -30Repository: cchaksa/cchaksa-app
Length of output: 1286
🏁 Script executed:
# Check build.gradle.kts for serialization setup
grep -A5 -B5 "serialization\|kotlinx" "composeApp/build.gradle.kts" | head -50Repository: cchaksa/cchaksa-app
Length of output: 881
🏁 Script executed:
# Check if any response models use `@Serializable`
rg "@Serializable" --type=kotlin "composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/"Repository: cchaksa/cchaksa-app
Length of output: 45
직렬화 어노테이션 추가 필요
API 응답 모델에서 @Serializable 어노테이션이 누락되었습니다. 프로젝트는 kotlinx.serialization을 사용하고 있으며, 다른 모델 클래스들(Timetable.kt, OpenLecture.kt 등)은 모두 이 어노테이션을 포함하고 있습니다. JSON 역직렬화 시 런타임 오류가 발생할 수 있으니 @Serializable을 각 데이터 클래스에 추가해주세요:
`@Serializable`
data class GraduationProcessResponse(...)
`@Serializable`
data class GraduationProcessResponseData(...)
`@Serializable`
data class GraduationProgressData(...)
`@Serializable`
data class GraduationProcessCourseData(...)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/graduation/GraduationProcessResponse.kt`
around lines 6 - 51, Add kotlinx.serialization support by annotating each
response model with `@Serializable`: GraduationProcessResponse,
GraduationProcessResponseData, GraduationProgressData, and
GraduationProcessCourseData; also add the import for
kotlinx.serialization.Serializable where these classes are declared so the JSON
(de)serializer can recognize and parse instances of these classes at runtime.
| fun toProfile() = Profile( | ||
| name = name, | ||
| studentCode = studentCode, | ||
| departmentName = departmentName, | ||
| majorName = majorName, | ||
| gradeLevel = gradeLevel, | ||
| currentSemester = currentSemester, | ||
| status = status | ||
| ) |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
매핑에서 제외된 필드 검토
toProfile()에서 lastUpdatedAt, lastSyncedAt, reconnectionRequired 필드가 매핑되지 않습니다. 특히 reconnectionRequired는 사용자에게 재연결이 필요함을 알려야 할 때 UI에서 활용될 수 있는 중요한 상태 정보입니다.
해당 필드들이 의도적으로 제외된 것인지, 또는 별도의 상태 관리를 통해 처리되는지 확인해 주세요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/profile/ProfileResponse.kt`
around lines 23 - 31, toProfile() currently omits lastUpdatedAt, lastSyncedAt,
and reconnectionRequired from the Profile conversion; update the toProfile()
function to map these fields into the Profile constructor (e.g., lastUpdatedAt =
lastUpdatedAt, lastSyncedAt = lastSyncedAt, reconnectionRequired =
reconnectionRequired), handling any nullable/format conversions required to
match Profile's property types and preserving existing behavior for defaults if
fields are absent.
| fun toSemesterGradesList() = SemesterGradesList( | ||
| semesterGradesList = data.map { it.toSemesterGrades() } | ||
| ) |
There was a problem hiding this comment.
실패 응답도 정상 모델로 변환되는 경로를 차단해야 합니다.
Line 11-13에서 success 확인 없이 변환하면, 실패 응답이 정상 데이터처럼 UI로 전달될 수 있습니다.
🔧 제안 수정안
data class SemesterGradesListResponse(
val data: List<SemesterGradesData>,
val message: String,
val success: Boolean
) {
- fun toSemesterGradesList() = SemesterGradesList(
- semesterGradesList = data.map { it.toSemesterGrades() }
- )
+ fun toSemesterGradesList(): SemesterGradesList {
+ require(success) { "Semester grades API failed: $message" }
+ return SemesterGradesList(
+ semesterGradesList = data.map { it.toSemesterGrades() },
+ )
+ }
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/semester/SemesterGradesListResponse.kt`
around lines 11 - 13, toSemesterGradesList currently converts response->model
without verifying the response succeeded, allowing error responses to flow to
the UI; update the toSemesterGradesList function to first check the response's
success boolean (the success property on this response) and if it's false stop
conversion—e.g. throw an IllegalStateException (or return null/Result as your
codebase prefers) instead of mapping data; reference the toSemesterGradesList
function, the success property, data collection and the target
SemesterGradesList model when making the change.
| fun toSemesterList() = SemesterList( | ||
| semesterList = data.map { it.toSemester() } | ||
| ) |
There was a problem hiding this comment.
실패 응답을 정상 데이터로 매핑할 위험이 있습니다
Line 11~13의 toSemesterList()가 success/message를 무시하고 항상 매핑합니다. 호출부 실수 시 실패 응답이 정상 데이터로 흘러가므로, 최소한 성공 여부를 검증하거나 nullable/Result 기반으로 계약을 명시해 주세요.
권장 수정 예시 (fail-fast)
- fun toSemesterList() = SemesterList(
- semesterList = data.map { it.toSemester() }
- )
+ fun toSemesterList(): SemesterList {
+ require(success) { "Failed to map SemesterListResponse: $message" }
+ return SemesterList(
+ semesterList = data.map { it.toSemester() }
+ )
+ }📝 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.
| fun toSemesterList() = SemesterList( | |
| semesterList = data.map { it.toSemester() } | |
| ) | |
| fun toSemesterList(): SemesterList { | |
| require(success) { "Failed to map SemesterListResponse: $message" } | |
| return SemesterList( | |
| semesterList = data.map { it.toSemester() } | |
| ) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/response/semester/SemesterListResponse.kt`
around lines 11 - 13, toSemesterList() currently ignores response
success/message and always maps data to a SemesterList, risking propagation of
failure responses; update the toSemesterList() implementation to check the
response's success (and/or message) first and only map data when success is
true—otherwise return a nullable (SemesterList?) or a Result/Failure (or throw)
to make the contract explicit; reference the toSemesterList() function, the
SemesterList type, and the response properties (data, success, message) and
update callers accordingly to handle the nullable/Result/exception return.
| import com.chukchukhaksa.mobile.presentation.timetable.semesterselect.Semester | ||
|
|
||
| data class SemesterList( | ||
| val semesterList: List<Semester> | ||
| ) |
There was a problem hiding this comment.
공용 모델이 프레젠테이션 레이어 타입에 직접 의존합니다
Line 3~7에서 common.model이 presentation...Semester를 참조해 레이어 경계가 깨졌습니다. 이 구조는 UI 변경이 모델 계층에 전파되는 결합을 만듭니다. common.model.semester 내부에 독립 타입을 두고 해당 타입으로만 보관하도록 분리해 주세요.
권장 수정 예시
-import com.chukchukhaksa.mobile.presentation.timetable.semesterselect.Semester
+import com.chukchukhaksa.mobile.common.model.semester.Semester
data class SemesterList(
val semesterList: List<Semester>
)// composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/semester/Semester.kt (신규)
package com.chukchukhaksa.mobile.common.model.semester
data class Semester(
val semester: Int,
val year: Int,
)📝 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.
| import com.chukchukhaksa.mobile.presentation.timetable.semesterselect.Semester | |
| data class SemesterList( | |
| val semesterList: List<Semester> | |
| ) | |
| import com.chukchukhaksa.mobile.common.model.semester.Semester | |
| data class SemesterList( | |
| val semesterList: List<Semester> | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@composeApp/src/commonMain/kotlin/com/chukchukhaksa/mobile/common/model/semester/SemesterList.kt`
around lines 3 - 7, The common model currently depends on the presentation type
Semester; create an independent domain model data class Semester in package
com.chukchukhaksa.mobile.common.model.semester and update the existing
SemesterList data class to use that new Semester type instead of
com.chukchukhaksa.mobile.presentation.timetable.semesterselect.Semester; ensure
imports are adjusted and presentation-layer Semester is only mapped to/from the
common.model.semester.Semester at the UI boundary (e.g., via a mapper).
📌 PR 요약
🌱 작업한 내용
🌱 PR 포인트
📸 스크린샷
📮 관련 이슈
RCA 룰을 사용하여 코드 리뷰를 해주세요
R (Request Changes): 적극적으로 반영을 고려해주세요C (Comment): 웬만하면 반영해주세요A (Approve): 반영해도 좋고, 넘어가도 좋습니다. 사소한 의견입니다.Summary by CodeRabbit
릴리스 노트