Pre release v103 - #45
Merged
Merged
Conversation
Signed-off-by: Alexis Tercero <alexistercero55@gmail.com>
Signed-off-by: Alexis Tercero <alexistercero55@gmail.com>
Signed-off-by: Alexis Tercero <alexistercero55@gmail.com>
Signed-off-by: Alexis Tercero <alexistercero55@gmail.com>
Signed-off-by: Alexis Tercero <alexistercero55@gmail.com>
4 tasks
alexistercero-rho-dev
approved these changes
Aug 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Technical Report: Rho Studio UI
An Android Jetpack Compose app.
Enterprise-Grade Android Architecture with Jetpack Compose
This document provides a comprehensive technical overview of the Rho Studio UI application. It serves as the primary architectural reference for developers, outlining the system's design, layer responsibilities, and technical standards.
1. Executive Summary
Rho Studio UI is the base application template designed to establish and enforce the Rho Studio Android App Standards. It provides a robust foundation for building secure, authenticated mobile experiences within the Rho Studio ecosystem.
The application is a Jetpack Compose implementation following a Single-Activity Architecture, leveraging a reactive MVVM (Model-View-ViewModel) pattern, implementing a Multi-Tier Dagger Hierarchy and a fluid user experience driven by Unidirectional Data Flow (UDF). This architectural foundation ensures a focus on Fluid UX, Transactional Integrity, and Decoupled Business Logic.
Important
In order to add a new feature: See CONTRIBUTING.md.
Core Features:
2. Architectural Framework
The application follows a Single-Activity Architecture and is structured according to Clean Architecture principles. It utilizes a Feature-Layered Modularization strategy to ensure scalability and maintainability.
2.1 Layered Structure
The system follows the three layers Google's recommendations:
graph TD subgraph UI["UI Layer (Presentation)"] UI_Screens[Jetpack Compose Screens] VM[ViewModels] Nav[Navigation / NavHost] end subgraph Domain["Domain Layer (Business Logic)"] UC[Use Cases / Interactors] Entities[Domain Entities] Int[Repository Interfaces] end subgraph Data["Data Layer (Infrastructure)"] Repo[Repository Implementations] SM[Session Manager / SSOT] Local[Local / Network Data Sources] end UI_Screens --> VM VM --> UC UC --> Entities UC --> Int Repo -.-> Int Repo --> SM Repo --> Local linkStyle default stroke:#D32F2F,stroke-width:2px classDef uiNode fill:#4A4A4A,stroke:#D32F2F,color:#FFFFFF classDef domainNode fill:#333333,stroke:#D32F2F,color:#FFFFFF classDef dataNode fill:#333333,stroke:#D32F2F,color:#FFFFFF class UI_Screens,VM,Nav uiNode class UC,Entities,Int domainNode class Repo,SM,Local dataNode style UI fill:#333333,stroke:#D32F2F,color:#FFFFFF style Domain fill:#4A4A4A,stroke:#333333,color:#FFFFFF style Data fill:#D3D3D3,stroke:#D32F2F,color:#0000002.2 Multi-Module Topology
The project is split into granular Gradle modules to improve build parallelization and enforce boundaries.
flowchart TD APP[":app<br/>MainActivity, NavHost"] AUTH[":features:auth<br/>LoginScreen, LoginViewModel"] HOME[":features:home<br/>HomeScreen, HomeViewModel"] UI_CORE[":core:ui<br/>Theme, Common Composables"] DOMAIN[":core:domain<br/>Use Cases, Models, Contracts"] DATA[":core:data<br/>Repositories, SessionManager"] APP --> AUTH APP --> HOME AUTH --> UI_CORE AUTH --> DOMAIN HOME --> UI_CORE HOME --> DOMAIN UI_CORE --> DOMAIN DOMAIN -.->|"implemented by"| DATA linkStyle default stroke:#D32F2F,stroke-width:2px classDef appNode fill:#D32F2F,stroke:#FFFFFF,color:#FFFFFF classDef featureNode fill:#4A4A4A,stroke:#D32F2F,color:#FFFFFF classDef coreNode fill:#333333,stroke:#D32F2F,color:#FFFFFF classDef domainNode fill:#333333,stroke:#D32F2F,color:#FFFFFF classDef dataNode fill:#333333,stroke:#D32F2F,color:#FFFFFF class APP appNode class AUTH,HOME featureNode class UI_CORE coreNode class DOMAIN domainNode class DATA dataNode style APP fill:#D32F2F,stroke:#FFFFFF,color:#FFFFFF style AUTH fill:#4A4A4A,stroke:#D32F2F,color:#FFFFFF style HOME fill:#4A4A4A,stroke:#D32F2F,color:#FFFFFF style UI_CORE fill:#333333,stroke:#D32F2F,color:#FFFFFF style DOMAIN fill:#4A4A4A,stroke:#333333,color:#FFFFFF style DATA fill:#D3D3D3,stroke:#D32F2F,color:#000000Tip
:featuresdepend only on:coremodules (:core:domain,:core:ui), preventing circular dependencies. Feature-specific models remain within their respective feature modules.2.3 Multi-Tier Dependency Injection (Dagger 2 + KSP)
We utilize a high-performance Directed Acyclic Graph (DAG) generated at compile-time using KSP to ensure zero runtime overhead. The graph is organized into three tiers to mirror the application lifecycle:
DI Conceptual Framework
@Injectconstructor@Modulewith@Provides/@Binds@Component@Scope(e.g.,@Singleton,@UserScope)@Retention(AnnotationRetention.RUNTIME)@MapKeyProvider<T>@JvmSuppressWildcardsMulti-Tier Component Dependency Architecture
flowchart TB subgraph Core["CoreComponent (@Singleton)"] direction TB CTX["Context (Application)"] DS["DataStore"] SM["SessionManager"] FA["FirebaseAuth"] FAN["FirebaseAnalytics"] end subgraph App["AppComponent (@AppScope)"] direction TB AM["AuthModule"] UM["UIModule"] LoginVM["LoginViewModel"] end subgraph User["UserComponent (@UserScope)"] direction TB HM["HomeModule"] UM2["UIModule (Reused)"] HomeVM["HomeViewModel"] HeaderVM["HeaderViewModel"] end Core -->|"Component Dependency"| App Core -->|"Component Dependency"| User AM -->|"Contains"| LoginVM AM -->|"Contains"| UM HM -->|"Contains"| HomeVM HM -->|"Contains"| HeaderVM HM -->|"Contains"| UM2 linkStyle default stroke:#D32F2F,stroke-width:2px classDef coreNode fill:#4A4A4A,stroke:#D32F2F,color:#FFFFFF classDef appNode fill:#333333,stroke:#D32F2F,color:#FFFFFF classDef userNode fill:#333333,stroke:#D32F2F,color:#FFFFFF class CTX,DS,SM,FA,FAN coreNode class AM,UM,LoginVM,HeaderVM appNode class HM,UM2,HomeVM,HeaderVM2 userNode style Core fill:#333333,stroke:#D32F2F,color:#FFFFFF style App fill:#4A4A4A,stroke:#333333,color:#FFFFFF style User fill:#D3D3D3,stroke:#D32F2F,color:#000000Core Tier (
CoreComponent):@Singleton.App Tier (
AppComponent):User Tier (
UserComponent):@UserScope.HomeModule(Post-Login ViewModels) andUIModule.2.4 ViewModel Multibinding Strategy
To decouple the UI from DI wiring, we implement a centralized registry using
@IntoMap:flowchart TB subgraph Contribution["Step 1: Contribution"] M1["AuthModule"] --> B1["@Binds LoginViewModel"] M2["UIModule"] --> B2["@Binds HeaderViewModel"] M3["HomeModule"] --> B3["@Binds HomeViewModel"] end subgraph Aggregation["Step 2: Aggregation"] M1 --> Map["Internal Map<br/>Map<Class, Provider<ViewModel>>"] M2 --> Map M3 --> Map end subgraph Resolution["Step 3: Resolution"] Map --> Factory["DaggerViewModelFactory"] Factory --> UI["UI requests ViewModel by Class"] end Contribution --> Aggregation --> Resolution linkStyle default stroke:#D32F2F,stroke-width:2px classDef contributionNode fill:#4A4A4A,stroke:#D32F2F,color:#FFFFFF classDef aggregationNode fill:#333333,stroke:#D32F2F,color:#FFFFFF classDef resolutionNode fill:#333333,stroke:#D32F2F,color:#FFFFFF class M1,B1,M2,B2,M3,B3 contributionNode class Map aggregationNode class Factory,UI resolutionNode style Contribution fill:#333333,stroke:#D32F2F,color:#FFFFFF style Aggregation fill:#4A4A4A,stroke:#333333,color:#FFFFFF style Resolution fill:#D3D3D3,stroke:#D32F2F,color:#000000Key Principles:
AuthModule,UIModule{LoginViewModel, HeaderViewModel}HomeModule,UIModule{HomeViewModel, HeaderViewModel}3. Layer Detail & Responsibilities
3.1 UI Layer (Presentation)
Goal: Transform application state into a visual interface and handle user interactions.
StateFlow, exposing it to the UI in a lifecycle-aware manner.MainActivityusesLaunchedEffectkeyed to authentication state, transforming state changes into one-time navigation events.MainActivity.kt: The entry point and navigation orchestrator.LoginViewModel.kt&HomeViewModel.kt: Feature-specific state holders.BaseViewModel.kt: Provides shared logic for loading states, error handling, and navigation side-effects.HeaderViewModel.kt: BridgesSessionManagerstate to common UI componentsflowchart TB subgraph Navigation["Navigation Orchestration"] MA["MainActivity.kt<br/>- NavHost<br/>- Session-based routing"] end subgraph Shared["Shared UI Components"] PV["BaseViewModel.kt<br/>- launchSafe<br/>- isLoading state"] HV["HeaderViewModel.kt<br/>- Session state bridging"] PH["PageHeader.kt"] end subgraph Auth["Authentication Feature"] LS["LoginScreen.kt"] LVM["LoginViewModel.kt"] end subgraph Home["Home Feature"] HS["HomeScreen.kt"] HVM["HomeViewModel.kt"] end MA --> LS MA --> HS LS --> LVM HS --> HVM LVM --> PV HVM --> PV HV --> PV linkStyle default stroke:#D32F2F,stroke-width:2px classDef navNode fill:#D32F2F,stroke:#FFFFFF,color:#FFFFFF classDef sharedNode fill:#333333,stroke:#D32F2F,color:#FFFFFF classDef authNode fill:#4A4A4A,stroke:#D32F2F,color:#FFFFFF classDef homeNode fill:#4A4A4A,stroke:#D32F2F,color:#FFFFFF class MA navNode class PV,HV,PH sharedNode class LS,LVM authNode class HS,HVM homeNode style Navigation fill:#D3D3D3,stroke:#D32F2F,color:#000000 style Shared fill:#4A4A4A,stroke:#333333,color:#FFFFFF style Auth fill:#333333,stroke:#D32F2F,color:#FFFFFF style Home fill:#333333,stroke:#D32F2F,color:#FFFFFF3.2 Domain Layer (Business Logic)
Goal: House the platform-agnostic business rules and "truth" of the application.
Pure Kotlin: This layer has zero dependencies on the Android Framework (no
Context, noParcelable).Entities: Data classes like
UserandCredentialsrepresent the core business models.Use Cases (Interactors): Each business action is encapsulated in a dedicated Use Case (e.g.,
LoginUseCase). This promotes the Single Responsibility Principle and makes logic reusable across ViewModels.BaseUseCase Pattern: All interactors inherit from
BaseUseCase<P, R>. This architectural anchor standardizes:Dispatchers.IO.Result<T>sealed class for Success/Error states.invokeoperator.Key Components:
BaseUseCase<P, R>: Standardizes execution context (Coroutines) and error handling.SessionManagerInterface: Defines the contract for session operations without revealing implementation details.LoginUseCase: Encapsulates the authentication transaction.LogoutUseCase: Orchestrates atomic session teardown.flowchart TB subgraph UseCases["Use Cases (Interactors)"] LU["LoginUseCase<br/>- Validate Credentials<br/>- Authenticate via Firebase<br/>- Commit to SSOT"] LogU["LogoutUseCase<br/>- Clear session<br/>- Reset global state"] VCU["ValidateCredentialsUseCase"] RTU["RefreshTokenUseCase<br/>(Planned)"] end subgraph Models["Domain Models"] U["User.kt"] C["Credentials.kt"] AT["AuthToken.kt"] end subgraph Contracts["Repository Contracts"] AR["AuthRepository"] SR["SessionRepository"] end UseCases --> Models UseCases --> Contracts linkStyle default stroke:#D32F2F,stroke-width:2px classDef useCaseNode fill:#333333,stroke:#D32F2F,color:#FFFFFF classDef modelNode fill:#333333,stroke:#D32F2F,color:#FFFFFF classDef contractNode fill:#333333,stroke:#D32F2F,color:#FFFFFF class LU,LogU,VCU,RTU useCaseNode class U,C,AT modelNode class AR,SR contractNode style UseCases fill:#4A4A4A,stroke:#333333,color:#FFFFFF style Models fill:#333333,stroke:#D32F2F,color:#FFFFFF style Contracts fill:#D3D3D3,stroke:#D32F2F,color:#0000003.3 Data Layer (Infrastructure)
Goal: Manage data acquisition, persistence, and external service coordination.
SessionManagerserves as the Single Source of Truth (SSOT) for the user's authentication state, exposingStateFlow<AuthState>for the UI to observe.flowchart TB subgraph SSOT["Single Source of Truth"] SM["SessionManager.kt<br/>- AuthState Flow<br/>- updateSession()<br/>- clearSession()"] end subgraph Repos["Repository Implementations"] ARI["AuthRepositoryImpl<br/>- Firebase Auth"] SRI["SessionRepositoryImpl<br/>- Jetpack DataStore"] end subgraph Sources["Production Infrastructure"] Remote["Firebase Auth SDK"] Local["Jetpack DataStore PII"] end SM --> SRI ARI --> Remote SRI --> Local linkStyle default stroke:#D32F2F,stroke-width:2px classDef ssotNode fill:#D32F2F,stroke:#FFFFFF,color:#FFFFFF classDef repoNode fill:#4A4A4A,stroke:#D32F2F,color:#FFFFFF classDef sourceNode fill:#333333,stroke:#D32F2F,color:#FFFFFF class SM ssotNode class ARI,SRI repoNode class Remote,Local sourceNode style SSOT fill:#333333,stroke:#D32F2F,color:#FFFFFF style Repos fill:#4A4A4A,stroke:#333333,color:#FFFFFF style Sources fill:#D3D3D3,stroke:#D32F2F,color:#000000Session State Machine
flowchart LR INIT["Uninitialized"] -->|"initialize()"| CHECK["Checking"] CHECK -->|"Valid token found"| AUTH["Authenticated"] CHECK -->|"No token / expired"| GUEST["Guest"] AUTH -->|"logout()"| GUEST GUEST -->|"login()"| AUTH linkStyle default stroke:#D32F2F,stroke-width:2px classDef stateNode fill:#333333,stroke:#D32F2F,color:#FFFFFF class INIT,CHECK,AUTH,GUEST stateNodeAuthentication Flow Architecture
flowchart TB subgraph UI["UI Layer"] LS["LoginScreen"] LVM["LoginViewModel"] end subgraph Domain["Domain Layer"] LU["LoginUseCase"] AR["AuthRepository<br/>(Interface)"] end subgraph Data["Data Layer"] ARI["AuthRepositoryImpl"] FRD["FirebaseRemoteDataSource"] ARD["AnalyticsRemoteDataSource"] SM["SessionManager"] end subgraph Firebase["Firebase SDK"] FA["FirebaseAuth"] FAN["FirebaseAnalytics"] end LS --> LVM LVM --> LU LU --> AR AR -.->|"implements"| ARI ARI --> FRD ARI --> ARD ARI --> SM FRD --> FA ARD --> FAN linkStyle default stroke:#D32F2F,stroke-width:2px classDef uiNode fill:#4A4A4A,stroke:#D32F2F,color:#FFFFFF classDef domainNode fill:#333333,stroke:#D32F2F,color:#FFFFFF classDef dataNode fill:#333333,stroke:#D32F2F,color:#FFFFFF classDef firebaseNode fill:#4A4A4A,stroke:#D32F2F,color:#FFFFFF class LS,LVM uiNode class LU,AR domainNode class ARI,FRD,ARD,SM dataNode class FA,FAN firebaseNode style UI fill:#333333,stroke:#D32F2F,color:#FFFFFF style Domain fill:#4A4A4A,stroke:#333333,color:#FFFFFF style Data fill:#D3D3D3,stroke:#D32F2F,color:#000000 style Firebase fill:#333333,stroke:#D32F2F,color:#FFFFFFTelemetry and Analytics Integration
flowchart LR USER["User Login"] --> AUTH["Authentication Success"] AUTH --> ANALYTICS["AnalyticsRemoteDataSource"] ANALYTICS --> FIREBASE["FirebaseAnalytics.logEvent()"] FIREBASE --> DEBUG["Visible in Firebase DebugView"] linkStyle default stroke:#D32F2F,stroke-width:2px classDef telemetryNode fill:#333333,stroke:#D32F2F,color:#FFFFFF class USER,AUTH,ANALYTICS,FIREBASE,DEBUG telemetryNode4. Technical Implementation Standards
Rho Studio UI is engineered for sensitive information (fintech) environments
4.1 Session Isolation
sequenceDiagram participant UI as MainActivity participant SM as SessionManager participant CM as ComponentManager participant FC as FeatureComponent UI->>SM: collectAsState() SM-->>UI: SessionState (Guest) UI->>CM: getAppComponent() CM-->>UI: AppComponent Note over UI,FC: User logs in UI->>SM: updateSession(User) SM-->>UI: SessionState (Authenticated) UI->>CM: getUserComponent() CM-->>UI: UserComponent Note over UI,FC: User logs out UI->>SM: clearSession() SM-->>UI: SessionState (Guest) UI->>CM: releaseUserComponent() Note over CM: @UserScope objects<br/>binary-purged from memory4.2 Modularization Strategy
The project is split into granular Gradle modules to improve build times and enforce architectural boundaries:
:app: The main coordinator and DI root.:features:*: Feature-specific UI and ViewModels (e.g.,:features:auth,:features:home).:core:ui: Shared design system components and theming.:core:domain: The platform-agnostic business layer.:core:data: Implementation details for data and external services.4.3 Design System
Located in
:core:ui, the design system defines the application's visual language:RhoRed,RhoStrongGray).5. Verification & Quality Assurance
5.1 Automated Tests
DaggerGraphTest)SessionManagerTest)LoginUseCaseTest,LogoutUseCaseTest)google-services.jsonintegration5.2 Manual QA Test Plan
Scenario 1: Fresh Install / First Launch
Scenario 2: Successful Login & Data Loading
Scenario 3: Secure Logout & Session Isolation
5.3 Regression Checklist for QA
UninitializedPropertyAccessExceptionoccurs during rapid Login/Logout cycles.PageHeaderreactively updates when a new user logs in.@UserScopeobjects are destroyed on logout (Android Profiler).6. Roadmap & Evolution: Strategic Phases
The application is transitioning from a modular prototype to a production-hardened system. The evolution is structured into three strategic phases:
Phase I: Dependency Orchestration & Decoupling - [COMPLETED v1.0.3]
@Componentand@Moduleboundaries for:coreand:features.@Injectfor UseCase and ViewModel construction to ensure compile-time dependency safety.@IntoMapandDaggerViewModelFactory.CoreComponent,AppComponent, andUserComponent.@UserScopegraph on logout to prevent data leakage.Phase II: Transactional Integrity & persistence
flowchart TD A[1. Acquisition<br/>LoginUseCase --> AuthRepository.login] B[2. Persistence<br/>SessionRepository.saveToken] C[3. Validation<br/>ValidateTokenUseCase] D[4. Refresh<br/>RefreshTokenUseCase] E[5. Recovery<br/>SessionManager.initializeSession] F[6. Invalidation<br/>LogoutUseCase] A --> B --> C C -->|"Valid"| G[Use Access Token] C -->|"Expired"| D --> B E --> C F --> H[Reset AuthState] style A fill:#D32F2F,stroke:#FFFFFF,color:#FFFFFF style B fill:#333333,stroke:#D32F2F,color:#FFFFFF style C fill:#4A4A4A,stroke:#333333,color:#FFFFFF style D fill:#333333,stroke:#D32F2F,color:#FFFFFF style E fill:#4A4A4A,stroke:#333333,color:#FFFFFF style F fill:#D32F2F,stroke:#FFFFFF,color:#FFFFFF style G fill:#333333,stroke:#D32F2F,color:#FFFFFF style H fill:#4A4A4A,stroke:#333333,color:#FFFFFFflowchart TD subgraph Domain["Domain Layer"] UC["TokenUseCases<br/>- ValidateTokenUseCase<br/>- RefreshTokenUseCase<br/>- RevokeTokenUseCase"] Entities["AuthToken.kt<br/>- accessToken<br/>- refreshToken<br/>- expiresAt"] end subgraph Data["Data Layer"] Repo["AuthRepositoryImpl<br/>- refreshToken()<br/>- revokeToken()"] Store["TokenStore<br/>- EncryptedSharedPreferences<br/>- In-memory cache"] SM["SessionManager<br/>- SessionState machine"] end subgraph Security["Security Layer"] Keystore["Android Keystore<br/>- MasterKey (AES-256-GCM)"] Encrypted["EncryptedSharedPreferences"] end UC --> Repo Repo --> Store Store --> Encrypted Encrypted --> Keystore style Domain fill:#333333,stroke:#D32F2F,color:#FFFFFF style Data fill:#4A4A4A,stroke:#333333,color:#FFFFFF style Security fill:#D32F2F,stroke:#FFFFFF,color:#FFFFFF8. References & Standards
Rho.Studio® - Engineering Department - Contact alexis.tercero@rho.studio