Skip to content

refactor: AGP 9.0 업그레이드 및 Clean Architecture 멀티모듈 마이그레이션#3

Open
Gael-Android wants to merge 11 commits intomainfrom
feat/agp9-build-logic-migration
Open

refactor: AGP 9.0 업그레이드 및 Clean Architecture 멀티모듈 마이그레이션#3
Gael-Android wants to merge 11 commits intomainfrom
feat/agp9-build-logic-migration

Conversation

@Gael-Android
Copy link
Copy Markdown

@Gael-Android Gael-Android commented Feb 11, 2026

Summary

  • AGP 9.0 업그레이드: Gradle 8.14.3 → 9.1.0, AGP 8.11.2 → 9.0.0, Compose Multiplatform 1.9.3 → 1.10.0
  • build-logic 서브모듈 교체: 기존 커스텀 convention 플러그인을 제거하고 Gael-Android/build-logic 서브모듈로 전환
  • 프로젝트 구조 변경 (AGP 9 KMP 호환): androidApp 모듈 신규 생성, composeApp을 KMP 라이브러리로 전환, Android 리소스/매니페스트를 androidApp으로 이동
  • Clean Architecture 멀티모듈 재편: core 모듈(domain/data/presentation/designsystem), feature 모듈(auth/groupchat/messaging) 각각 domain/data/presentation 레이어로 분리

Changes

AGP 9.0 + Gradle 9.1 업그레이드

  • Kotlin 2.3.0, AGP 9.0.0, Gradle 9.1.0, CMP 1.10.0
  • com.android.kotlin.multiplatform.library 플러그인 기반 KMP 모듈 설정

build-logic 마이그레이션

  • 기존 커스텀 convention 플러그인 5개 제거
  • Gael-Android/build-logic git submodule로 교체
  • 새 플러그인 ID 적용 (convention.cmp.application, convention.kmp.library, convention.cmp.library, convention.cmp.feature, convention.android.application.compose)

멀티모듈 구조 재편

core/domain, core/data, core/presentation, core/designsystem
feature/auth/{domain,data,presentation}
feature/groupchat/{domain,data,presentation}
feature/messaging/{domain,data,presentation}

버그 수정

  • composeAppandroidResources.enable = true 설정 추가 (Compose 리소스 패키징 누락 해결)
  • lifecycle 라이브러리 참조를 JetBrains KMP 카탈로그 이름으로 수정
  • orphan 상태의 Platform.ios.kt 제거

Test plan

  • ./gradlew :androidApp:assembleDebug 빌드 성공 확인
  • ./gradlew :androidApp:installDebug로 앱 실행 확인
  • 각 모듈별 ./gradlew :{module}:build 성공 확인
  • iOS 타겟 컴파일 확인

🤖 Generated with Claude Code

Gael-Android and others added 9 commits February 8, 2026 01:42
## 주요 변경사항

### AGP 9.0 업그레이드
- Gradle 8.14.3 → 9.1.0
- AGP 8.11.2 → 9.0.0
- Compose Multiplatform 1.9.3 → 1.10.0

### 프로젝트 구조 변경 (AGP 9 KMP 호환)
- androidApp 모듈 신규 생성 (Android 앱 진입점)
- composeApp을 KMP 라이브러리로 전환
- Android 리소스/매니페스트를 androidApp으로 이동

### build-logic 마이그레이션
- 기존 커스텀 convention 플러그인 제거
- Gael-Android/build-logic 서브모듈로 교체
- 새 플러그인 ID 적용:
  - convention.cmp.application
  - convention.kmp.library
  - convention.cmp.library

### 모듈별 플러그인 매핑
- composeApp → convention.cmp.application
- core/model, core/data → convention.kmp.library
- core/designsystem, core/ui → convention.cmp.library
- feature/settings/api → convention.kmp.library
- feature/settings/impl → convention.cmp.library

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- build-logic: Desktop 타겟 제거 및 불필요한 설정 옵션 정리
- libs.versions.toml: 사용하지 않는 프로젝트 설정 및 lifecycle 라이브러리 참조 제거

Co-authored-by: Cursor <cursoragent@cursor.com>
androidx.lifecycle → jetbrains lifecycle으로 version catalog 참조 변경

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- core 모듈을 domain/data/designsystem/presentation으로 재구성
- feature 모듈 추가 (auth, groupchat, messaging)
- 각 feature를 domain/data/presentation 레이어로 분리
- composeApp 의존성을 새 모듈 구조에 맞게 업데이트

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- androidApp/build.gradle.kts에서 수동 빌드 설정 제거
- convention.android.application.compose 플러그인 적용
- build-logic 서브모듈 업데이트

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
com.android.kotlin.multiplatform.library 플러그인 사용 시
androidResources.enable = true 설정이 없으면 Compose Multiplatform
리소스가 Android assets로 패키징되지 않아 런타임 크래시 발생

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
commonMain에 expect 선언이 삭제된 후 orphan 상태로 남아있던
템플릿 파일로 iOS 컴파일 에러 발생

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- build-logic 서브모듈을 feat/precompiled-script-migration 브랜치로 전환
- kotlin-serialization-gradlePlugin을 version catalog에 등록

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@minjun011026 minjun011026 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다
리뷰 확인 부탁드릴게요!

commonMain.dependencies {
implementation(libs.jetbrains.compose.viewmodel)
implementation(libs.jetbrains.lifecycle.viewmodel)
implementation(libs.jetbrains.lifecycle.compose)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

이 presentation 모듈의 역할은 무엇인가요?

클린 아키텍처를 적용한다면 feature모듈이 아닌 presentation 모듈에 각 피처(화면)들을 배치하는 게 일반적인 걸로 알고 있는데 이미 별도의 feature 모듈이 존재하고 있다면 이 presentation의 역할이 궁금합니다!

viewmodel 라이브러리를 사용하는 걸 보면 UI 레벨의 역할을 수행할 것으로 예상되는데 feature와의 차이점도 궁금해용

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Feature 모듈들이 UI를 구현할 때 반복적으로 필요한 공통 코드들을 두는 곳입니다..! 예를 들어 이벤트처리나 Dialog, sheet 같은거도 있고 권한처리 같이 앱 전역에서 사용하는 코드들을 두는곳이에요!!

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

공통 코드를 feature에서 각각의 화면 명의 모듈에 배치하는 건 좀 어색하지 않을까요?
공통, 기반, 중심이라는 의미에서의 core 모듈의 역할이 애매해질 것 같아요.

오히려 권한처리같은 앱 전역에서 사용되는 코드는 app모듈이나 core에서 관리하는 게 맞지 않을까 하는 생각이 듭니다.

예를 들어 feature 모듈 내에는 또다시 여러가지 모듈이 위치하는데 어떤 기준으로 공통으로 사용되는 코드를 어느 하나의 모듈에 배치할 지에 대한 기준도 모호해진다고 생각합니다.

또한 UI 구현에서 반복적으로 사용되는 건 core의 ui 와 designsystem 으로 처리하는게 일반적이기도 하구요.
core라는 공통의 의미를 담고 있는 모듈에 개별적으로 구현되는 presentation이 위치하는 게 개인적으로는 조금 어색하게 느껴집니다.
공통되는 부분이 적은 presentation이 어떤 의미에서 core의 하위로서 성립하게 되는지 잘 와닿지 않아 이 부분에 대한 설명을 좀더 해주시면 감사하겠습니다!

물론 아키텍처 설계에 정답은 없지만 개인적으로 공통, 중심이라는 의미를 갖는 core에 개별적인 구현이 이루어지는 presentation이 위치하는 것 그리고 공통 코드가 위치하게 되는 feature가 오히려 core 외부에 있는 것, 이 2가지가 조금 어색하게 느껴집니다.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

좋은 리뷰 감사해요!! 👍

core:presentation 모듈은 개별 feature의 presentation 구현을 두는 공간이 아니라,
feature의 presentation 레이어에서 반복적으로 사용되는 공통 UI를 제공하는 모듈이에요

실제 각 화면 구현은 feature들의 presentation 에 존재하며,
feature는 core에만 의존하고 core는 feature를 참조하지 않기 때문에 의존성 방향은 유지되고 있긴합니다!

그리고 제가 해당 설정을 https://github.com/philipplackner/Chirp 에 따라 해서 동일하게 presentation으로 간 거긴합니다..!

다만 Teach님 말대로 네이밍 측면에서는 core:presentation이 오해를 줄 수 있어
core:ui 또는 core:designsystem, 그리고 권한등이 필요하다면 core:platform 등으로 명확히 구분하는 것 더 좋을거 같긴하네요!

마지막까지 리뷰 정성스럽게 남겨주셔서 감사합니다..! 잘 반영해서 마무리 할게용

androidLibrary {
namespace = "com.yourssu.pingpong.core.presentation"
compileSdk = libs.versions.projectCompileSdkVersion.get().toInt()
minSdk = libs.versions.projectMinSdkVersion.get().toInt()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

버전 카탈로그에 별도의 컴파일Sdk 버전과 minSdk 버전을 명시하고 이를 컨벤션 플러그인에서 사용하고 있는 걸로 예상되는데 이곳에서는 별도로 직접 선언하는 이유가 무엇인가요?

만약 이처럼 라이브러리 코드로서 사용된다면 아예 공통되는 cmp.library 컨벤션플러그인에 작성시 불필요한 보일러플레이트를 줄일 수 있지 않을까요?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

해당 기능을 Precompiled에서는 구현했는데, binary plugin 형태에서는 따로 기능을 만들지 않았네요... 이 보일러플레이트를 줄이는 코드는 추후에 반영하겠습니다!

Comment thread gradle/libs.versions.toml Outdated
# Android SDKs (legacy - for modules not using convention plugins)
android-compileSdk = "36"
android-minSdk = "24"
android-targetSdk = "36"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

projectMinSdkVersion = "24"
projectTargetSdkVersion = "36"
projectCompileSdkVersion = "36"

이거랑 차이가 뭔가요?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

아 필요없습니다! 제거하겠습니다

Comment thread gradle/libs.versions.toml Outdated

# Koin
koin = "4.0.4"
koin-compose = "4.0.4"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

제가 알기로는
koin이랑 koin-compose로 구분한 라이브러리 들이 같은 버전을 공유하는 걸로 알고 있는데
하나의 버전으로 통일하면 더 좋을 것 같아요

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

넵..!

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.

2 participants