Coverage Summary for Class: ConfigEntryEntity (com.georgeci.moneysurfer.data.db.entity)

Class Class, % Method, % Branch, % Line, % Instruction, %
ConfigEntryEntity 100% (1/1) 100% (1/1) 100% (5/5) 100% (24/24)


 package com.georgeci.moneysurfer.data.db.entity
 
 import androidx.room.ColumnInfo
 import androidx.room.Entity
 import androidx.room.PrimaryKey
 
 /**
  * One synced user setting — the storage behind every `SettingKey` declared `sync = true`.
  *
  * Room rather than DataStore for three reasons, in order of weight: the push plugin needs
  * `value + updatedAt` readable **by key** at push time, LWW needs a real `updatedAt` column to
  * compare against the remote document, and the storage boundary then coincides with the reset
  * boundary — this table joins the DAO fan-out in `LocalDataResetRepositoryImpl.clearAll()`, so an
  * account change cannot leave the previous user's settings behind. `sync = false` keys stay in
  * DataStore precisely because they must *not* be wiped (`ui.onboarding_completed`) or replicated.
  *
  * It is **not** transactional atomicity with the outbox: that lives in `SyncDatabase`
  * (`moneysurfer_sync.db`), a different database, so no table here can share a transaction with it.
  * The write-then-crash window is closed by the sign-in reconciliation instead — see
  * [lastPushedAt].
  *
  * No foreign key and no workspace column: settings are user-scoped, not workspace-scoped, which is
  * also why the matching sync plugin declares `scopeKey = null`.
  */
 @Entity(tableName = "config_entry")
 data class ConfigEntryEntity(
     /** The key *name* (`ui.theme_mode`), unprefixed — the same string used as the Firestore doc id. */
     @PrimaryKey @ColumnInfo(name = "key") val key: String,
     /** Codec-encoded value. Always a string: that is what every backing store has in common. */
     @ColumnInfo(name = "value") val value: String,
     /** Client-clock epoch millis of the last local write, and the basis of per-key LWW. */
     @ColumnInfo(name = "updatedAt") val updatedAt: Long,
     /**
      * `updatedAt` of the value last known to have reached Firestore, or `null` for a row that has
      * never been pushed.
      *
      * This is what makes the sign-in reconciliation cheap and exact: `OutboxEnqueuerImpl` silently
      * drops writes made in demo or signed-out sessions and nothing re-enqueues them, so before the
      * first pull of a real session every row with `lastPushedAt IS NULL OR updatedAt > lastPushedAt`
      * is queued. A pulled value is stamped as already-pushed, so a pull never provokes an echo push.
      */
     @ColumnInfo(name = "lastPushedAt") val lastPushedAt: Long? = null,
 )