Skip to main content

Overview

The in/db module serves as the application’s “Source of Truth.” It is a sophisticated persistence layer built on that transforms high-frequency raw system events into actionable user insights. This module doesn’t just store data; it manages a complex pipeline where raw accessibility and usage logs are distilled into sessions, daily summaries, and a “User Journey” timeline. It also handles the state for the app’s core value proposition: App Limits and Nudges.

Architecture & Data Flow

The database architecture follows a tiered approach, moving from high-cardinality raw logs to low-cardinality aggregated insights.

Key Components

1. The Event Log (Raw Data)

  • RawAppEvent: Captures every interaction, including app foregrounding, scrolls, and notification arrivals. It supports multiple sources like USAGE_STATS and ACCESSIBILITY.
  • NotificationRecord: A specialized log for system notifications, tracking their “impact” (Passive vs. Interruption) and batching status.

2. Aggregated Sessions

  • UnlockSessionRecord: Tracks the time between a device unlock and lock, identifying “Compulsive Checks” and “Notification Driven” unlocks.
  • ScrollSessionRecord: Quantifies physical scrolling distance in pixels or micrometers, providing a more visceral metric of “doomscrolling” than simple time-on-app.

3. Wellbeing Enforcement

  • LimitGroup & LimitedApp: Defines user-created buckets of apps (e.g., “Social Media”) and their daily time quotas.
  • SnoozeHistoryEntity: Implements a sophisticated “Snooze” logic with phases (Compassion, Reflection, Deliberate) to prevent mindless limit bypassing.

4. Materialized Views for UI

  • UserJourney: A optimized for the timeline UI. Instead of querying three different tables at runtime, the app reads from this pre-computed table.

Operational Logic

Initialization & Sync

When the app starts or a new app is installed, the AppMetadataDao and AppCategoryDao work together to identify the app and fetch its category (e.g., “Productivity”) from a remote API. This is managed via a CategoryStatus state machine (NEEDS_CHECK -> SYNCED).

Reactive State Management

The module heavily utilizes in its methods. This ensures that when a background service updates the DailyAppUsageRecord, the UI automatically refreshes without a manual reload.

Data Engineering & Transformation

The system performs significant “On-Device ETL” (Extract, Transform, Load):
  • Source Tables: raw_app_events, notifications.
  • Transformation: The UserJourney table is regenerated by joining raw events with session data to create a chronological narrative of the user’s day.
  • Performance: Heavy write operations (like inserting batches of raw events) use OnConflictStrategy.IGNORE and are intended to be wrapped in using Dispatchers.IO.

Data Retention (TTL)

To prevent the local database from growing indefinitely, several DAOs implement logic:
  • RawAppEventDao.deleteEventsOlderThan(cutoff)
  • UserJourneyDao.deleteJourneysOlderThan(dateString)
  • DailyAppUsageDao.deleteOldUsageData(timestamp)

Dependencies

DependencyPurpose
RoomPrimary for SQLite.
HiltProvides the AppDatabase and DAO instances via .
SharedPreferencesUsed via NudgeStateStore for lightweight, non-relational flags like last_any_nudge_ms.

Technical Terms Glossary

  • UDF:
  • ViewModel:
  • StateFlow:
  • LiveData:
Last modified on January 22, 2026