6.9 KiB
6.9 KiB
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 parsingAuthInterceptor.kt— OkHttp interceptor injecting JWT from EncryptedSharedPreferencesErrorHandler.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
DAOinterfaces for each entity with CRUD operationsCacheManager.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
Parcelablewhere 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 requestsPendingRequestDao.kt— Room table for queued mutationsSyncManager.kt— Manages queue, triggers WorkManager on connectivity restore
android/app/src/main/java/com/shieldai/android/di/— Dependency injection:NetworkModule.kt— Retrofit/OkHttp setupDatabaseModule.kt— Room database providerRepositoryModule.kt— Repository bindings
steps:
- Add dependencies to
build.gradle.kts:- Retrofit:
com.squareup.retrofit2:retrofit,converter-gsonorconverter-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
- Retrofit:
- Create
TRPCApiService.kt:- Define POST endpoints for each tRPC procedure
- Request body:
{"0": {"json": { ... }}}(tRPC batch format for single call) - Response:
TRPCResponse<T>withresult.datafield - Use Kotlinx Serialization for JSON parsing
- Create data models:
- Kotlin data classes with
@Serializableannotation - Enum classes with
@Serializableand custom serializers if needed - Date parsing using
kotlinx.datetimeorjava.time.Instant
- Kotlin data classes with
- Create Room database:
ShieldAIDatabaseabstract class extendingRoomDatabase- Entity classes with
@Entity,@PrimaryKey,@ColumnInfo - DAO interfaces with
@Dao,@Query,@Insert,@Update,@Delete - Type converters for complex types (enums, dates, JSON)
- Create repositories:
- Each repository has
remoteDataSource(API service) andlocalDataSource(DAO) getData(): check cache first, if stale or missing → fetch remote → save to cache → return- Return
Flow<T>orsuspendfunctions withResult<T>
- Each repository has
- Create offline support:
PendingRequestentity:endpoint,method,body,timestamp,retryCountSyncManager: add request to pending queue when offlineOfflineWorker: periodic WorkManager task that processes pending requests- Network monitor using
ConnectivityManagerto trigger immediate sync
- Create DI modules:
NetworkModule: provideRetrofit,OkHttpClientwith auth interceptor and loggingDatabaseModule: provideShieldAIDatabasesingletonRepositoryModule: bind repository interfaces to implementations
- 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.meagainst 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:3000for emulator) - Call
user.me()and verify response parsed intoUsermodel - 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 testfor 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.registerDefaultNetworkCallbackis the modern approach (API 24+). - Use
Result<T>or sealed classes (Success,Error,Loading) for API state management in ViewModels.