diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c586309..00a2493 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: Android Release Rho.Studio® on: workflow_dispatch: push: - branches: [ "Pre-release-v102" ] + branches: [ "pre-release-v103" ] pull_request: branches: [ "main" ] @@ -23,6 +23,12 @@ jobs: distribution: 'temurin' cache: gradle + # Add this step here + - name: Decode Google Services JSON + env: + GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} + run: echo $GOOGLE_SERVICES_JSON | base64 --decode > app/google-services.json + - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a1e5038 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,90 @@ +# Architecture & Contribution Guide: Rho Studio UI + +## 1. Project Vision & Architecture +Rho Studio UI is a modern Android application built with **Jetpack Compose** and **MVVM** following a **Single-Activity Architecture**. + +To achieve scalability, implement **Domain-Driven Design (DDD)** and **Clean Architecture** principles. This ensures a clear separation of concerns, framework independence, and high testability. + +--- + +## 2. Feature Implementation Workflow (Step-by-Step) + +When adding a new feature (e.g., "Settings", "Profile"), follow this **Inside-Out** sequence to ensure architectural integrity: + +### Step 1: Domain Layer (The Logic) +1. **Define Models**: Create pure Kotlin data classes in `core:domain` (e.g., `Settings.kt`). +2. **Define Repository Interface**: Add an interface in `core:domain` describing the data contract. +3. **Create Interactor (UseCase)**: Implement the business logic by inheriting from `BaseUseCase`. + * **P (Parameters)**: Use a `data class` for multiple inputs or `Unit` for none. + * **R (Return)**: The raw data type (Dagger/BaseUseCase will wrap it in `Result`). + * **Rule**: Must be a pure Kotlin class without Android dependencies. + * **Rule**: Must be testable with MockK/JUnit 5. + +Example: +```kotlin +class LoginUseCase @Inject constructor( + private val repository: AuthRepository +) : BaseUseCase() { + override suspend fun execute(parameters: Credentials): User { + return repository.login(parameters) + } +} +``` + +### Step 2: Data Layer (The Infrastructure) +1. **Implement Repository**: Create the implementation in `core:data` using Firebase, Retrofit, or DataStore. +2. **Dagger Binding**: Add a `@Binds` method in `CoreModule.kt` to link the interface to the implementation. + +### Step 3: UI Layer (The Presentation) +1. **Create ViewModel**: Inherit from `BaseViewModel`. + * Use `launchSafe` or `launchWithLoading` for all coroutines. + * Expose UI state via `StateFlow`. +2. **Dagger Multibinding**: + * Create a Dagger `@Module` for the feature. + * Use `@Binds @IntoMap @ViewModelKey(MyViewModel::class)` to register it. + * Add the module to the appropriate component (`AppComponent` for public, `UserComponent` for authenticated). +3. **Build Composables**: Create stateless Compose functions. Observe the ViewModel state in the screen-level Composable. + +--- + +## 3. Dependency Injection Standards (Dagger 2) + +We use a **Multi-Tiered Dependency Graph**. Developers must respect scope boundaries: + +* **@Singleton**: For infrastructure (Network, Firebase, SessionManager). Lives in `CoreComponent`. +* **@AppScope**: For public/login logic. Lives in `AppComponent`. +* **@UserScope**: For authenticated user data. Lives in `UserComponent`. + +> [!WARNING] +> Never attempt to inject a `@UserScope` dependency into a `@Singleton` class. This will cause a memory leak or a crash. + +--- + +## 4. UI Standards & Base Classes + +### 4.1 BaseViewModel +Every ViewModel **must** extend `BaseViewModel`. This provides: +- `isLoading`: A built-in StateFlow for progress bars. +- `launchSafe { ... }`: Automatic error handling and crash prevention. +- `handleError(e)`: Standardized toast and error state management. + +### 4.2 Stateless Composables +Divide your UI into two parts: +1. **Screen Composable**: "Stateful." Injects the ViewModel and passes data down. +2. **Component Composables**: "Stateless." Take raw data and lambdas (e.g., `onClick: () -> Unit`). This makes them previewable and testable. + +--- + +## 5. Security & PII +- **PII**: Any Personal Identifiable Information must be stored in the **Encrypted DataStore**. +- **Session**: Global session state is managed by `SessionManager`. Use it to reactively hide/show UI elements based on authentication. + +--- + +## 6. Testing Requirements +- **Domain**: 90%+ coverage for UseCases. +- **ViewModels**: Test state transitions using `Dispatcher.Main` delegation. +- **Data**: Mock external SDKs (Firebase) using MockK. + +--- +**[Rho.Studio®](https://rho.studio/) - Engineering Department** - Contact [alexis.tercero@rho.studio](mailto:alexis.tercero@rho.studio) diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md deleted file mode 100644 index 3ea1c6a..0000000 --- a/CONTRIBUTION.md +++ /dev/null @@ -1,70 +0,0 @@ -# Architecture & Contribution Guide: Rho Studio UI - -## 1. Project Vision & Architecture -Rho Studio UI is a modern Android application built with **Jetpack Compose** and **MVVM** following a **Single-Activity Architecture**. - -To achieve enterprise-grade scalability, we strictly implement **Clean Architecture** principles. This ensures a clear separation of concerns, framework independence, and high testability. - ---- - -## 2. Clean Architecture Layer Responsibilities -All contributions must respect the strict boundaries between the following three layers: - -### 2.1 The UI Layer (`features/` & `ui/`) -* **Role**: Handles user interaction and data presentation. -* **Components**: - * **Compose Screens/Components**: Purely declarative and stateless. They observe state and emit events. - * **ViewModels**: Act as a bridge. They manage UI state (Loading, Error, Toast) and handle user intent by calling Use Cases. -* **Boundary Rule**: Never contains business logic. Never interacts directly with Repositories. - -### 2.2 The Domain Layer (`core/domain/`) -* **Role**: The "Heart" of the application. Contains the essential business rules. -* **Components**: - * **Use Cases (Interactors)**: Classes like `LoginUseCase.kt` that encapsulate a single, atomic business transaction. - * **Domain Models**: Pure data entities (e.g., `User.kt`) that are framework-independent. -* **Boundary Rule**: **Pure Kotlin only**. Must not import `android.*` or depend on any external libraries/frameworks (except pure Kotlin ones). This layer is the "Single Source of Truth" for *logic*. - -### 2.3 The Data Layer (`core/data/`) -* **Role**: Manages data acquisition and persistence. -* **Components**: - * **Repositories**: Implementation of data fetching (API, Room, Preferences). - * **Managers**: State holders like `SessionManager.kt` that coordinate global app state. -* **Boundary Rule**: Acts as the "Single Source of Truth" for *data state*. It implements the requirements defined by the Domain layer. - ---- - -## 3. Core Requirements for Contributions - -### 3.1 MVVM & UDF (Unidirectional Data Flow) -- **State flows down**: From ViewModel to Composables. -- **Events flow up**: From UI to ViewModel via lambdas. - -### 3.2 Single-Activity & Reactive Navigation -- **MainActivity** is the sole navigation orchestrator. -- **ViewModels** and **Use Cases** must **never** hold a `NavController` or trigger navigation directly. -- **Logic**: Use Cases update the session/state in the Data layer. `MainActivity` observes this state and performs the transition (e.g., auto-routing to Login on session expiry). - ---- - -## 4. Implementing New Features (Profile, Feed, Chat) - -Every new feature should be built following the **Inside-Out** approach: - -1. **Inside (Domain)**: Create the `UseCase` (e.g., `UpdateProfileUseCase`, `GetFeedUseCase`, `SendMessageUseCase`). - - Use the `Result` wrapper for success/failure. - - Write a Unit Test for the logic. -2. **Middle (ViewModel)**: Create the bridge that transforms the Use Case `Result` into observable UI state. -3. **Outside (UI)**: Build the stateless Compose UI. - - **Feed UI**: Use `LazyColumn` for efficiency. Implement a stateless `PostItem.kt`. - - **Chat UI**: Implement specialized "Message Bubble" components. Input fields must update the ViewModel state immediately. - ---- - -## 5. Technical Constraints -- **Atomic Transactions**: Multi-step actions (e.g., validate -> save -> sync) must be managed as a single atomic unit within a `UseCase`. -- **Framework Independence**: Keep the Domain layer free of Android dependencies to support future Gradle modularization. -- **Standardized Results**: Always return `Result.Success`, `Result.Error`, or `Result.Loading` from Use Cases. - ---- -**[Rho.Studio®](https://rho.studio/) - Engineering Department** - Contact [alexis.tercero@rho.studio](mailto:alexis.tercero@rho.studio) - diff --git a/README.md b/README.md index 8558d41..f3b030e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ An Android Jetpack Compose app. [![Android CI/CD Rho.Studio®](https://github.com/Rho-Studio/UI-Utils-Rho-Studio/actions/workflows/android.yml/badge.svg)](https://github.com/Rho-Studio/UI-Utils-Rho-Studio/actions/workflows/android.yml) [![Android Release Rho.Studio®](https://github.com/Rho-Studio/UI-Utils-Rho-Studio/actions/workflows/release.yml/badge.svg)](https://github.com/Rho-Studio/UI-Utils-Rho-Studio/actions/workflows/release.yml) -> _Document Version: 2.0 Last Updated: August 10, 2026_ +> _Document Version: 3.1 Last Updated: August 25, 2026_ ## 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. @@ -16,12 +16,17 @@ This document provides a comprehensive technical overview of the **Rho Studio UI ## 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 pure **Jetpack Compose** implementation following a **Single-Activity Architecture**, leveraging a reactive **MVVM (Model-View-ViewModel)** pattern to ensure a clean separation of concerns, testability, 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**. +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](CONTRIBUTING.md). ### Core Features: -- **Secure Authentication**: Robust login flow with real-time validation and session lifecycle management, following corporate security protocols. -- **Adaptive Home Experience**: A responsive home interface that dynamically adjusts to different service modules and device form factors. -- **Brand Consistency**: A centralized design system leveraging Material 3 to reflect the Rho Studio corporate identity across all derived applications. +- **Authentication Orchestration**: Implements a production flow using Firebase Auth with a reactive session lifecycle. It ensures transactional security by synchronizing remote authentication states with automated, state-driven navigation transitions. +- **Architectural Boundaries**: A high-performance Multi-Tier Dagger Hierarchy that enforces strict data isolation between core, app, and user scopes. Sensitive user information is isolated within a dedicated "User Tier" that is physically purged from memory upon logout to prevent data leakage. +- **Reactive Data Layer and State Integrity**: Leverages Jetpack DataStore for atomic persistence and a Sealed State Machine for global orchestration. This creates a thread-safe, non-blocking "stream of truth" that guarantees the UI remains a perfect reflection of the underlying data. +- **Stateless Presentation Layer**: A fully decoupled UI built with Jetpack Compose following Unidirectional Data Flow (UDF) principles. This enables the presentation layer to scale dynamically across diverse device form factors while ensuring high testability and visual consistency. +- **Domain-Driven Design (DDD)**: Every business operation is encapsulated in a dedicated UseCase (Interactor) within a framework-independent domain layer. By strictly isolating the business rules from the Android framework, ensure testability, logic reusability, and architectural resilience against framework changes. --- @@ -29,39 +34,53 @@ The application is a pure **Jetpack Compose** implementation following a **Singl 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 is divided into three primary logical layers, enforcing a strict unidirectional dependency flow: **UI → Domain ← Data**. +The system follows the three layers Google's recommendations: ```mermaid graph TD - subgraph "UI Layer (Presentation)" - UI[Jetpack Compose Screens] + subgraph UI["UI Layer (Presentation)"] + UI_Screens[Jetpack Compose Screens] VM[ViewModels] Nav[Navigation / NavHost] end - subgraph "Domain Layer (Business Logic)" + subgraph Domain["Domain Layer (Business Logic)"] UC[Use Cases / Interactors] Entities[Domain Entities] Int[Repository Interfaces] end - subgraph "Data Layer (Infrastructure)" + subgraph Data["Data Layer (Infrastructure)"] Repo[Repository Implementations] - SM[Session Manager] + SM[Session Manager / SSOT] Local[Local / Network Data Sources] end - UI --> VM + 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:#000000 ``` ### 2.2 Multi-Module Topology -We have moved away from a monolithic `:app` structure to a **Feature-Layered Modularization** strategy. This optimizes build parallelization and enforces strict dependency inversion. +The project is split into granular Gradle modules to improve build parallelization and enforce boundaries. ```mermaid flowchart TD APP[":app
MainActivity, NavHost"] @@ -84,15 +103,169 @@ flowchart TD 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:#000000 +``` +> [!Tip] +> `:features` depend only on `:core` modules (`: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 + +| Concept | Implementation | Purpose | +| :--- | :--- | :--- | +| **The Request** | `@Inject` constructor | Objects request dependencies via constructor injection, ensuring loose coupling and testability | +| **The Recipe** | `@Module` with `@Provides` / `@Binds` | Dagger Modules define how to provide complex objects, interfaces, or library classes | +| **The Manager** | `@Component` | Bridge between providers (Modules) and consumers (Activities/ViewModels). Validates graph at compile-time | +| **The Lifecycle** | `@Scope` (e.g., `@Singleton`, `@UserScope`) | Ensures objects live exactly as long as their context (App lifecycle vs. User session) | +| **Annotation Retention** | `@Retention(AnnotationRetention.RUNTIME)` | Ensures annotation metadata is available to Dagger compiler and at runtime | +| **Multibinding Keys** | `@MapKey` | Identifies which class type to use as a Key in Dagger's internal Maps | +| **Lazy Provisioning** | `Provider` | Defers actual creation of dependencies until requested, saving memory and startup time | +| **Kotlin Interop** | `@JvmSuppressWildcards` | Handles Kotlin's generic covariance in Dagger's Java-based compiler | + +#### Multi-Tier Component Dependency Architecture + +```mermaid +flowchart TB + subgraph Core["CoreComponent (@Singleton)"] + direction TB + CTX["Context (Application)"] + DS["DataStore"] + SM["SessionManager"] + FA["FirebaseAuth"] + FAN["FirebaseAnalytics"] + end - style APP fill:#e94560,stroke:#c62828,color:#ffffff - style AUTH fill:#1a1a2e,stroke:#e94560,color:#ffffff - style HOME fill:#1a1a2e,stroke:#e94560,color:#ffffff - style UI_CORE fill:#16213e,stroke:#0f3460,color:#ffffff - style DOMAIN fill:#0f3460,stroke:#16213e,color:#ffffff - style DATA fill:#1a1a2e,stroke:#e94560,color:#ffffff + 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:#000000 ``` -> **Key Principle**: `:features` depend only on `:core` modules (`:core:domain`, `:core:ui`), preventing circular dependencies. Feature-specific models remain within their respective feature modules, adhering to the Interface Segregation Principle. + +**Core Tier** (`CoreComponent`): + +- **Scope**: `@Singleton`. +- **Responsibility**: Infrastructure foundation (Firebase, DataStore, Threading). +- **Hierarchy**: The foundation; does not depend on other components. + +**App Tier** (`AppComponent`): + +- **Scope**: @AppScope. +- **Responsibility**: Public lifecycle (Authentication feature, Shared UI). +- **Hierarchy**: Depends on CoreComponent. Orchestrates AuthModule (Pre-Login ViewModels) and UIModule (Shared ViewModels). + +**User Tier** (`UserComponent`): + +- **Scope**: `@UserScope`. +- **Responsibility**: Authenticated session (Home feature, 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. + +### 2.4 ViewModel Multibinding Strategy + +To decouple the UI from DI wiring, we implement a centralized registry using `@IntoMap`: + +```mermaid +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
Map>"] + 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:#000000 +``` + +#### Key Principles: + +- **Registry**: Feature modules contribute ViewModels via a custom @ViewModelKey. +- **Factory**: A single DaggerViewModelFactory resolves instances on-demand, adhering to the Open/Closed Principle. +- **Isolation**: Each component builds unique internal Maps, ensuring strict data and logic isolation based on user state. + +| Component | Modules Included | Resulting Internal Map | +| :--- | :--- | :--- | +| **AppComponent** | `AuthModule`, `UIModule` | `{LoginViewModel, HeaderViewModel}` | +| **UserComponent** | `HomeModule`, `UIModule` | `{HomeViewModel, HeaderViewModel}` | --- @@ -116,20 +289,19 @@ flowchart TB end subgraph Shared["Shared UI Components"] - PV["BaseViewModel.kt
- Loading states
- Error handling"] + PV["BaseViewModel.kt
- launchSafe
- isLoading state"] HV["HeaderViewModel.kt
- Session state bridging"] PH["PageHeader.kt"] - PF["PageFooter.kt"] end subgraph Auth["Authentication Feature"] LS["LoginScreen.kt"] - LVM["LoginViewModel.kt
- Form state
- Debounced validation"] + LVM["LoginViewModel.kt"] end subgraph Home["Home Feature"] HS["HomeScreen.kt"] - HVM["HomeViewModel.kt
- Home state
- Session termination"] + HVM["HomeViewModel.kt"] end MA --> LS @@ -139,34 +311,86 @@ flowchart TB LVM --> PV HVM --> PV HV --> PV - - style Navigation fill:#e94560,stroke:#c62828,color:#ffffff - style Shared fill:#16213e,stroke:#0f3460,color:#ffffff - style Auth fill:#1a1a2e,stroke:#e94560,color:#ffffff - style Home fill:#1a1a2e,stroke:#e94560,color:#ffffff + + 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:#FFFFFF ``` ### 3.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`, no `Parcelable`). -- **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. - **Entities**: Data classes like `User` and `Credentials` represent 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`. This architectural anchor standardizes: + - **Thread Safety**: Automatic execution on `Dispatchers.IO`. + - **Result Wrapping**: Consistent use of the `Result` sealed class for Success/Error states. + - **Functional Invocation**: Use cases are invoked as functions using the `invoke` operator. + - **Key Components**: - `BaseUseCase`: 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. +```mermaid +flowchart TB + subgraph UseCases["Use Cases (Interactors)"] + LU["LoginUseCase
- Validate Credentials
- Authenticate via Firebase
- Commit to SSOT"] + LogU["LogoutUseCase
- Clear session
- Reset global state"] + VCU["ValidateCredentialsUseCase"] + RTU["RefreshTokenUseCase
(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:#000000 +``` + ### 3.3 Data Layer (Infrastructure) **Goal**: Manage data acquisition, persistence, and external service coordination. - **Repository Pattern**: Acts as a mediator between different data sources (Network, Database) and the Domain Layer. - **Session Management**: `SessionManager` serves as the Single Source of Truth (SSOT) for the user's authentication state, exposing `StateFlow` for the UI to observe. -- **Current Implementation**: Uses `SharedPreferences` with `Gson` serialization for persistence and mock authentication for development. -- **Key Components**: - - `SessionManager.kt`: Singleton coordinator for authentication state and user profile. - - `SessionRepository.kt`: Coordinates data retrieval strategies. - - `SessionRepositoryImpl.kt`: Manages persistent storage using SharedPreferences. Migrated to Room Database in the future. - - `AuthRepositoryImpl.kt`: Mock implementation (**temporary**) simulating network delay and user creation. Replaced by Firebase Auth in the future. +- **Production Sources**: Production-grade implementation using Firebase Auth and Jetpack DataStore. +- **Telemetry**: Integrated Firebase Analytics for automated journey tracking. +- **Dependency Inversion**: Repository interfaces defined in Domain; implementations in Data. ```mermaid flowchart TB subgraph SSOT["Single Source of Truth"] @@ -174,51 +398,148 @@ flowchart TB end subgraph Repos["Repository Implementations"] - ARI["AuthRepositoryImpl
- Mock login()"] - SRI["SessionRepositoryImpl
- SharedPreferences"] + ARI["AuthRepositoryImpl
- Firebase Auth"] + SRI["SessionRepositoryImpl
- Jetpack DataStore"] end - subgraph Sources["Data Sources (Planned)"] - Remote["Remote API
- Firebase Auth"] - Local["Local Storage
- Room Database"] + 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:#000000 +``` +#### Session State Machine + +```mermaid +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 stateNode +``` +#### Authentication Flow Architecture +```mermaid +flowchart TB + subgraph UI["UI Layer"] + LS["LoginScreen"] + LVM["LoginViewModel"] + end + + subgraph Domain["Domain Layer"] + LU["LoginUseCase"] + AR["AuthRepository
(Interface)"] + end + + subgraph Data["Data Layer"] + ARI["AuthRepositoryImpl"] + FRD["FirebaseRemoteDataSource"] + ARD["AnalyticsRemoteDataSource"] + SM["SessionManager"] + end + + subgraph Firebase["Firebase SDK"] + FA["FirebaseAuth"] + FAN["FirebaseAnalytics"] + end - style SSOT fill:#e94560,stroke:#c62828,color:#ffffff - style Repos fill:#1a1a2e,stroke:#e94560,color:#ffffff - style Sources fill:#0f3460,stroke:#16213e,color:#ffffff + 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:#FFFFFF ``` +#### Telemetry and Analytics Integration + +```mermaid +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 telemetryNode +``` + --- ## 4. Technical Implementation Standards -### 4.1 Reactive Orchestration -The application uses **Kotlin Coroutines and Flow** for all asynchronous operations. -- **State-Driven Navigation**: `MainActivity` observes `SessionManager.isAuthenticated`; state changes trigger navigation transitions via `LaunchedEffect`. -- **Debounced Validation**: Login inputs are validated using a 300ms debounce to optimize performance. -- **State Pushing**: ViewModels push immutable state objects to the UI, ensuring that recompositions are predictable and efficient. +Rho Studio UI is engineered for sensitive information (fintech) environments + +### 4.1 Session Isolation + ```mermaid sequenceDiagram participant UI as MainActivity participant SM as SessionManager - participant Nav as NavController + participant CM as ComponentManager + participant FC as FeatureComponent UI->>SM: collectAsState() - SM-->>UI: AuthState (Unauthenticated) - UI->>Nav: navigate to Login - - Note over UI,Nav: User clicks Login - UI->>LoginViewModel: onLoginClicked() - LoginViewModel->>LoginUseCase: login(email, password) - LoginUseCase->>AuthRepository: login(credentials) - AuthRepository-->>LoginUseCase: User - LoginUseCase->>SessionManager: updateSession(user) - - SM-->>UI: AuthState (Authenticated) - UI->>Nav: navigate to Home + 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
binary-purged from memory ``` ### 4.2 Modularization Strategy @@ -237,14 +558,58 @@ Located in `:core:ui`, the design system defines the application's visual langua --- -## 5. Roadmap & Evolution: Strategic Phases +## 5. Verification & Quality Assurance + +### 5.1 Automated Tests + +| Test Suite | Scope | Status | +| :--- | :--- | :---: | +| **DI Graph Audit** (`DaggerGraphTest`) | Verifies all components and providers (Firebase, Analytics) are correctly satisfied | Passed | +| **Transactional Integrity** (`SessionManagerTest`) | Validates atomic state flow and DataStore synchronization | Passed | +| **Business Logic** (`LoginUseCaseTest`, `LogoutUseCaseTest`) | 90%+ coverage of core transactions using MockK | Passed | +| **CI/CD Build** | Verified on GitHub Actions including `google-services.json` integration | Passed | + +### 5.2 Manual QA Test Plan + +**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. + - Firebase Analytics event is visible in DebugView. + +**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. + +### 5.3 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. +- Verify that `@UserScope` objects 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 +### Phase I: Dependency Orchestration & Decoupling - [COMPLETED v1.0.3] - **Dagger Migration**: Implementation of **Dagger 2** to replace manual Service Locators. - Define `@Component` and `@Module` boundaries for `:core` and `:features`. - Implement `@Inject` for UseCase and ViewModel construction to ensure compile-time dependency safety. +- **ViewModel Multibinding**: Centralized ViewModel registry using `@IntoMap` and `DaggerViewModelFactory`. +- **Component Dependencies**: Hierarchical component architecture with `CoreComponent`, `AppComponent`, and `UserComponent`. +- **Session Isolation**: Physical destruction of `@UserScope` graph on logout to prevent data leakage. - **Interface Segregation**: Strict enforcement of domain-defined interfaces to further isolate the Data Layer from Business Logic. ### Phase II: Transactional Integrity & persistence @@ -252,9 +617,6 @@ The application is transitioning from a modular prototype to a production-harden - Implementation of an atomic token refresh mechanism within the Data Layer. - Securing critical transaction flows by validating session integrity before high-stakes domain executions. - Complete token lifecycle: Acquisition → Persistence → Validation → Refresh → Recovery → Invalidation. -- **Offline-First with Room**: - - Integration of **Room Database** as the local cache for service modules. - - Implementation of a "Source of Truth" strategy in Repositories to handle network-to-local synchronization. ```mermaid flowchart TD A[1. Acquisition
LoginUseCase --> AuthRepository.login] @@ -270,76 +632,50 @@ flowchart TD E --> C F --> H[Reset AuthState] - style A fill:#e94560,stroke:#c62828,color:#ffffff - style B fill:#16213e,stroke:#0f3460,color:#ffffff - style C fill:#1a1a2e,stroke:#e94560,color:#ffffff - style D fill:#0f3460,stroke:#16213e,color:#ffffff - style E fill:#16213e,stroke:#0f3460,color:#ffffff - style F fill:#e94560,stroke:#c62828,color:#ffffff - style G fill:#0f3460,stroke:#16213e,color:#ffffff - style H fill:#1a1a2e,stroke:#e94560,color:#ffffff + 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:#FFFFFF ``` -### Phase III: Verification & Quality Engineering -- **Domain Test Suite**: Achieving 90%+ coverage for `:core:domain` logic using JUnit 5 and MockK. -- **UI & Regression Testing**: - - Implementation of **Compose UI Tests** for critical user journeys (Login, Home navigation). - - Integration of **Screenshot Testing** to ensure visual consistency across the Rho Studio design system. -- **Performance Profiling**: Regular benchmarking of recomposition counts and memory allocation in high-density feature screens. +- **Offline-First with Room**: + - Integration of **Room Database** as the local cache for service modules. + - Implementation of a "Source of Truth" strategy in Repositories to handle **network-to-local synchronization**. + ```mermaid -flowchart LR - subgraph Current["Current Flow"] - C1[UI] --> C2[ViewModel] --> C3[UseCase] --> C4[Repository] --> C5[SharedPreferences/Mock Auth] +flowchart TD + subgraph Domain["Domain Layer"] + UC["TokenUseCases
- ValidateTokenUseCase
- RefreshTokenUseCase
- RevokeTokenUseCase"] + Entities["AuthToken.kt
- accessToken
- refreshToken
- expiresAt"] + end + + subgraph Data["Data Layer"] + Repo["AuthRepositoryImpl
- refreshToken()
- revokeToken()"] + Store["TokenStore
- EncryptedSharedPreferences
- In-memory cache"] + SM["SessionManager
- SessionState machine"] end - subgraph Planned["Planned Flow"] - P1[UI] --> P2[ViewModel] --> P3[UseCase] --> P4[Repository] - P4 --> P5[Local: Room Database] - P4 --> P6[Remote: Retrofit/Firebase] + subgraph Security["Security Layer"] + Keystore["Android Keystore
- MasterKey (AES-256-GCM)"] + Encrypted["EncryptedSharedPreferences"] end - Current -.->|"Evolution"| Planned + UC --> Repo + Repo --> Store + Store --> Encrypted + Encrypted --> Keystore - style Current fill:#1a1a2e,stroke:#e94560,color:#ffffff - style Planned fill:#0f3460,stroke:#16213e,color:#ffffff + style Domain fill:#333333,stroke:#D32F2F,color:#FFFFFF + style Data fill:#4A4A4A,stroke:#333333,color:#FFFFFF + style Security fill:#D32F2F,stroke:#FFFFFF,color:#FFFFFF ``` ---- -## 6. Verification & Quality Assurance -- **CI/CD**: GitHub Actions pipeline verifies every commit against build and test suites. -- **Static Analysis**: Automated linting and ASCII metadata headers enforce code style and legal standards. - -## 7. File Registry and responsibilities -Here is the updated table based on the file structure provided: - -| File / Module | Layer | Responsibility | Status | -|:----------------------------------|:-------------|:-------------------------------------|:-------| -| `MainActivity.kt` | UI Layer | Navigation orchestration | ✅ | -| `BaseViewModel.kt` | UI Layer | Loading/Error state management | ✅ | -| `HeaderViewModel.kt` | UI Layer | Session state bridging | ✅ | -| `PageHeader.kt` / `PageFooter.kt` | UI Layer | Shared UI components | ✅ | -| `LoginScreen.kt` | UI Layer | Login UI entry point | ✅ | -| `LoginViewModel.kt` | UI Layer | Form state & validation | ✅ | -| `LoginEmailField.kt` | UI Layer | Email input with validation | ✅ | -| `LoginPasswordField.kt` | UI Layer | Password input with security | ✅ | -| `LoginButton.kt` | UI Layer | Login action button | ✅ | -| `HomeScreen.kt` | UI Layer | Home UI entry point | ✅ | -| `HomeViewModel.kt` | UI Layer | Home state & session termination | ✅ | -| `ServiceList.kt` | UI Layer | Service list grid component | ✅ | -| `ServiceItem.kt` | UI Layer | Individual service item component | ✅ | -| `ServiceModule.kt` | UI Layer | Feature-specific model (Home) | ✅ | -| `BaseUseCase.kt` | Domain Layer | Standardized UseCase abstraction | ✅ | -| `LoginUseCase.kt` | Domain Layer | Atomic authentication transaction | ✅ | -| `LogoutUseCase.kt` | Domain Layer | Session teardown orchestration | ✅ | -| `SessionManagerInterface.kt` | Domain Layer | Session operations contract | ✅ | -| `AuthRepository.kt` | Domain Layer | Authentication contract | ✅ | -| `SessionRepository.kt` | Domain Layer | Session persistence contract | ✅ | -| `User.kt` / `Credentials.kt` | Domain Layer | Pure Kotlin Entities | ✅ | -| `SessionManager.kt` | Data Layer | SSOT for authentication | ✅ | -| `AuthRepositoryImpl.kt` | Data Layer | Mock auth (Firebase **planned**) | ⚠️ | -| `SessionRepositoryImpl.kt` | Data Layer | SharedPreferences (Room **planned**) | ⚠️ | -| `RefreshTokenUseCase.kt` | Domain Layer | Token refresh (**planned**) | 📅 | -| `Dagger Components` | App Root | DI setup (**planned**) | 📅 | + + ## 8. References & Standards - **MAD (Modern Android Development)**: Adhering to official [Android Architecture Guidelines](https://developer.android.com/topic/architecture). - **Jetpack Compose Best Practices**: Following UDF ([Unidirectional Data Flow](https://developer.android.com/develop/ui/compose/architecture#udf)) principles for state management. diff --git a/app/src/test/java/com/rho/studio/ui/di/DaggerGraphTest.kt b/app/src/test/java/com/rho/studio/ui/di/DaggerGraphTest.kt index 68a6776..01fbd37 100644 --- a/app/src/test/java/com/rho/studio/ui/di/DaggerGraphTest.kt +++ b/app/src/test/java/com/rho/studio/ui/di/DaggerGraphTest.kt @@ -1,3 +1,22 @@ +/** + * ██████╗ ██╗ ██╗ ██████╗ ███████╗████████╗██╗ ██╗██████╗ ██╗ ██████╗ + * ██╔══██╗██║ ██║██╔═══██╗ ██╔════╝╚══██╔══╝██║ ██║██╔══██╗██║██╔═══██╗ + * ██████╔╝███████║██║ ██║ ███████╗ ██║ ██║ ██║██║ ██║██║██║ ██║ + * ██╔══██╗██╔══██║██║ ██║ ╚════██║ ██║ ██║ ██║██║ ██║██║██║ ██║ + * ██║ ██║██║ ██║╚██████╔╝ ███████║ ██║ ╚██████╔╝██████╔╝██║╚██████╔╝ + * ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝ + * + * ========================================================================== + * File: DaggerGraphTest.kt + * Author: Alexis Tercero + * Email: alexis.tercero@rho.studio + * Date: 2026-08-25 + * ========================================================================== + * Description: Test suite for Dagger graph integrity. + * Verifies that all components and modules are correctly wired + * and that the scoped lifecycle of components is maintained. + * ========================================================================== + */ package com.rho.studio.ui.di import android.content.Context diff --git a/core/data/src/test/java/com/rho/studio/ui/core/data/manager/SessionManagerTest.kt b/core/data/src/test/java/com/rho/studio/ui/core/data/manager/SessionManagerTest.kt index b1beb90..141da9b 100644 --- a/core/data/src/test/java/com/rho/studio/ui/core/data/manager/SessionManagerTest.kt +++ b/core/data/src/test/java/com/rho/studio/ui/core/data/manager/SessionManagerTest.kt @@ -1,3 +1,22 @@ +/** + * ██████╗ ██╗ ██╗ ██████╗ ███████╗████████╗██╗ ██╗██████╗ ██╗ ██████╗ + * ██╔══██╗██║ ██║██╔═══██╗ ██╔════╝╚══██╔══╝██║ ██║██╔══██╗██║██╔═══██╗ + * ██████╔╝███████║██║ ██║ ███████╗ ██║ ██║ ██║██║ ██║██║██║ ██║ + * ██╔══██╗██╔══██║██║ ██║ ╚════██║ ██║ ██║ ██║██║ ██║██║██║ ██║ + * ██║ ██║██║ ██║╚██████╔╝ ███████║ ██║ ╚██████╔╝██████╔╝██║╚██████╔╝ + * ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝ + * + * ========================================================================== + * File: SessionManagerTest.kt + * Author: Alexis Tercero + * Email: alexis.tercero@rho.studio + * Date: 2026-08-25 + * ========================================================================== + * Description: Test suite for SessionManager. + * Verifies the reactive session state machine, initialization logic, + * and synchronization with the persistent repository. + * ========================================================================== + */ package com.rho.studio.ui.core.data.manager import com.rho.studio.ui.core.domain.model.SessionState