Skip to content

37 data layer and dagger di - #42

Merged
AlexisTercero55 merged 14 commits into
devfrom
37-data-layer-and-dagger-di
Aug 19, 2026
Merged

37 data layer and dagger di#42
AlexisTercero55 merged 14 commits into
devfrom
37-data-layer-and-dagger-di

Conversation

@AlexisTercero55

@AlexisTercero55 AlexisTercero55 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Development Iteration Report: Data Layer & DI Infrastructure

Iteration Overview

This iteration focused on transitioning the Rho Studio UI app from a manual to a DI system Key priorities included implementing a professional dependency injection using Dagger, establishing a secure Single Source of Truth (SSOT) data layer, and migrating the authentication workflow to production Firebase services.

Associated Issues:


Technical Implementation and File Analysis

1. Dependency Injection: High-Performance Multi-Tier DAG

We have successfully implemented a high-performance Multi-Tier Dependency Graph using Pure Dagger and KSP.

DI Conceptual Framework

To maintain a scalable architecture, we adhere to the following core DI concepts:

  • The Request (@Inject): Objects do not create their own dependencies. They "request" them via constructor injection, ensuring loose coupling and testability.
  • The Recipe (@Module): Dagger Modules act as recipe books, defining how to provide complex objects, interfaces, or library classes using @Provides and @Binds.
  • The Manager (@Component): Components act as the bridge between the providers (Modules) and consumers (Activities/ViewModels). They validate the graph at compile-time.
  • The Lifecycle (@Scope): Scopes (like @Singleton and @UserScope) ensure objects live exactly as long as their context (e.g., App lifecycle vs. User session).
  • Annotation Retention (@Retention): For Dagger, custom scopes and keys use AnnotationRetention.RUNTIME. This ensures the annotation metadata is available to the Dagger compiler and at runtime for reflected dependency resolution when necessary.
  • Multibinding Keys (@MapKey): Used in ViewModelKey.kt, this identifies which class type should be used as a Key in Dagger's internal Maps.
  • Lazy Provisioning (Provider<T>): Used in DaggerViewModelFactory, Provider<T>.get() allows the app to defer the actual creation of a ViewModel until it is requested by the UI, saving memory and startup time.
  • Kotlin Interop (@JvmSuppressWildcards): Dagger's Java-based compiler requires this to handle Kotlin's generic covariance/contravariance in collections like Map<Class, Provider>.
  • Architectural Boundary Control: We utilized Component Dependencies instead of Subcomponents. This enforces a strict professional contract between modules; Tier 2 and Tier 3 components only access dependencies that the CoreComponent explicitly chooses to expose. This prevents "Graph Leakage" and maintains the integrity of the Interface Segregation Principle.
  • ViewModel Multibinding & Lazy Provisioning: ViewModels are contributed to a centralized map via @IntoMap, allowing the DaggerViewModelFactory to instantiate them on-demand. This pattern supports Lazy Injection, where complex dependencies are only created at the moment of first use.
  • Binary Session Isolation: Orchestrated by the ComponentManager, the @UserScope graph is tied to the lifecycle of a specific object instance. Upon logout, this instance is destroyed, ensuring that the Double-Check Lock protected Singletons and all sensitive business logic are binary-purged from memory.

Structural Organization: Layered Hierarchy

Rho Studio UI utilizes Component Dependencies to organize the graph into three tiers, mirroring the application's lifecycle:

  1. Core Layer (CoreComponent):
    • Scope: @Singleton.
    • Role: Root infrastructure (Context, DataStore, SessionManager).
    • Hierarchy: The foundation; does not depend on other components.
  2. Application Layer (AppComponent):
    • Scope: @AppScope.
    • Role: Manages "Public" states and global logic.
    • Hierarchy: Depends on CoreComponent. Orchestrates AuthModule (Pre-Login ViewModels) and UIModule (Shared ViewModels).
  3. User Session Layer (UserComponent):
    • Scope: @UserScope.
    • Role: Manages authenticated features (Home, Profile).
    • Hierarchy: Depends on CoreComponent. Orchestrates HomeModule (Post-Login ViewModels) and UIModule.
    • Isolation: Created dynamically upon login and binary-purged from memory upon logout to ensure session security.

ViewModel Multibinding Strategy

We utilize Dagger Multibindings (@IntoMap) to centralize ViewModel provisioning. This process operates in three automated stages:

  1. Contribution (The Modules): Feature modules (e.g., AuthModule, UIModule) contribute their ViewModels to a central registry using @Binds, @IntoMap, and a custom @ViewModelKey.
  2. Aggregation (The Component): During compilation, Dagger scans all modules within a component and aggregates these contributions into a generated internal Map (e.g., Map<Class<? extends ViewModel>, Provider<ViewModel>>).
  3. Resolution (The Factory): The DaggerViewModelFactory injects this map and performs an on-demand lookup. This allows the UI to request any ViewModel by its class type without the factory requiring manual updates (adhering to the Open/Closed Principle).

Hierarchy Isolation:
One of the most powerful features of this architecture is that Dagger builds unique internal Maps for each component, ensuring strict data and logic isolation based on the user's state:

Component Modules Included Resulting Internal Map
AppComponent AuthModule, UIModule {LoginViewModel, HeaderViewModel}
UserComponent HomeModule, UIModule {HomeViewModel, HeaderViewModel}
  • Security & Isolation: When the app is in the UserComponent (logged in), the Map does not contain LoginViewModel. Dagger prevents accidental instantiation of pre-auth logic in a post-auth context.
  • Reusability: HeaderViewModel is defined once in UIModule but is automatically "aggregated" into both maps because both components include the module.

The Strategic Benefit of Multibinding

By using Dagger Multibindings, we adhere to the Open/Closed Principle. The DaggerViewModelFactory is "Open" for extension (you can add new ViewModels) but "Closed" for modification (you never need to edit the factory code itself).

Traditional (Brittle) Approach:

// The OLD way: Requires manual updates for every new screen
override fun <T : ViewModel> create(modelClass: Class<T>): T {
    return when {
        modelClass.isAssignableFrom(LoginViewModel::class.java) -> LoginViewModel(authRepo) as T
        modelClass.isAssignableFrom(HomeViewModel::class.java) -> HomeViewModel(sessionRepo) as T
        else -> throw IllegalArgumentException("Unknown ViewModel class")
    }
}

The Dagger Way (Scalable):
The factory remains a generic "black box" that performs a Map lookup. Adding a new feature simply requires adding a @Binds method in a new Dagger Module. The dependency graph auto-populates during compilation, eliminating human error in factory wiring.

Performance Optimization: Companion Object Provides

In CoreModule.kt, we use Kotlin companion object for @Provides methods. This is an intentional optimization:

  • Static Generation: Dagger generates static methods in Java bytecode when @Provides is inside a companion object, avoiding the overhead of instantiating the Module class itself.

  • Architectural Boundary Control: We utilized Component Dependencies instead of Subcomponents. This enforces a strict professional contract between modules; Tier 2 and Tier 3 components only access dependencies that the CoreComponent explicitly chooses to expose. This prevents "Graph Leakage" and maintains the integrity of the Interface Segregation Principle.

  • Static Directed Acyclic Graph (DAG): By leveraging Dagger's static code generation, we moved all dependency validation to Compile-Time. This guarantees a crash-free dependency retrieval at runtime and optimizes startup performance by eliminating classpath scanning.

Related Files:

  • MODIFY [:app] [MainActivity.kt]: Refactored to use reactive viewModel() provisioning and bootstrapped Dagger injection.
  • NEW [:app] [RhoStudioUIApp.kt]: Custom Application class for Firebase and DI initialization.
  • NEW [:app] [di/AppComponent.kt]: Root application component orchestrating Auth and Common UI modules.
  • NEW [:app] [di/UserComponent.kt]: Session-scoped component for authenticated features.
  • NEW [:app] [di/ComponentManager.kt]: Centralized logic for component lifecycle orchestration.
  • NEW [:core:ui] [di/DaggerViewModelFactory.kt]: Generic factory for Dagger ViewModel multibinding.
  • NEW [:core:ui] [di/Scopes.kt] / [di/ViewModelKey.kt]: Annotations for hierarchical scoping.

2. Data Layer Evolution: Reactive SSOT

The data layer was refactored to prioritize transactional integrity and thread-safety using a reactive stream for session truths.

  • Architectural Split: Relocated the SessionRepository interface to the Domain module, adhering to the Dependency Inversion Principle and ensuring the Domain remains pure.
  • Jetpack DataStore Migration: Replaced legacy SharedPreferences with a reactive, coroutine-based DataStore implementation for session persistence.
  • Atomic Session State: Introduced a sealed SessionState (Checking, Authenticated, Guest) within SessionManager to eliminate illegal UI transitions and synchronization bugs.

Related Files:

  • MODIFY [:core:data] [manager/SessionManager.kt]: Transitioned from Singleton to injectable class with sealed SessionState.
  • MODIFY [:core:data] [repository/SessionRepositoryImpl.kt]: Implemented Jetpack DataStore for reactive persistence.
  • NEW [:core:domain] [repository/SessionRepository.kt]: Relocated contract to ensure dependency inversion.
  • NEW [:core:domain] [model/SessionState.kt]: Sealed class defining the global user session state machine.
  • NEW [:core:data] [di/CoreComponent.kt] / [di/CoreModule.kt]: Infrastructure graph root.

3. Production Authentication and Infrastructure

The authentication feature has been cut over from development mocks to a robust cloud infrastructure with integrated telemetry.

  • Firebase SDK Abstraction: Implemented FirebaseRemoteDataSource and AnalyticsRemoteDataSource as thread-safe wrappers, ensuring the core data module remains testable and decoupled from the external SDKs.
  • Decoupled Remote Data Source: Introduced FirebaseRemoteDataSource as a thread-safe wrapper for the FirebaseAuth SDK. This ensures that feature modules remain isolated from the specific implementation details of the auth provider.
  • Repository Implementation: AuthRepositoryImpl now bridges the Domain layer's login request to the Firebase backend, providing a clean separation between business logic and infrastructure.
  • Simplified Model Integrity: Refactored Credentials.kt to balance domain purity with maintainability, utilizing standard String fields backed by reactive Regex validation.
  • Dynamic User Profiles: Implemented fallback logic to extract display names from user emails when the Firebase displayName is null, ensuring consistent UI headers.

Telemetry and Analytics

  • Analytics Integration: Integrated AnalyticsRemoteDataSource directly into the authentication flow. Every successful login triggers an automated telemetry event, providing immediate visibility into app adoption and user activity.
  • DI Scoping for Infrastructure: Firebase instances (FirebaseAuth, FirebaseAnalytics) are managed as @Singleton objects within the CoreModule, ensuring efficient resource reuse across both the AppComponent and UserComponent.

Related Files:

  • MODIFY [:core:data] [repository/AuthRepositoryImpl.kt]: Switched to production FirebaseRemoteDataSource.
  • NEW [:core:data] [remote/FirebaseRemoteDataSource.kt]: Thread-safe wrapper for FirebaseAuth SDK.
  • NEW [:core:data] [remote/AnalyticsRemoteDataSource.kt]: Thread-safe wrapper for FirebaseAnalytics SDK.
  • MODIFY [:core:domain] [model/Credentials.kt]: Simplified data model for maintainability.

4. Critical Fixes and Stability Optimization

  • Race Condition Mitigation: Refactored MainActivity from lateinit ViewModel initialization to Compose-native viewModel(factory = ...) provisioning. This resolved a critical UninitializedPropertyAccessException during navigation.
  • Operational Orchestration: Wired the NavHost to reactively switch DI providers based on the live session state, ensuring user data is injected only when authorized.

Terminal Verification Suite (Automated)

The following automated tests have passed with 100% success rate:

  • DI Graph Audit (DaggerGraphTest): Verifies all components and providers (Firebase, Analytics) are correctly satisfied.
  • Transactional Integrity (SessionManagerTest): Validates atomic state flow and DataStore synchronization.
  • Business Logic (LoginUseCaseTest, LogoutUseCaseTest): 90%+ coverage of core transactions using MockK.
  • CI/CD Build: Verified on GitHub Actions including google-services.json integration.

Manual QA Test Plan (Instructions for Reviewers)

Scenario 1: Fresh Install / First Launch

  1. Open the app.
  2. Expected: App shows LoadingScreen (CircularProgress), then transitions to Login Screen once session check is complete.

Scenario 2: Successful Login & Data Loading

  1. Enter valid Firebase credentials.
  2. Click "Login".
  3. Expected:
    • Circular progress overlay appears.
    • On success, toast "Login successful!" appears.
    • UI transitions to Home Screen.
    • Header displays correct user email/name.

Scenario 3: Secure Logout & Session Isolation

  1. On the Home Screen, click "Logout".
  2. Expected:
    • UI transitions immediately back to Login Screen.
    • User input fields in Login are cleared (form reset).
    • Verification: Using Android Profiler, confirm that @UserScope objects (e.g., HomeViewModel) are cleared from heap.

Regression Checklist for QA

  • Verify that no UninitializedPropertyAccessException occurs during rapid Login/Logout cycles.
  • Verify that the PageHeader reactively updates when a new user logs in.
  • Confirm that Firebase Analytics events are visible in DebugView.

Final Status: Domain and Data Layer Ready for Production

The Rho Studio UI application is achieving architectural and operational stability.


Further Work: UX Refinement & Fintech Hardening

Before developing more UI features, the following hardening and UX improvements are planned:

  1. UX/UI Refinement (Auth Feature):

    • Flexible Password Policy: Shift from hard validation to proactive warnings for login, while maintaining strict rules for signup.
    • Enhanced Feedback: Implement more granular error mapping for Firebase-specific authentication failures.
  2. Domain Extension:

    • SignupUseCase: Implement a new domain interactor for user signup (Firebase Email/Password).
    • Value Object Restoration: Re-introduce Value Objects for signup-specific validation (e.g., complexity requirements).
  3. Fintech Security Hardening:

    • Encrypted Persistence: Upgrade the current DataStore implementation to utilize Tink-based encryption for all PII.
    • Environment Integrity: Integrate Root & Emulator detection to safeguard sensitive financial transactions.
    • Biometric Integration: Establish a foundation for Biometric Prompt orchestration within the SessionManager.

Rho.Studio® - Engineering team

- Scopes.
- Modules.
- Components.
- Remote data sources (firebase).
- Repository implementations.
- RhoStudioUIApp.kt : Init firebase and Dagger ComponentManager.
- MainActivity.kt : DI configuration and session based navigation.
- Define possible states of a user session.
Signed-off-by: Alexis Tercero <alexistercero55@gmail.com>
Signed-off-by: Alexis Tercero <alexistercero55@gmail.com>
Signed-off-by: Alexis Tercero <alexistercero55@gmail.com>
- DevIteration completed

Signed-off-by: Alexis Tercero <alexistercero55@gmail.com>
Signed-off-by: Alexis Tercero <alexistercero55@gmail.com>
@AlexisTercero55 AlexisTercero55 self-assigned this Aug 19, 2026
@AlexisTercero55 AlexisTercero55 added Auth-feature UI compose feature - LoginViewModel Core Rho Studio UI app codebase Domain layer Use cases of business flow Data layer Repository and data sources Dagger DI Dagger2 Dependency injection labels Aug 19, 2026
@AlexisTercero55 AlexisTercero55 moved this from Backlog to In progress in UI-Rho-Studio-Components Aug 19, 2026

@alexistercero-rho-dev alexistercero-rho-dev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dagger hierarchy reviwed

Android Debug CI/CD Rho.Studio®

Comment thread app/src/main/java/com/rho/studio/ui/di/ComponentManager.kt
Comment thread app/src/main/java/com/rho/studio/ui/di/UserComponent.kt
@AlexisTercero55
AlexisTercero55 merged commit f6648b7 into dev Aug 19, 2026
2 checks passed
@github-project-automation github-project-automation Bot moved this from In progress to Done in UI-Rho-Studio-Components Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Auth-feature UI compose feature - LoginViewModel Core Rho Studio UI app codebase Dagger DI Dagger2 Dependency injection Data layer Repository and data sources Domain layer Use cases of business flow

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Firebase authentication Data Layer definition Dagger DI PLAN | Data Layer and Dagger DI

2 participants