# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview VBHelper is an Android app (Kotlin + Jetpack Compose) for interacting with Vital Bracelet series devices (VB, VH, VBC, VBBE) via NFC. It reads/writes characters, manages cards, tracks adventures, and handles cryptographic secrets for device communication. ## Build & Development Commands All Gradle commands require JDK 17. Set `JAVA_HOME` before building: ```bash export JAVA_HOME=/usr/lib/jvm/java-17-openjdk ``` ```bash # Build the project ./gradlew build # Run unit tests ./gradlew test # Run a single unit test class ./gradlew testDebugUnitTest --tests "com.github.nacabaro.vbhelper.ExampleUnitTest" # Run instrumented (Android device) tests ./gradlew connectedAndroidTest # Install debug APK ./gradlew installDebug # Lint check (has baseline in lint-baseline.xml) ./gradlew lint ``` Single-module project — all Gradle tasks target `:app`. ## Architecture **Pattern:** Controller-based screens with Repository data access and a manual service locator for DI. **Data flow:** Screen composables → Controller (interface + impl) → Repository → Room DAO → SQLite **Key architectural decisions:** - `DefaultAppContainer` (in `di/`) is the DI root — lazily creates the Room DB, DataStore instances, and all repositories. Accessed via `(application as VBHelper).container`. - Each major screen has a `Controller` interface and `ControllerImpl`. Controllers hold business logic and expose state via Kotlin Flow. - Cryptographic secrets (AES keys, HMAC keys, ciphers for device communication) are stored in Protocol Buffers via DataStore, not Room. - NFC operations use `vb-nfc-reader` library (0.2.0-SNAPSHOT from mavenLocal). Card parsing uses `vb-dim-reader`. - Pre-loaded item data ships in `app/src/main/assets/items.db`. **Source layout** (`app/src/main/java/com/github/nacabaro/vbhelper/`): | Directory | Purpose | |-----------|---------| | `di/` | App-level DI container and Application class | | `database/` | Room database, DAOs (11 DAOs, 17 entities) | | `domain/` | Domain model classes (card, characters, device_data, items) | | `source/` | Repositories (8) for data access | | `screens/` | Compose UI screens, each with its own Controller | | `navigation/` | Compose NavHost, route definitions, bottom nav bar | | `components/` | Shared UI components | | `dtos/` | Data transfer objects for screen-layer queries | | `utils/` | DeviceType enum, bitmap helpers | | `proto/` | Protobuf definitions for secrets | ## Key Technical Details - **Kotlin 2.3.0**, JVM target 11, Min SDK 28, Target/Compile SDK 36 - **Room** for structured data; **DataStore + Protobuf** for secrets; **DataStore Preferences** for currency/settings - **Compose Material 3** with dynamic color on Android 12+ - **KSP** for Room annotation processing; **Protobuf Gradle plugin** generates Java lite classes - `vb-nfc-reader` is resolved from `mavenLocal()` — must be installed locally to build - Version catalog in `gradle/libs.versions.toml` ## Conventions - **No ViewModel** — screens use the Controller pattern (interface + impl), not Android ViewModel - **No DI framework** — manual DI via `AppContainer`/`DefaultAppContainer`. Do not introduce Hilt, Dagger, or Koin - **Controller callback pattern** — Controllers expose callbacks (lambdas) to composables for user actions, and `Flow` for observable state - **Version catalog** — all dependency versions are declared in `gradle/libs.versions.toml`, never inline in `build.gradle.kts` ## Dangerous Operations The following modifications carry high risk and require careful consideration: - **`app/src/main/assets/items.db`** — Pre-loaded item database. Must stay in sync with Room schema. A mismatch crashes the app on fresh install. - **`app/src/main/proto/*.proto`** — Protobuf definitions for cryptographic secret storage. Changing field numbers or removing fields can make existing user secrets unreadable, effectively bricking their device pairing. - **`vb-nfc-reader` version** — Resolved from `mavenLocal()` as a SNAPSHOT. Changing the version requires the new version to be installed locally. Version mismatches cause build failures with confusing error messages. - **`gradlew` / `gradle/wrapper/`** — Managed by Gradle. Manual edits can break the build for all developers. Use `./gradlew wrapper --gradle-version=X.Y` to upgrade.