# 37. Android App — API Client, tRPC Bridge, and Offline Support

meta:
  id: shieldai-unified-restructure-37
  feature: shieldai-unified-restructure
  priority: P1
  depends_on: [shieldai-unified-restructure-34, shieldai-unified-restructure-35, shieldai-unified-restructure-36]
  tags: [android, kotlin, api, networking, offline, mobile]

objective:
- Build the API client layer for the Android app that communicates with the unified monolith's tRPC endpoints. Use a thin HTTP bridge approach with Retrofit or Ktor Client, plus offline support with Room caching and WorkManager request queuing.

deliverables:
- `android/app/src/main/java/com/shieldai/android/data/remote/` — Remote data layer:
  - `TRPCApiService.kt` — Retrofit interface or Ktor client defining all tRPC endpoints:
    - `@POST("api/trpc/user.me")`, `@POST("api/trpc/darkwatch.getWatchlist")`, etc.
    - Request/response wrappers for tRPC batch format
  - `TRPCResponse.kt` / `TRPCError.kt` — Data classes for tRPC response/error parsing
  - `AuthInterceptor.kt` — OkHttp interceptor injecting JWT from EncryptedSharedPreferences
  - `ErrorHandler.kt` — Centralized error handling with retry logic
- `android/app/src/main/java/com/shieldai/android/data/local/` — Local data layer:
  - `ShieldAIDatabase.kt` — Room database with entities:
    - `UserEntity`, `SubscriptionEntity`, `WatchlistItemEntity`, `ExposureEntity`, `AlertEntity`, `VoiceEnrollmentEntity`, `VoiceAnalysisEntity`, `SpamRuleEntity`, `PropertyEntity`, `RemovalRequestEntity`, `BrokerListingEntity`
  - `DAO` interfaces for each entity with CRUD operations
  - `CacheManager.kt` — TTL-based cache logic using Room
- `android/app/src/main/java/com/shieldai/android/data/repository/` — Repository layer:
  - `UserRepository.kt`, `DarkWatchRepository.kt`, `VoicePrintRepository.kt`, etc.
  - Each repository: remote fetch → cache to Room → return flow/coroutine
  - `RepositoryModule.kt` — Hilt module for DI
- `android/app/src/main/java/com/shieldai/android/data/model/` — Data models:
  - `User.kt`, `Subscription.kt`, `WatchlistItem.kt`, `Exposure.kt`, `Alert.kt`, etc.
  - All models as Kotlin data classes with `Parcelable` where needed
  - Enum classes matching backend enums
- `android/app/src/main/java/com/shieldai/android/data/sync/` — Offline support:
  - `OfflineWorker.kt` — WorkManager worker for retrying queued requests
  - `PendingRequestDao.kt` — Room table for queued mutations
  - `SyncManager.kt` — Manages queue, triggers WorkManager on connectivity restore
- `android/app/src/main/java/com/shieldai/android/di/` — Dependency injection:
  - `NetworkModule.kt` — Retrofit/OkHttp setup
  - `DatabaseModule.kt` — Room database provider
  - `RepositoryModule.kt` — Repository bindings

steps:
1. Add dependencies to `build.gradle.kts`:
   - Retrofit: `com.squareup.retrofit2:retrofit`, `converter-gson` or `converter-kotlinx-serialization`
   - OkHttp: `logging-interceptor`
   - Room: `androidx.room:room-runtime`, `room-ktx`, `room-compiler`
   - WorkManager: `androidx.work:work-runtime-ktx`
   - Hilt: `com.google.dagger:hilt-android`, `hilt-compiler`
   - Kotlinx Serialization: `org.jetbrains.kotlinx:kotlinx-serialization-json`
2. Create `TRPCApiService.kt`:
   - Define POST endpoints for each tRPC procedure
   - Request body: `{"0": {"json": { ... }}}` (tRPC batch format for single call)
   - Response: `TRPCResponse<T>` with `result.data` field
   - Use Kotlinx Serialization for JSON parsing
3. Create data models:
   - Kotlin data classes with `@Serializable` annotation
   - Enum classes with `@Serializable` and custom serializers if needed
   - Date parsing using `kotlinx.datetime` or `java.time.Instant`
4. Create Room database:
   - `ShieldAIDatabase` abstract class extending `RoomDatabase`
   - Entity classes with `@Entity`, `@PrimaryKey`, `@ColumnInfo`
   - DAO interfaces with `@Dao`, `@Query`, `@Insert`, `@Update`, `@Delete`
   - Type converters for complex types (enums, dates, JSON)
5. Create repositories:
   - Each repository has `remoteDataSource` (API service) and `localDataSource` (DAO)
   - `getData()`: check cache first, if stale or missing → fetch remote → save to cache → return
   - Return `Flow<T>` or `suspend` functions with `Result<T>`
6. Create offline support:
   - `PendingRequest` entity: `endpoint`, `method`, `body`, `timestamp`, `retryCount`
   - `SyncManager`: add request to pending queue when offline
   - `OfflineWorker`: periodic WorkManager task that processes pending requests
   - Network monitor using `ConnectivityManager` to trigger immediate sync
7. Create DI modules:
   - `NetworkModule`: provide `Retrofit`, `OkHttpClient` with auth interceptor and logging
   - `DatabaseModule`: provide `ShieldAIDatabase` singleton
   - `RepositoryModule`: bind repository interfaces to implementations
8. Test all layers with mocked dependencies.

steps:
- Unit: Retrofit service creates correct HTTP requests
- Unit: Room DAO inserts and retrieves entities correctly
- Unit: Repository returns cached data when offline
- Unit: SyncManager queues requests when network unavailable
- Integration: API client successfully calls `user.me` against local dev server

acceptance_criteria:
- [ ] Retrofit/Ktor client makes authenticated HTTP requests to tRPC endpoints
- [ ] tRPC response format is correctly parsed into Kotlin data classes
- [ ] Room database caches API responses with TTL-based invalidation
- [ ] Offline mutations are queued and retried when connectivity restored
- [ ] All common API procedures have type-safe Kotlin wrappers
- [ ] Network errors trigger retry with exponential backoff
- [ ] Repository layer provides clean abstraction over remote and local data
- [ ] Hilt dependency injection is configured for all layers
- [ ] API configuration supports different environments (dev, staging, prod)

validation:
- Point API client to local dev server (`http://10.0.2.2:3000` for emulator)
- Call `user.me()` and verify response parsed into `User` model
- Disconnect network, attempt a mutation, verify it queues in Room
- Reconnect network, verify WorkManager processes queued request
- Verify cache hit by calling same endpoint twice with network disabled
- Run `./gradlew test` for unit tests

notes:
- Retrofit with Kotlinx Serialization is the recommended stack. Gson works too but Kotlinx Serialization has better null safety.
- For tRPC, the Android client cannot use tRPC's type-safe client directly. The HTTP bridge is the pragmatic approach.
- The tRPC batch link sends multiple procedures in one HTTP request. For simplicity, use single-procedure requests.
- Room database schema should mirror the Drizzle schema closely, but can be simplified (fewer columns) for caching purposes.
- WorkManager requires `androidx.work:work-runtime-ktx`. It handles background execution reliably across Android versions.
- For network monitoring, `ConnectivityManager.registerDefaultNetworkCallback` is the modern approach (API 24+).
- Use `Result<T>` or sealed classes (`Success`, `Error`, `Loading`) for API state management in ViewModels.
