Code

The Room cache — Entity, DAO, Database

Three files in the code column as tabs, in dependency order: MenuItemEntity.ktMenuDao.ktPicaDatabase.kt (a row, then how you read/write it, then the database that holds it).

1. MenuItemEntity.kt — the cache row. It's separate from the domain MenuItem (lesson 2): the entity lives in core/data/local (the storage layer), carries @Entity and @PrimaryKey, while MenuItem stays the clean model the UI renders. We map between them.

First add the Room dependencies in build.gradle.kts (stack-when-needed; Room 2.x, not 3.0):

implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.ktx)      // Flow + suspend support
ksp(libs.androidx.room.compiler)            // plugin: id("androidx.room") + id("com.google.devtools.ksp")

2. MenuDao.kt — how you read and write. The key asymmetry: reads return a Flow (a live stream — the UI re-renders when the table changes), writes are suspend (insertAll, clearAll).

3. PicaDatabase.kt — the database itself: @Database(entities = [MenuItemEntity::class], version = 1), exposing menuDao().

Gotcha (schema migration). version = 1 matters. If you later change the entity (add a column) and don't bump the version, Room throws an IllegalStateException about a schema mismatch. And if you bump the version (version = 2) without a migration you get:

java.lang.IllegalStateException: A migration from 1 to 2 was required but not found.

Fixes: write a Migration(1, 2) (preserves data), or — for a cache — .fallbackToDestructiveMigration() (drops and rebuilds; fine for a cache, since the server is the source of truth). Never just bump the version "to make it compile."