This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
# Build all modules
./gradlew build
# Build and install debug APK
./gradlew :app:installDebug
# Run unit tests
./gradlew test
# Run a single module's tests
./gradlew :feature:experience:test
# Run Android instrumentation tests
./gradlew connectedAndroidTest
# Lint
./gradlew lint
# Increment version code (custom task)
./gradlew incrementVersionCodeThis is a multi-module Android app following Clean Architecture with Jetpack Compose.
app/— Entry point.MainActivityhosts theNavHostand wires all feature routes.core/domain— Pure JVM library. Contains entities (Cv,Experience, etc.), theCvRepositoryinterface, and use cases (GetCvUseCases,ObserveCvUseCase). No Android dependencies.core/data— Repository implementation (CvRepositoryImpl), Retrofit API (CvApiService→GET /cv.json), Moshi DTOs/mappers, and Hilt modules. Flavor-specific implementations live here (real/mock).core/dispatcher— Hilt-provided coroutine dispatchers with qualifiers:@IoDispatcher,@DefaultDispatcher,@MainDispatcher,@MainImmediateDispatcher.core/designsystem— Material Design 3 theme and shared UI components.core/common— Navigation routes defined as a serializable sealedRouteinterface.feature/*— One module per screen. Each feature depends oncore:commonandcore:designsystem(injected automatically by thecvshowcase-featureconvention plugin).
All modules use convention plugins instead of duplicating Gradle config:
cvshowcase-application— App module (Compose, Hilt, Firebase, build types, flavors)cvshowcase-library— Base Android librarycvshowcase-feature— Feature modules (extends library, auto-addscore:common+core:designsystem)cvshowcase-hilt— Adds Hilt to any modulecvshowcase-jvm-library— Pure Kotlin library (used bycore:domain)cvshowcase-flavors—real(Firebase/prod) andmock(fake data) build variants
| Flavor | Purpose |
|---|---|
real |
Production — uses Firebase and the live Retrofit endpoint |
mock |
Development/testing — uses an in-memory mock CvRepository |
Routes are declared in core/common as a serializable sealed interface:
interface Route {
@Serializable data object Experience : Route
@Serializable data object Profile : Route
@Serializable data class DetailExperience(val title: String) : Route
}The NavHost lives in MainActivity. Use Jetpack Navigation Compose with type-safe routes.
- State: ViewModels expose
StateFlow<ScreenState>. Collect withcollectAsStateWithLifecycle(). - Search debouncing: 500 ms
debounceon the search query flow (seeExperienceViewModel). - Immutable collections: Use
toPersistentList()fromkotlinx-collections-immutablein UI state. - Dispatcher injection: Always inject
@IoDispatcherfor network/disk work rather than hardcodingDispatchers.IO. - Error handling: Use
.catch { }on flows; propagate errors as part of UI state.
- Kotlin 2.2.0 / Compose BOM 2024.09.00 / Navigation Compose 2.9.3
- Hilt (DI) + KSP (annotation processing)
- Retrofit 3.0 + Moshi 1.15.2 (Kotlin Codegen)
- Coil 3.3.0 (image loading)
- Firebase Analytics + Crashlytics (production flavor only)
- Timber for logging
kotlinx-coroutines-testfor ViewModel/flow unit tests