chore: scaffold multi-module project, version catalog, and build-logic

Foundation milestone (REDI-78, REDI-79):

- Multi-module skeleton: :app, :core:{domain,data,presentation,design-system},
  :feature:characters:{domain,data,presentation,presentation-compose,presentation-views},
  :feature:about:presentation, plus the :build-logic composite build.
- gradle/libs.versions.toml as the single source of truth ([versions]/[libraries]/
  [bundles]/[plugins]); no inline versions in any build file.
- Convention plugins: architecture.android.{application,library,feature,feature.views},
  domain.module, compose, koin, ktor, kotlinx.serialization.
- Pure-Kotlin domain modules; presentation-compose uses android.feature;
  presentation-views uses android.feature.views (ViewBinding on, Compose off);
  the UI-agnostic :presentation has neither Compose nor Views deps.
- Toolchain: AGP 9.0.1, Kotlin 2.3.20, Gradle 9.1.0, compileSdk 36, minSdk 24, Java 17.
- Minimal MainActivity placeholder; CI (assembleDebug) via GitHub Actions.

Verified: ./gradlew projects lists the full tree and ./gradlew assemble is green.
This commit is contained in:
2026-06-10 10:52:03 +02:00
commit 10fa6dc9eb
56 changed files with 1468 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
plugins {
alias(libs.plugins.architecture.android.library)
alias(libs.plugins.architecture.koin)
alias(libs.plugins.architecture.kotlinx.serialization)
}
android {
namespace = "com.example.architecture.feature.characters.data"
}
dependencies {
implementation(project(":core:domain"))
implementation(project(":core:data"))
implementation(project(":feature:characters:domain"))
}

View File

@@ -0,0 +1,7 @@
plugins {
alias(libs.plugins.architecture.domain.module)
}
dependencies {
implementation(project(":core:domain"))
}

View File

@@ -0,0 +1,14 @@
plugins {
alias(libs.plugins.architecture.android.feature)
}
android {
namespace = "com.example.architecture.feature.characters.presentation.compose"
}
dependencies {
implementation(project(":core:presentation"))
implementation(project(":core:design-system"))
implementation(project(":feature:characters:domain"))
implementation(project(":feature:characters:presentation"))
}

View File

@@ -0,0 +1,15 @@
plugins {
alias(libs.plugins.architecture.android.feature.views)
}
// Classic Views renderer (Fragment + ViewBinding + RecyclerView) driving the SAME ViewModel from
// :feature:characters:presentation. ViewBinding ON, Compose OFF.
android {
namespace = "com.example.architecture.feature.characters.presentation.views"
}
dependencies {
implementation(project(":core:presentation"))
implementation(project(":feature:characters:domain"))
implementation(project(":feature:characters:presentation"))
}

View File

@@ -0,0 +1,20 @@
plugins {
alias(libs.plugins.architecture.android.library)
alias(libs.plugins.architecture.koin)
}
// UI-agnostic presentation: the MVI ViewModel + State/Action/Event live here and are shared by
// BOTH the Compose and the Views renderers. No Compose, no Views dependencies on purpose.
android {
namespace = "com.example.architecture.feature.characters.presentation"
}
dependencies {
implementation(project(":core:domain"))
implementation(project(":core:presentation"))
implementation(project(":feature:characters:domain"))
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.lifecycle.viewmodel.savedstate)
implementation(libs.kotlinx.coroutines.android)
}