Data Layer
SkillDatabases & dataData layer on the KMP Starter Template — repositories and data sources, Logics guidance, DataStore persistence, Room database, StarterFileManager, and the Calf file picker.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Data Layer skill
What this skill tells your AI
The instructions your AI receives, as published by devatrii/kmp-starter-template in .agents/skills/kmp-starter/data/SKILL.md and read by ahel’s review.
Repositories & data sources
- Domain defines the interface; data implements it. See the onboarding trio:
features/core/domain/.../repositories/OnboardingRepository.ktfeatures/core/data/.../repositories/OnboardingRepositoryImpl.kt
- Bind impl to interface via Koin (
singleOf(::Impl) bind Interface::class).
Logics (use cases) — only when meaningful
Logics are use cases. Create them only for meaningful user-driven actions.
Good: RegisterAccountLogic, LogoutLogic, PurchaseSubscriptionLogic, DeleteAccountLogic, ExportNotesLogic, BackupDatabaseLogic.
Bad: ValidateEmailLogic, FormatDateLogic, GetUsersLogic, ParseJsonLogic, SavePreferenceLogic.
Simple operations belong in repositories, extension functions, or utilities. Do not wrap every repository call in a Logic. A Logic is a class with suspend operator fun invoke(); aggregate multiple Logics into a data class XLogics(...) if the ViewModel needs several.
Persistence — DataStore
Use Starter DataStores; do not introduce another preference framework.
Non-Compose (ViewModels/repos) — inject AppDataStore and use delegates:
class AuthViewModel(appDataStore: AppDataStore) : ViewModel() {
private val accessToken = appDataStore.stringDataStore("access_token")
private val isLoggedIn = appDataStore.booleanDataStore("is_logged_in", default = false)
private val settings = appDataStore.serializableDataStore("settings", default = Settings())
// API: flow, get(), set(value), clear()
}
Factories: stringDataStore, intDataStore, longDataStore, booleanDataStore, floatDataStore, doubleDataStore, stringSetDataStore, byteArrayDataStore, serializableDataStore.
Compose — remember*DataStore helpers:
val themeMode by rememberStringDataStore("theme_mode", "LIGHT")
var counter by rememberMutableIntDataStore("counter", 0)
Database (Room)
If features/database exists, define entities, DAOs, and migrations there; other features consume it.
- Entity:
@Entitydata class with@PrimaryKey. - DAO:
@Daointerface with@Query/@Insert/@Update/@Delete. - Register entity + DAO in
KmpStarterDatabase(@Database(entities=[...], version=DB_VERSION)). - Bump
DB_VERSIONon schema change; add migrations toKmpStarterDatabaseMigrations.SUPPORTED_MIGRATIONS.
If the project was generated without the database feature, ask the user to regenerate with Database enabled.
StarterFileManager
Cross-platform file API in starter:utils; returns Result for every operation. Marked @ExperimentalStarterApi — opt in with @OptIn(ExperimentalStarterApi::class).
// Compose (Activity-bound; required for saveFileIn / shareFile / openFile)
val fileManager = rememberStarterFileManager()
// Repos / background (no Activity needed)
class ReportRepository(private val fileManager: StarterFileManager) {
suspend fun cacheReport(bytes: ByteArray) = fileManager.saveInCache(
file = "report", folderPath = "exports", extension = "pdf",
content = bytes, mimeType = "application/pdf",
)
}
Key types: pass file (name, no extension) and extension (no dot) separately. StarterFile holds path, name, extension, mimeType, sizeBytes, timestamps.
- Downloads:
saveFileIntoDownloads,getFilesFromDownloads,getFileFromDownloads,readFromDownloads,renameFromDownloads,deleteFromDownloads(Android → public Downloads; iOS → Documents). - Cache:
saveInCache,getFilesFromCache,getFileFromCache,readFromCache,renameFromCache,deleteFromCache(paths relative to cache dir). - System picker:
saveFileIn(suggestedName, extension, content, mimeType). - Share/open:
shareFile(path),openFile(path)— need Activity on Android (userememberStarterFileManager()). - Android host app owns
FileProviderfor local paths (androidApp/.../AndroidManifest.xml+res/xml/starter_file_paths.xml).
Pass an Activity-bound instance into a ViewModel with Koin parameters (parametersOf(fileManager)).
See https://starter.atherio.dev/fundamentals/13-starter-file-manager/ for full API.
File picker
Use the bundled Calf library for file picking. Do not introduce another picker library.
Signals
- GitHub stars
- 162
- Forks
- 28
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
kmp-starter-data- Source
- github.com/devatrii/kmp-starter-template