diff --git a/app/src/main/java/app/closer/data/local/ConversationCacheDao.kt b/app/src/main/java/app/closer/data/local/ConversationCacheDao.kt new file mode 100644 index 00000000..7c96ab74 --- /dev/null +++ b/app/src/main/java/app/closer/data/local/ConversationCacheDao.kt @@ -0,0 +1,24 @@ +package app.closer.data.local + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import app.closer.data.local.entity.ConversationCacheEntity + +@Dao +interface ConversationCacheDao { + + /** Idempotent restore: re-restoring the same message id replaces (latest-wins). */ + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun upsertAll(rows: List) + + @Query("SELECT * FROM conversation_cache WHERE conversationId = :conversationId ORDER BY createdAt ASC") + suspend fun forConversation(conversationId: String): List + + @Query("SELECT COUNT(*) FROM conversation_cache") + suspend fun count(): Int + + @Query("DELETE FROM conversation_cache") + suspend fun clear() +} diff --git a/app/src/main/java/app/closer/data/local/ConversationCacheDatabase.kt b/app/src/main/java/app/closer/data/local/ConversationCacheDatabase.kt new file mode 100644 index 00000000..9e85520d --- /dev/null +++ b/app/src/main/java/app/closer/data/local/ConversationCacheDatabase.kt @@ -0,0 +1,14 @@ +package app.closer.data.local + +import androidx.room.Database +import androidx.room.RoomDatabase +import app.closer.data.local.entity.ConversationCacheEntity + +/** + * Separate Room DB for the restored conversation cache — kept apart from the asset-backed [AppDatabase] + * (the prepopulated question bank) so backup/restore never risks that DB's asset schema hash. + */ +@Database(entities = [ConversationCacheEntity::class], version = 1, exportSchema = false) +abstract class ConversationCacheDatabase : RoomDatabase() { + abstract fun conversationCacheDao(): ConversationCacheDao +} diff --git a/app/src/main/java/app/closer/data/local/entity/ConversationCacheEntity.kt b/app/src/main/java/app/closer/data/local/entity/ConversationCacheEntity.kt new file mode 100644 index 00000000..e1a29568 --- /dev/null +++ b/app/src/main/java/app/closer/data/local/entity/ConversationCacheEntity.kt @@ -0,0 +1,25 @@ +package app.closer.data.local.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +/** + * A restored/backed-up message in the local durable conversation cache. Keyed by the Firestore + * message id so restore is idempotent (upsert = latest-wins on re-restore). `encText` keeps the + * `enc:v1:` body verbatim; `reactionsJson` is a small JSON object of uid→emoji. This store is the + * source of truth for restored history and the foundation for the later Option-B switch. + */ +@Entity(tableName = "conversation_cache") +data class ConversationCacheEntity( + @PrimaryKey val messageId: String, + val conversationId: String, + val conversationType: String, + val authorUserId: String, + val type: String, + val encText: String?, + val mediaUrl: String?, + val durationMs: Long?, + val createdAt: Long, + val deleted: Boolean, + val reactionsJson: String +)