Kotlin Multiplatform library for the Umami web analytics REST API.
| Module | Path | Purpose |
|---|---|---|
:umami |
umami/ |
Core event tracking (lightweight client) |
:umami-api |
umami-api/ |
Full REST API wrapper — depends on :umami via api() |
:sample:* |
sample/ |
Demo apps (Compose Desktop, native terminal). Not published. |
:umami-api re-exports :umami. Both publish to Maven Central as dev.appoutlet:umami / dev.appoutlet:umami-api.
./gradlew detekt # Lint + auto-correct — runs automatically on pre-push; do NOT run autonomously
./gradlew allTests # All tests, all KMP targets — very slow on dev machines; do NOT run autonomously
./gradlew jvmTest # JVM tests only — still slow; do NOT run autonomously
./gradlew koverVerify # Coverage gates — runs full test suite; do NOT run autonomouslyWhen to run what:
- To verify a change compiles and behaves correctly, run only the specific test class(es) affected:
./gradlew jvmTest --tests "dev.appoutlet.umami.api.auth.LoginTest" detekt,allTests,jvmTest, andkoverVerifymust only be run when explicitly requested by the user.- CI pipeline order (reference only):
detekt→koverVerify→koverXmlReport.
Dokka and Maven publish require --no-configuration-cache despite it being globally enabled.
- Wrap every test in
kotlinx.coroutines.test.runTest. - Assertions: Kotest matchers (
shouldBe). - HTTP mocking: Ktor
MockEnginevia helpers indev.appoutlet.umami.testingpackage (both modules have their own copy). - General mocking: Mokkery.
- Test names use backtick style:
fun `should do something`() = runTest { ... } - Tests live in
commonTestonly — no platform-specific test source sets. - See
umami-api/src/commonTest/AGENTS.mdfor detailed test-writing patterns (MockEngine helpers,getUmamiInstance,respond<T>,body<T>()).
Key difference between the two getUmamiInstance copies: :umami-api sets enableEventQueue = false; :umami leaves it enabled.
- Extension function pattern: API features are classes taking
Umamias a constructor param, exposed via extension functions (umami.auth(),umami.websites(), etc.). - Ktor Resources: API routes are nested
@Resourceclasses inumami-api/.../Api.kt. @InternalUmamiApi:@RequiresOptInannotation for internal APIs. All source sets opt in vialanguageSettings.SuspendMutableMap: Custom interface for async-safe header management (InMemoryHeadersdefault impl).- Platform
expect/actualdeclarations live only in:umami(HTTP engine selection, user-agent string).
- Gradle 8.14.2 (use
./gradlew, not system Gradle). - JVM toolchain: Java 21 for compilation. CI uses Java 17 (JetBrains distro).
- KMP targets: Android, JVM, JS (browser), WasmJS, iOS, macOS, Linux, Windows.
- NEVER commit or push code autonomously. Every change must be reviewed by a human before committing.
- Commit messages: Conventional Commits (
feat:,fix:,chore:, etc.). - Branch names:
feature/,fix/prefixes. - Pre-push hook runs
detektautomatically (installed via./gradlew installGitHooks, which runs onassemble).