Milestone 5. One BackupManager entry point so export, import and auto-backup share the same serializer and crypto by construction. Explicit DTOs decouple the backup contract from the Room schema. JCE baseline (PBKDF2-HMAC-SHA256 600k → AES-256-GCM) behind the BackupCrypto interface with format auto-detection on decrypt; age lands behind the same interface in milestone 6. SigV4 signer verified against AWS's published documentation example signature. Settings in SharedPreferences encrypted under a non-exportable AndroidKeyStore key — replaces the now fully deprecated androidx security-crypto with the same construction (~70 lines, zero deps); threat-model comments state plainly that the stored auto-backup passphrase only protects against bucket compromise. WorkManager daily periodic job, inexact by design. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
45 lines
1.4 KiB
Kotlin
45 lines
1.4 KiB
Kotlin
package no.naiv.meddetsamme.data
|
|
|
|
import android.content.Context
|
|
import androidx.room.Database
|
|
import androidx.room.Room
|
|
import androidx.room.RoomDatabase
|
|
|
|
/**
|
|
* exportSchema=true with schemas/ committed: this DB holds a medical record,
|
|
* so every future schema change ships as a tested Migration against the
|
|
* exported baseline — never destructive fallback.
|
|
*
|
|
* Enums are stored as TEXT (Room's built-in enum converter); all other columns
|
|
* are primitives, so no TypeConverters are needed yet.
|
|
*/
|
|
@Database(
|
|
entities = [Medication::class, DoseTime::class, DoseLog::class],
|
|
version = 1,
|
|
exportSchema = true,
|
|
)
|
|
abstract class MedDatabase : RoomDatabase() {
|
|
abstract fun medicationDao(): MedicationDao
|
|
abstract fun doseTimeDao(): DoseTimeDao
|
|
abstract fun doseLogDao(): DoseLogDao
|
|
abstract fun backupDao(): BackupDao
|
|
|
|
suspend fun restoreAll(
|
|
meds: List<Medication>,
|
|
doseTimes: List<DoseTime>,
|
|
logs: List<DoseLog>,
|
|
) = backupDao().replaceAll(meds, doseTimes, logs)
|
|
|
|
companion object {
|
|
@Volatile private var instance: MedDatabase? = null
|
|
|
|
fun get(context: Context): MedDatabase =
|
|
instance ?: synchronized(this) {
|
|
instance ?: Room.databaseBuilder(
|
|
context.applicationContext,
|
|
MedDatabase::class.java,
|
|
"med-det-samme.db",
|
|
).build().also { instance = it }
|
|
}
|
|
}
|
|
}
|