Domain Module Creation Skill
This skill creates a new domain module in the domain/ package.
Prerequisites & Pre-steps
Before generating the module, confirm:
- Module Naming:
{domain}: Must be snake_case (e.g.,photo_tag).{Domain}: Must be PascalCase (e.g.,PhotoTag).
- Module Purpose (What business domain this represents)
- Repository Interfaces (What data contracts are needed)
- Use Cases (What business operations are needed)
Module Structure
Each domain module consists of a single api submodule:
domain/
└── {domain}/
└── api/ ← Public contracts (interfaces only)
├── build.gradle.kts
└── src/main/java/com/metasearch/android/domain/{domain}/api/
├── repository/
│ └── {Domain}Repository.kt
└── usecase/
└── {Action}{Domain}UseCase.kt
Implementation Steps
1. Gradle Configuration (domain/{domain}/api/build.gradle.kts)
plugins {
alias(libs.plugins.metasearch.jvm.library)
}
dependencies {
api(projects.data.domain)
implementation(libs.kotlinx.coroutines.core)
}
2. File Structure
Create the source directory:
domain/{domain}/api/src/main/java/com/metasearch/android/domain/{domain}/api/
3. Key Files to Create
Repository Interface (repository/{Domain}Repository.kt)
package com.metasearch.android.domain.{domain}.api.repository
import kotlinx.coroutines.flow.Flow
interface {Domain}Repository {
fun getAll(): Flow<List<{DomainModel}>>
suspend fun getById(id: Long): {DomainModel}?
// TODO: Add data contract methods
}
UseCase Interface (usecase/{Action}{Domain}UseCase.kt)
Flow return (reactive stream):
package com.metasearch.android.domain.{domain}.api.usecase
import kotlinx.coroutines.flow.Flow
interface Get{Domain}UseCase {
operator fun invoke(id: Long): Flow<{DomainModel}?>
}
Result return (one-shot operation):
package com.metasearch.android.domain.{domain}.api.usecase
interface Update{Domain}UseCase {
suspend operator fun invoke(id: Long, value: String): Result<Unit>
}
4. Registration
Add to settings.gradle.kts in alphabetical order:
include(":domain:{domain}:api")
5. Sync & Verify
./gradlew :domain:{domain}:api:compileKotlin
Naming & Architecture Rules
| Item | Convention | Example (domain=photo_tag) |
|---|---|---|
| Module Directory | snake_case | photo_tag |
| Class Prefix | PascalCase | PhotoTag |
| Namespace | com.metasearch.android.domain.{domain}.api |
com.metasearch.android.domain.photo_tag.api |
| Repository | {Domain}Repository |
PhotoTagRepository |
| UseCase | {Verb}{Domain}UseCase |
GetPhotoTagUseCase, UpdatePhotoTagUseCase |
| Settings (Gradle) | :domain:{domain}:api |
:domain:photo_tag:api |
Best Practices
- Pure Kotlin Only:
domainmodules must not depend on any Android SDK, Compose, or platform-specific frameworks. - JVM Convention: Use the
metasearch.jvm.libraryplugin. This prevents accidental usage of Android APIs. - Interfaces Only: Define only interfaces here. Implementations belong in the
datalayer. - UseCase = Single Responsibility: Each UseCase must have exactly one
operator fun invoke. One operation per class. - Domain Models: Use
data.domainmodels viaapi(projects.data.domain). Do not define new domain models inside this module. - operator fun invoke: Always expose UseCase logic through
operator fun invokefor clean call-site syntax. - Feature Integration: Feature modules must depend on
domain.{domain}.api, never ondatamodules directly.