docs: tighten kotlin support examples

This commit is contained in:
Affaan Mustafa
2026-03-10 20:50:34 -07:00
committed by Affaan Mustafa
parent f6a470de63
commit 7433610105
7 changed files with 28 additions and 8 deletions

View File

@@ -28,6 +28,16 @@ Check for:
- `CLAUDE.md` for project-specific conventions - `CLAUDE.md` for project-specific conventions
- Whether this is Android-only, KMP, or Compose Multiplatform - Whether this is Android-only, KMP, or Compose Multiplatform
### Step 2b: Security Review
Apply the Kotlin/Android security guidance before continuing:
- exported Android components, deep links, and intent filters
- insecure crypto, WebView, and network configuration usage
- keystore, token, and credential handling
- platform-specific storage and permission risks
If you find a CRITICAL security issue, stop the review and hand off to `security-reviewer` before doing any further analysis.
### Step 3: Read and Review ### Step 3: Read and Review
Read changed files fully. Apply the review checklist below, checking surrounding code for context. Read changed files fully. Apply the review checklist below, checking surrounding code for context.
@@ -97,6 +107,15 @@ Button(onClick = onClick)
- **Hardcoded strings** — User-facing strings not in `strings.xml` or Compose resources - **Hardcoded strings** — User-facing strings not in `strings.xml` or Compose resources
- **Missing lifecycle handling** — Collecting Flows in Activities without `repeatOnLifecycle` - **Missing lifecycle handling** — Collecting Flows in Activities without `repeatOnLifecycle`
### Security (CRITICAL)
- **Exported component exposure** — Activities, services, or receivers exported without proper guards
- **Insecure crypto/storage** — Homegrown crypto, plaintext secrets, or weak keystore usage
- **Unsafe WebView/network config** — JavaScript bridges, cleartext traffic, permissive trust settings
- **Sensitive logging** — Tokens, credentials, PII, or secrets emitted to logs
If any CRITICAL security issue is present, stop and escalate to `security-reviewer`.
### Gradle & Build (LOW) ### Gradle & Build (LOW)
- **Version catalog not used** — Hardcoded versions instead of `libs.versions.toml` - **Version catalog not used** — Hardcoded versions instead of `libs.versions.toml`

View File

@@ -5,7 +5,7 @@ paths:
--- ---
# Kotlin Coding Style # Kotlin Coding Style
> This file extends [common/coding-style.md](../common/coding-style.md) with Kotlin specific content. > This file extends [common/coding-style.md](../common/coding-style.md) with Kotlin-specific content.
## Formatting ## Formatting

View File

@@ -5,7 +5,7 @@ paths:
--- ---
# Kotlin Patterns # Kotlin Patterns
> This file extends [common/patterns.md](../common/patterns.md) with Kotlin and Android/KMP specific content. > This file extends [common/patterns.md](../common/patterns.md) with Kotlin and Android/KMP-specific content.
## Dependency Injection ## Dependency Injection

View File

@@ -5,7 +5,7 @@ paths:
--- ---
# Kotlin Security # Kotlin Security
> This file extends [common/security.md](../common/security.md) with Kotlin and Android/KMP specific content. > This file extends [common/security.md](../common/security.md) with Kotlin and Android/KMP-specific content.
## Secrets Management ## Secrets Management

View File

@@ -5,7 +5,7 @@ paths:
--- ---
# Kotlin Testing # Kotlin Testing
> This file extends [common/testing.md](../common/testing.md) with Kotlin and Android/KMP specific content. > This file extends [common/testing.md](../common/testing.md) with Kotlin and Android/KMP-specific content.
## Test Framework ## Test Framework

View File

@@ -252,11 +252,12 @@ val showScrollToTop by remember {
// BAD — new lambda and list every recomposition // BAD — new lambda and list every recomposition
items.filter { it.isActive }.forEach { ActiveItem(it, onClick = { handle(it) }) } items.filter { it.isActive }.forEach { ActiveItem(it, onClick = { handle(it) }) }
// GOOD — remember filtered list, stable lambda with key // GOOD — key each item so callbacks stay attached to the right row
val activeItems = remember(items) { items.filter { it.isActive } } val activeItems = remember(items) { items.filter { it.isActive } }
activeItems.forEach { item -> activeItems.forEach { item ->
val onClick = remember(item.id) { { handle(item) } } key(item.id) {
ActiveItem(item, onClick = onClick) ActiveItem(item, onClick = { handle(item) })
}
} }
``` ```

View File

@@ -217,7 +217,7 @@ viewModelScope.launch {
```kotlin ```kotlin
@Test @Test
fun `search updates item list`() = runTest { fun `search updates item list`() = runTest {
val fakeRepository = FakeItemRepository(items = testItems) val fakeRepository = FakeItemRepository().apply { emit(testItems) }
val viewModel = ItemListViewModel(GetItemsUseCase(fakeRepository)) val viewModel = ItemListViewModel(GetItemsUseCase(fakeRepository))
viewModel.state.test { viewModel.state.test {