add CLAUDE.md
This commit is contained in:
parent
749427f4d8
commit
580bc993cc
88
CLAUDE.md
Normal file
88
CLAUDE.md
Normal file
@ -0,0 +1,88 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project
|
||||
|
||||
Heimdall is an Android password manager (Jetpack Compose, Kotlin) that also acts as a
|
||||
system **Autofill service**. Users register/login against a remote backend, then store and
|
||||
retrieve credentials locally in an encrypted vault.
|
||||
|
||||
## Build & Test
|
||||
|
||||
```bash
|
||||
./gradlew assembleDebug # build debug APK
|
||||
./gradlew installDebug # build + install on connected device/emulator
|
||||
./gradlew test # JVM unit tests (src/test)
|
||||
./gradlew connectedAndroidTest # instrumented tests on device (src/androidTest)
|
||||
./gradlew lint # Android lint
|
||||
|
||||
# single unit test class / method:
|
||||
./gradlew test --tests "com.longnh15.heimdall.SomeTest"
|
||||
./gradlew test --tests "com.longnh15.heimdall.SomeTest.someMethod"
|
||||
```
|
||||
|
||||
- Single-module project (`:app`). Dependencies are managed via the version catalog
|
||||
`gradle/libs.versions.toml` — add/upgrade libraries there, not inline in `build.gradle.kts`.
|
||||
- minSdk 26, targetSdk/compileSdk 37, Java 11.
|
||||
|
||||
## Architecture
|
||||
|
||||
Clean-architecture-style layering under `app/src/main/java/com/longnh15/heimdall/`:
|
||||
|
||||
- **`domain/`** — interfaces + models, no Android/framework deps. `repository/` holds repo
|
||||
interfaces, `model/` holds domain types (`ApiResult`, `AuthInfo`, `Credential`), `vault/`
|
||||
holds the session abstraction.
|
||||
- **`data/`** — implementations. `repository/*Impl` implement domain interfaces; `source/remote`
|
||||
is Retrofit (`ApiService` + `dto/`); `source/local` is Room (`HeimdallDatabase`, `CredentialDao`,
|
||||
`entity/` + mappers) plus DataStore; `preferences/` and `vault/` hold other impls.
|
||||
- **`ui/`** — Compose screens grouped by feature (`auth/login`, `auth/register`, `onboarding`,
|
||||
`vault`, `vault/edit`). Each feature follows MVVM: `*Screen` (Compose) + `*ViewModel` +
|
||||
`*State` + `*Event` (user intents). State is exposed as `StateFlow` via `stateIn`.
|
||||
- **`navigation/`** — `Screen` is a `@Serializable sealed class`; routes are type-safe Compose
|
||||
Navigation destinations wired in `HeimdallNavGraph`.
|
||||
|
||||
Key cross-cutting flows:
|
||||
|
||||
- **Network**: repositories extend `BaseRepository` and wrap calls in `safeApiCall { ... }`,
|
||||
which converts a Retrofit `Response` into `ApiResult.Success`/`ApiResult.Error`. Error bodies
|
||||
are parsed by `ErrorBodyParser.toApiError()`. JSON config lives in `common/GlobalConfig.json`.
|
||||
Base URL is hardcoded in `di/NetworkModule`.
|
||||
- **Auth tokens**: on login, the token is encrypted with `common/TokenCrypto` (AES/GCM key in
|
||||
the Android Keystore, IV prepended) and persisted in the `"terces"` DataStore via
|
||||
`LocalDataSource`. Never store the token in plaintext.
|
||||
- **Vault locking**: `VaultSessionManager` (impl in `data/vault`) holds an in-memory
|
||||
`Locked`/`Unlocked(expiredAt)` `StateFlow`. `HeimdallApplication` observes
|
||||
`ProcessLifecycleOwner` and calls `refreshSession()` on app foreground, re-locking after the
|
||||
timeout. ViewModels read `sessionState` to gate access. (Timeout is currently 5 seconds —
|
||||
`TIMEOUT_DURATION` in `VaultSessionManagerImpl`.)
|
||||
- **Autofill**: `HeimdallAutofillService` (registered in the manifest, BIND_AUTOFILL_SERVICE)
|
||||
receives an `AssistStructure`; `StructureParser` classifies username/password fields using a
|
||||
layered heuristic (autofillHints → inputType → htmlInfo → text/hint keyword matching). The
|
||||
fill values in `buildFillResponse` are currently **hardcoded placeholders**, not yet wired to
|
||||
the vault.
|
||||
- **First launch / onboarding**: `MainViewModel` reads `PreferenceDataSource` (`"settings"`
|
||||
DataStore) to decide the nav start destination (Onboarding vs Login); the splash screen is held
|
||||
until that flag resolves to avoid a flicker.
|
||||
|
||||
## Dependency Injection (Koin) — note the inconsistency
|
||||
|
||||
DI is **mid-migration between two Koin styles**, and only one is actually loaded:
|
||||
|
||||
- `HeimdallApplication.startKoin` loads **only** the manual `appModule` (`di/AppModule.kt`),
|
||||
which uses the DSL (`single<Impl>() bind Interface::class`, `viewModel<...>()`).
|
||||
- Other files use **Koin annotations** (`@Module`, `@Single` in `NetworkModule`/`DatabaseModule`,
|
||||
`@KoinViewModel`, `@Singleton`) which require the KSP-generated module to be included to take
|
||||
effect. These are **not currently passed to `startKoin`**.
|
||||
|
||||
When adding a dependency, prefer registering it in `appModule` so it is actually wired, or
|
||||
explicitly include the annotation-generated modules in `startKoin`. Don't assume an `@Single`
|
||||
annotation alone makes a class injectable here.
|
||||
|
||||
## Conventions
|
||||
|
||||
- Room schemas are exported to `app/schemas/`; bump the DB version and commit the new schema JSON
|
||||
when changing entities.
|
||||
- DTOs (`data/source/remote/dto`) use `kotlinx.serialization` (`@Serializable`); domain models are
|
||||
separate types — map between them in the repository.
|
||||
- Validation lives in `common/ValidationHelper`.
|
||||
Loading…
x
Reference in New Issue
Block a user