Skip to main content
Here is the introduction.mdx file, tailored to the specific architecture and codebase provided.
---
title: "System Architecture"
sidebarTitle: "Introduction"
description: "High-level overview of the ScrollLess technology stack, architectural patterns, and data flow."
icon: "sitemap"
mode: "wide"
---

## Welcome to the Team

Welcome to the **ScrollLess** engineering team. You are looking at the "Spinal Cord" of our application. Unlike a standard CRUD app, ScrollLess operates as a system-level monitor, requiring a robust architecture to handle real-time event ingestion (scrolling, notifications) while maintaining a smooth UI.

## System Metaphor

Think of ScrollLess as a **Digital Wellbeing Interceptor**.

It sits quietly between the Android Operating System and the User. It listens for specific signals (an app opening, a scroll gesture, a notification), processes them against a local set of rules (Limits), and intervenes only when necessary (blocking the screen or sending a nudge).

## Technology Stack

We use a modern, opinionated Android stack centered around Google's latest recommendations.

| Layer | Technology | Purpose |
| :--- | :--- | :--- |
| **UI** | <Tooltip tip="Google's modern toolkit for building native UI using Kotlin code">Jetpack Compose</Tooltip> | We use Material3 and Compose for 99% of our UI. |
| **DI** | <Tooltip tip="Dependency Injection library built on top of Dagger">Hilt</Tooltip> | Connects our Database, Network, and Services to the UI. |
| **Async** | <Tooltip tip="Kotlin's solution for asynchronous programming">Coroutines</Tooltip> & Flow | Handling background threads and reactive data streams. |
| **Local Data** | <Tooltip tip="Abstraction layer over SQLite database">Room</Tooltip> | The "Single Source of Truth" for all app data. |
| **Remote** | <Tooltip tip="Type-safe HTTP client for Android">Retrofit</Tooltip> | Syncing app categories and metadata. |
| **Background** | <Tooltip tip="Library for persistent background processing">WorkManager</Tooltip> | Daily data summarization and limit enforcement. |
| **Ingestion** | Accessibility & Notification Services | Listening to system events in real-time. |

## High-Level Architecture

We follow the **MVVM (Model-View-ViewModel)** pattern with a strict **Repository** layer. Data flows unidirectionally: from the Database to the UI.

```mermaid
graph TD
    subgraph "UI Layer"
        UI[Jetpack Compose UI]
        VM[ViewModel]
    end

    subgraph "Data Layer"
        Repo[Repository]
        Room[<Tooltip tip='Local Database'>Room DB</Tooltip>]
        Remote[Retrofit API]
    end

    subgraph "Ingestion Layer (Services)"
        Acc[Accessibility Service]
        Notif[Notification Listener]
        Usage[Usage Stats Worker]
    end

    %% Flows
    UI <-->|"StateFlow / Events"| VM
    VM <-->|"Suspend Functions"| Repo
    
    Repo <-->|"Read/Write"| Room
    Repo <-->|"Fetch"| Remote
    
    Acc -->|"Write Raw Events"| Room
    Notif -->|"Write Notifications"| Room
    Usage -->|"Write Usage Stats"| Room

    style Room fill:#f9f,stroke:#333,stroke-width:2px
    style Acc fill:#bbf,stroke:#333,stroke-width:1px
    style Notif fill:#bbf,stroke:#333,stroke-width:1px

Core Architectural Patterns

1. The “Heavy” Service Layer

Unlike most apps that only run when open, ScrollLess relies on Foreground Services.
  • Accessibility Service (ScrollTrackService): Reads screen content to detect infinite scrolling.
  • Notification Listener: Intercepts incoming notifications to batch or block them.
  • App Tracker: Monitors which app is currently in the foreground.
These services write directly to the database via DAOs (Data Access Objects).

2. Offline-First Principle

The app is designed to work 100% offline.
  • Source of Truth: The local database (AppDatabase.kt) is the absolute truth.
  • Syncing: We use (CategorySyncWorker) to fetch app categories from the cloud, but the UI always reads from the local database, never the network directly.

3. Reactive Data Flow

We use Kotlin Flows to make the UI reactive.
  1. A Service writes a new ScrollSession to the database.
  2. emits the new data automatically via a Flow.
  3. The Repository exposes this Flow.
  4. The ViewModel collects it and updates the StateFlow.
  5. automatically redraws the screen.

4. Periodic Reconciliation

Because real-time tracking can be messy, we use “Reconciliation Workers” (like DailyProcessingWorker). These run every 15 minutes or once a day to:
  • Compress raw event logs into daily summaries.
  • Calculate strict limit usage.
  • Clean up old data to keep the app lightweight.

Where to Start?

If you are new to the codebase, we recommend exploring in this order:
  1. AppDatabase.kt: Understand the data models (Entities).
  2. AppModule.kt: See how the pieces are wired together using .
  3. AppCategoryViewModel.kt: Look at a standard UI implementation.
Last modified on January 22, 2026