Architecture Document: LocusFlow

KotlinJetpack ComposeMVVMRoomHiltCoroutines + FlowNavigation ComposeOn-device LLM
Presentation
Compose screens, ViewModels, UI state
Domain
Use cases, domain models, business rules
On-Device LLM
LEAP SDK, on-device inference
Data
Room DB, DAOs, repository implementations
User Settings
Extensible user preferences
Local-firstOn-device LLMZero telemetryNo cloud deps

High-Level Architecture

Three-Layer Architecture

The app follows a standard three-layer architecture:

  1. Presentation Layer (UI)

    • Jetpack Compose screens and components
    • ViewModels for state management
    • UI state classes
    • Navigation graph
    • Handles user interactions and displays data
  2. Domain Layer (Business Logic)

    • Use cases for business operations
    • Domain models (pure Kotlin classes)
    • Business rules and validation
    • Orchestrates data flow between UI and data layers
  3. Data Layer

    • Repository implementations
    • Room database and DAOs
    • Data models (entities)
    • Data source abstractions
    • Handles data persistence and retrieval
    • Module Structure
app/
├── ui/                              # Presentation layer (ADR-0025)
│   ├── navigation/                  # Route constants & NavHost orchestrator
│   │   ├── NavGraph.kt              # Thin orchestrator — calls per-feature extensions
│   │   └── NavigationRoutes.kt
│   ├── features/                    # One sub-package per screen/feature
│   │   ├── inbox/                   # Capture & inbox
│   │   ├── processing/              # Processing flow (type/subtype classification)
│   │   ├── nextactions/             # Filtered actionable items
│   │   ├── edititem/                # Edit processed items
│   │   ├── reflection/              # Daily reflection
│   │   ├── someday/                 # Someday/Maybe list
│   │   ├── reference/               # Reference items
│   │   ├── morning/                 # Morning briefing
│   │   └── llm/                     # Model download UI, status banner
│   ├── components/                  # Shared composables (cross-feature)
│   └── theme/                       # Material theme + design tokens
├── domain/
│   ├── model/                       # Domain models
│   ├── usecase/                     # Business logic use cases
│   ├── llm/                         # LlmService, LlmConfig, LlmResult, PromptTemplate,
│   │                                # PromptTemplateRepository, ReflectionSummaryState
│   └── repository/                  # Repository interfaces
├── data/
│   ├── local/
│   │   ├── database/                # Room database
│   │   ├── dao/                     # Data access objects
│   │   └── entity/                  # Database entities
│   ├── llm/                         # LeapLlmService, ModelManager, ModelState,
│   │                                # LocalPromptTemplateRepository
│   └── repository/                  # Repository implementations
└── di/                              # Hilt modules (DatabaseModule, RepositoryModule,
                                     # LlmModule, LlmProvidesModule)

Key Design Patterns

Repository Pattern

Each major feature has a repository interface in the domain layer with concrete implementation in the data layer. This abstracts data sources from business logic.

interface InboxRepository {
    suspend fun addItem(item: InboxItem): Long
    fun getAllItems(): Flow<List<InboxItem>>
    suspend fun deleteItem(id: Long)
}

Use Case Pattern

Business operations are encapsulated in single-responsibility use cases:

class SummarizeDailyReflectionUseCase(
    private val reflectionRepository: ReflectionRepository,
    private val llmService: LlmService
) {
    suspend operator fun invoke(dayKey: String): LlmResult
}

Current use cases: GetDailyReflectionUseCase, SaveReflectionUseCase, SummarizeDailyReflectionUseCase. Processing logic currently lives in ViewModels; dedicated use cases may be extracted as complexity grows.

Repository Interfaces

The domain layer defines repository interfaces for each data domain:

  • InboxRepository — inbox item CRUD
  • ProcessedItemRepository — processed item CRUD and filtering
  • ReflectionRepository — daily reflection persistence
  • CategoryRepository — category definitions (user-customizable)
  • ContextRepository — context definitions (user-customizable)
  • TagRepository — tag operations

State Management

Each screen has a corresponding ViewModel that exposes UI state via StateFlow:

class InboxViewModel @Inject constructor(
    private val inboxRepository: InboxRepository
) : ViewModel() {
    val uiState: StateFlow<InboxUiState>
}