Guidelines for AI coding agents working in this repository.
Android application "SW Parks" (Street Workout Parks), built with Kotlin and Jetpack Compose. A port of the iOS version (SwiftUI-WorkoutApp).
- Package:
com.swparks - Min SDK: 26
- Target SDK: 35
- Kotlin: 2.3.20
- Serena MCP is available in this repository.
- Use Serena first for symbol search, references, and structure.
- Prefer symbol-level navigation over full-file reads.
- Read only the minimal relevant code needed for the task.
- Avoid scanning many large files sequentially.
- Use broad reads only for final verification or very small files.
Preferred order:
- Find relevant symbols/files with Serena
- Read only needed sections
- Make changes
- Re-check affected usages
- Run relevant tests/lint
Prefer Serena especially for:
- refactoring
- finding usages/references
- ViewModel / UseCase / Repository relationships
- navigation changes
- impact analysis
make build
./gradlew assembleDebug
make clean
make lint
./gradlew ktlintCheck
./gradlew app:detekt
make format
./gradlew ktlintFormatmake test
./gradlew :app:testDebugUnitTest
# Single test class
./gradlew :app:testDebugUnitTest --tests "com.swparks.domain.usecase.LoginUseCaseTest"
# Single test method
./gradlew :app:testDebugUnitTest --tests "com.swparks.domain.usecase.LoginUseCaseTest.invoke_whenValidCredentials_thenSavesTokenAndCallsLogin"
# Android instrumented tests
make android-test
./gradlew connectedDebugAndroidTestOrder imports as:
- AndroidX
- Kotlin
- Third-party libraries
- com.swparks.*
Separate groups with blank lines. Remove unused imports.
- Classes: PascalCase
- Functions/variables: camelCase
- Constants: UPPER_SNAKE_CASE
- Packages: lowercase
- Composables: PascalCase
- Use data classes for models
- Use sealed classes for UI state and navigation
- Use extension functions when they improve readability
Never use !!.
Prefer:
val itemId = checkNotNull(savedStateHandle["itemId"]) { "ItemId is required" }
user?.let { processUser(it) }
val name = user?.name ?: "Unknown"- In UseCases, return
Result<T> - In ViewModels, use sealed UI state
- For one-off events (navigation, toast), use
Channel
- Add KDoc for public APIs
- Explain why, not what
- Write logs in Russian
UI Layer (Compose + ViewModels)
↓
Domain Layer (Use Cases)
↓
Data Layer (Repositories + API + Room + DataStore)
- MVVM
- Unidirectional Data Flow
- Repository Pattern
- Manual DI via AppContainer (no Hilt)
- Global state for navigation and auth
isAuthorized = currentUser != null
- Parks, Cities: cache-first with server sync
- Events: online-first
- Journals: offline-first with sync
- Messages: online-first with fallback cache
- Auth: online-only
- TDD order: Tests → Logic → UI
@Test
fun functionName_whenCondition_thenExpectedResult()- JUnit 4
- MockK
- kotlinx.coroutines.test
- Turbine
- Robolectric
app/src/test/java/com/swparks/app/src/androidTest/java/com/swparks/
app/build.gradle.ktsconfig/detekt/detekt.ymlMakefile.cursor/rules/*.mdcdocs/plan-development.md
make formatmake lintmake test- No crashes on app launch
- No deprecated API usage