7 KiB
7 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build & Test Commands
# Build debug APK (Google flavor)
./gradlew :app:assembleGoogleDebug
# Run all unit tests (debug/googleDebug variants + JVM modules)
./gradlew unitTest
# Run tests for a single module
./gradlew :features:wallet:impl:testDebugUnitTest # Android library module
./gradlew :app:testGoogleDebugUnitTest # App module
./gradlew :domain:tokens:test # Pure JVM module
# Run a single test class
./gradlew :core:ui:testDebugUnitTest --tests "com.tangem.core.ui.format.BigDecimalCryptoFormatTest"
# Detekt (static analysis) — runs automatically via convention plugin on applicable modules
./gradlew detekt detektMain
# Build UI tests APKs (for Marathon)
./gradlew :app:assembleGoogleMocked :app:assembleGoogleMockedAndroidTest
# 1. :app:assembleGoogleMocked — main APK (mocked build)
# 2. :app:assembleGoogleMockedAndroidTest — test APK with instrumented tests
Product flavors: google and huawei (dimension: service). Default development flavor is google.
Build types: debug, mocked, internal, external, release.
Architecture Overview
Module Layers
The project is a heavily modularized Android app (~220 modules) organized in layers:
app/— Application entry point, Hilt setup, navigation rootdomain/— Business logic and models. Each domain area (e.g.,tokens,wallets,card) has amodelssubmodule for pure data types and a core module for use casesdata/— Repository implementations and data sources, mirrors domain structurefeatures/— UI features using API/Impl split pattern:features:foo:apidefines the public contract,features:foo:implcontains the implementation. This enforces clean dependency boundariescore/— Cross-cutting concerns:ui,analytics,datasource,decompose,navigation,res,utils,security,paginationcommon/— Shared models, routing, UI components, test utilitieslibs/— SDK wrappers:blockchain-sdk,tangem-sdk-api,crypto,auth,visa
Component Architecture (Decompose)
The app uses Decompose for lifecycle-aware components. Every feature screen follows this structure:
API module (features/{name}/api/):
{Name}Componentinterface implementingComposableContentComponent- Inner
Paramsdata class for input parameters - Inner
Factoryinterface:fun create(context: AppComponentContext, params: Params): {Name}Component
Impl module (features/{name}/impl/):
Default{Name}Componentwith@AssistedInjectconstructor taking@Assisted appComponentContext: AppComponentContextand@Assisted params- Delegates
AppComponentContext by appComponentContext - Creates model via
getOrCreateModel(params) @Composable Content(modifier)collects model state viacollectAsStateWithLifecycle()- Inner
@AssistedFactoryinterface extending the publicFactory
Model (features/{name}/impl/.../model/):
{Name}ModelextendingModelbase class, annotated@ModelScoped, uses@Injectconstructor- Receives params via
ParamsContainer.require<ParamsType>() - Exposes
StateFlow<{Name}UM>(UM = UI Model, state class inui/state/subpackage) - Has
modelScope(SupervisorJob + mainImmediate), auto-cancelled on destroy
Child navigation within features:
childStack()— stacked screen navigation (back stack)childSlot()— optional overlays/bottom sheets (single or no child)InnerRouter— feature-internal navigation that delegates unknown routes to parent router
Feature Package Conventions
- API package:
com.tangem.features.{name}.api(pluralfeatures) - Impl package:
com.tangem.feature.{name}.impl(singularfeature— legacy inconsistency, follow existing pattern per feature) - Component:
{Name}Component(api),Default{Name}Component(impl) - Model:
{Name}Modelinmodel/subpackage - UI State:
{Name}UMinui/state/subpackage - UI Composable: in
ui/subpackage
Key Frameworks & Patterns
- DI: Hilt with
@SingletonComponentscope and custom@ModelScopedscope for model-lifecycle dependencies - UI: Jetpack Compose with Material3. Image loading via Coil
- Navigation: Custom
AppRouter+AppRoutesealed classes with deep link support viaDeepLinkBuilder - Networking: Retrofit + Moshi for API communication
- Local storage:
AppPreferencesStorefor key-value pairs,DataStorefor larger data - Async: Kotlin Coroutines + Flow. Inject
CoroutineDispatcherProvider(fromcore/utils) instead of usingDispatchers.*directly — providesmain,mainImmediate,io,default,single - Error handling: Arrow's
Either<Error, Success>pattern throughout domain/data layers.DataErrorsealed hierarchy for domain errors. Seedomain/core/CLAUDE.mdfor the LCE pattern - Analytics:
AnalyticsEvent(category, event, params)incore/analytics/models/. Feature events are sealed class hierarchies extendingAnalyticsEvent. Send via injectedAnalyticsEventHandler - Feature toggles:
FeatureTogglesManagerincore/config-toggles/. Toggles are defined incore/config-toggles/src/main/assets/configs/feature_toggles_config.jsonand auto-generated into aFeatureTogglesenum by the convention plugin at build time. Each feature module exposes its ownXxxFeatureTogglesinterface (inapi/) with aDefaultXxxFeatureTogglesimplementation (inimpl/) that delegates toFeatureTogglesManager - Supported languages:
SupportedLanguagesincore/utils/defines the app's supported locales: en, ru, de, fr, it, ja, uk, zh, es.getCurrentSupportedLanguageCode()returns the device locale if supported, otherwise falls back to English. Used by API calls that accept a language parameter
Build System
- Gradle 8.14.1, AGP 8.10.1, Kotlin 2.1.10
- Version catalogs:
gradle/dependencies.toml(external/third-party dependencies) andgradle/tangem_dependencies.toml(in-house Tangem SDK dependencies) - Convention plugin:
plugins/configuration/— applies Detekt, configures test settings, generates environment configs and feature toggles - Custom Detekt rules:
plugins/detekt-rules/. Detekt configuration is in thetangem-android-toolsgit submodule. Key rule:UnsafeStringResourceUsage— prevents directstringResource()/pluralStringResource()calls; use theSafe-suffixed variants instead - Localization: Managed via Lokalise. Update strings by running
python3 lokalize.py - GitHub Packages auth: Requires
gpr.userandgpr.keyinlocal.propertiesfor Tangem SDK dependencies
Testing
- JUnit 5 (Jupiter) for unit tests
- MockK for mocking
- Turbine for Flow testing
- Truth for assertions
- Marathon for UI tests (emulator-based, configured via
Marathonfile) - Shared test utilities in
common:testandtest/core/