Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns.
Copy the install command and let the AI configure it · recommended for beginners
Please install the "android-clean-architecture" skill from askskill: 1. Download https://raw.githubusercontent.com/affaan-m/ECC/main/skills/android-clean-architecture/SKILL.md 2. Save it as ~/.claude/skills/android-clean-architecture/SKILL.md 3. Reload skills and tell me it's ready
Clean Architecture patterns for Android and KMP projects. Covers module boundaries, dependency inversion, UseCase/Repository patterns, and data layer design with Room, SQLDelight, and Ktor.
project/
├── app/ # Android entry point, DI wiring, Application class
├── core/ # Shared utilities, base classes, error types
├── domain/ # UseCases, domain models, repository interfaces (pure Kotlin)
├── data/ # Repository implementations, DataSources, DB, network
├── presentation/ # Screens, ViewModels, UI models, navigation
├── design-system/ # Reusable Compose components, theme, typography
└── feature/ # Feature modules (optional, for larger projects)
├── auth/
├── settings/
└── profile/
app → presentation, domain, data, core
presentation → domain, design-system, core
data → domain, core
domain → core (or no dependencies)
core → (nothing)
Critical: domain must NEVER depend on data, presentation, or any framework. It contains pure Kotlin only.
Each UseCase represents one business operation. Use operator fun invoke for clean call sites:
class GetItemsByCategoryUseCase(
private val repository: ItemRepository
) {
suspend operator fun invoke(category: String): Result<List<Item>> {
return repository.getItemsByCategory(category)
}
}
// Flow-based UseCase for reactive streams
class ObserveUserProgressUseCase(
private val repository: UserRepository
) {
operator fun invoke(userId: String): Flow<UserProgress> {
return repository.observeProgress(userId)
}
}
Domain models are plain Kotlin data classes — no framework annotations:
data class Item(
val id: String,
val title: String,
val description: String,
val tags: List<String>,
val status: Status,
val category: String
)
enum class Status { DRAFT, ACTIVE, ARCHIVED }
Defined in domain, implemented in data:
interface ItemRepository {
suspend fun getItemsByCategory(category: String): Result<List<Item>>
suspend fun saveItem(item: Item): Result<Unit>
fun observeItems(): Flow<List<Item>>
}
Coordinates between local and remote data sources:
class ItemRepositoryImpl(
private val localDataSource: ItemLocalDataSource,
private val remoteDataSource: ItemRemoteDataSource
) : ItemRepository {
override suspend fun getItemsByCategory(category: String): Result<List<Item>> {
return runCatching {
val remote = remoteDataSource.fetchItems(category)
localDataSource.insertItems(remote.map { it.toEntity() })
localDataSource.getItemsByCategory(category).map { it.toDomain() }
}
}
override suspend fun saveItem(item: Item): Result<Unit> {
return runCatching {
localDataSource.insertItems(listOf(item.toEntity()))
}
}
override fun observeItems(): Flow<List<Item>> {
return localDataSource.observeAll().map { entities ->
entities.map { it.toDomain() }
}
}
}
Keep mappers as extension functions near the data models:
// In data layer
fun ItemEntity.toDomain() = Item(
id = id,
title = title,
description = description,
tags = tags.split("|"),
status = Status.valueOf(status),
category = category
)
fun ItemDto.toEntity() = ItemEntity(
id = id,
…
Record polished web app UI demo videos for walkthroughs, tutorials, and showcases.
Refine retrieved context iteratively to improve subagent understanding and output quality.
Unify multi-channel notifications for routing, deduplication, escalation, and inbox consolidation.
Audit, plan, and implement SEO improvements for better search visibility.
Create iOS liquid glass interfaces with dynamic visuals and interactive morphing.
Fetches up-to-date framework docs for setup, APIs, and code examples.