DB-Migration: Datenverlust bei App-Updates verhindern #49

Closed
opened 2026-05-16 11:02:52 +00:00 by jreinemann-euris · 1 comment
jreinemann-euris commented 2026-05-16 11:02:52 +00:00 (Migrated from github.com)

Ziel

App-Updates dürfen unter keinen Umständen gespeicherte Daten löschen. Bei jedem Schema-Wechsel der Room-Datenbank muss eine automatische Migration stattfinden, die bestehende Daten vollständig erhält.

Problem

Ohne explizite Migrationsstrategie löscht Room bei Schema-Änderungen die gesamte Datenbank (fallbackToDestructiveMigration). Für eine Inventar-App, in der User ihre Vorräte mühsam erfasst haben, ist das inakzeptabel.

Anforderungen

1. Automatische DB-Migration beim Erststart einer neuen Version

  • Beim ersten Start nach einem App-Update erkennt die App, ob die DB-Version sich geändert hat
  • Für jede Versionsänderung existiert eine definierte Room-Migration (Migration(X, Y))
  • Migrationen werden vor dem normalen App-Start ausgeführt
  • fallbackToDestructiveMigration ist verboten und darf nicht im Code vorkommen

2. Interaktive Migration bei neuen Pflichtfeldern

  • Kommen durch ein Update neue Pflichtfelder hinzu (z.B. ein neues Feld ohne sinnvollen Default), wird der User beim Erststart nach dem Update gefragt
  • Beispiel: Neues Pflichtfeld "Lagertemperatur" → Dialog: "Welche Standard-Lagertemperatur soll für bestehende Artikel gesetzt werden?"
  • Der User kann einen Wert wählen oder "Später einzeln pflegen" auswählen
  • Erst nach Abschluss der interaktiven Migration startet die App normal

3. Migrations-Checkliste für Entwickler

Jede Schema-Änderung muss folgende Schritte durchlaufen:

  • Room-Migration (SQL ALTER TABLE / neue Tabelle) geschrieben
  • DB-Versionsnummer hochgezählt
  • Interaktive Migration implementiert (falls neue Pflichtfelder ohne Default)
  • Migrationspfad getestet (alte DB → neue DB, Daten vollständig erhalten)
  • Mehrstufige Migration getestet (z.B. v3 → v5 über v4)

Technische Umsetzung

  • Room addMigrations() statt fallbackToDestructiveMigration()
  • MigrationManager-Klasse, die beim App-Start prüft, ob interaktive Eingaben nötig sind
  • Migrations-Screen (Compose) für User-Rückfragen, bevor die Haupt-Navigation geladen wird
  • Automatisierte Tests mit MigrationTestHelper für jeden Migrationspfad

Akzeptanzkriterien

  • fallbackToDestructiveMigration kommt im gesamten Projekt nicht vor
  • Jede DB-Schema-Änderung hat eine zugehörige Migration
  • Bestehende Daten bleiben bei jedem Update vollständig erhalten
  • Bei neuen Pflichtfeldern ohne sinnvollen Default wird der User beim Erststart gefragt
  • Migrationspfade sind automatisiert getestet (inkl. Sprung über mehrere Versionen)
  • Entwickler-Dokumentation beschreibt den Migrations-Workflow
## Ziel App-Updates dürfen **unter keinen Umständen** gespeicherte Daten löschen. Bei jedem Schema-Wechsel der Room-Datenbank muss eine automatische Migration stattfinden, die bestehende Daten vollständig erhält. ## Problem Ohne explizite Migrationsstrategie löscht Room bei Schema-Änderungen die gesamte Datenbank (fallbackToDestructiveMigration). Für eine Inventar-App, in der User ihre Vorräte mühsam erfasst haben, ist das inakzeptabel. ## Anforderungen ### 1. Automatische DB-Migration beim Erststart einer neuen Version - Beim ersten Start nach einem App-Update erkennt die App, ob die DB-Version sich geändert hat - Für jede Versionsänderung existiert eine definierte Room-Migration (Migration(X, Y)) - Migrationen werden **vor** dem normalen App-Start ausgeführt - `fallbackToDestructiveMigration` ist **verboten** und darf nicht im Code vorkommen ### 2. Interaktive Migration bei neuen Pflichtfeldern - Kommen durch ein Update neue Pflichtfelder hinzu (z.B. ein neues Feld ohne sinnvollen Default), wird der User beim Erststart nach dem Update gefragt - Beispiel: Neues Pflichtfeld "Lagertemperatur" → Dialog: "Welche Standard-Lagertemperatur soll für bestehende Artikel gesetzt werden?" - Der User kann einen Wert wählen oder "Später einzeln pflegen" auswählen - Erst nach Abschluss der interaktiven Migration startet die App normal ### 3. Migrations-Checkliste für Entwickler Jede Schema-Änderung muss folgende Schritte durchlaufen: - [ ] Room-Migration (SQL ALTER TABLE / neue Tabelle) geschrieben - [ ] DB-Versionsnummer hochgezählt - [ ] Interaktive Migration implementiert (falls neue Pflichtfelder ohne Default) - [ ] Migrationspfad getestet (alte DB → neue DB, Daten vollständig erhalten) - [ ] Mehrstufige Migration getestet (z.B. v3 → v5 über v4) ## Technische Umsetzung - Room `addMigrations()` statt `fallbackToDestructiveMigration()` - MigrationManager-Klasse, die beim App-Start prüft, ob interaktive Eingaben nötig sind - Migrations-Screen (Compose) für User-Rückfragen, bevor die Haupt-Navigation geladen wird - Automatisierte Tests mit `MigrationTestHelper` für jeden Migrationspfad ## Akzeptanzkriterien - [ ] `fallbackToDestructiveMigration` kommt im gesamten Projekt nicht vor - [ ] Jede DB-Schema-Änderung hat eine zugehörige Migration - [ ] Bestehende Daten bleiben bei jedem Update vollständig erhalten - [ ] Bei neuen Pflichtfeldern ohne sinnvollen Default wird der User beim Erststart gefragt - [ ] Migrationspfade sind automatisiert getestet (inkl. Sprung über mehrere Versionen) - [ ] Entwickler-Dokumentation beschreibt den Migrations-Workflow
jreinemann-euris commented 2026-05-16 12:52:20 +00:00 (Migrated from github.com)

Abgeschlossen (2026-05-16)

Durchgeführte Aufgaben

  • \ allbackToDestructiveMigration()\ aus \DatabaseModule\ entfernt – kommt im gesamten Projekt nicht mehr vor
  • \Migrations.kt\ mit \MIGRATION_1_2\ erstellt (Tabellen-Neubau wegen SQLite < 3.25 / minSdk 26): \kcal_per_100g\ → \kcal_per_kg, \min_stock\ entfernt
  • \ddMigrations(Migrations.MIGRATION_1_2)\ in \DatabaseModule\ eingetragen
  • \exportSchema = true\ + KSP-Argument
    oom.schemaLocation\ gesetzt; \pp/schemas/2.json\ eingecheckt
  • \pp/schemas/\ als androidTest-Asset-Quelle registriert (Basis für künftige \MigrationTestHelper.createDatabase()-Aufrufe)
  • \KrisenvorratDatabaseMigrationTest\ mit 4 instrumentierten Tests:
    • Datenerhalt nach Migration (kcalPerKg, name, notes)
    • Spalten-Schema korrekt (min_stock weg, kcal_per_kg da)
    • Indices vorhanden (category_id, location_id)
    • Fresh-Install funktioniert ohne Migration

Entwickler-Checkliste für künftige Schema-Änderungen

Steht als KDoc-Kommentar in \Migrations.kt:

  1. Migration(X, Y)-Objekt in \Migrations.kt\ ergänzen
  2. DB-Version in \KrisenvorratDatabase\ hochzählen
  3. Migration in \DatabaseModule.addMigrations()\ eintragen
  4. Test in \KrisenvorratDatabaseMigrationTest\ ergänzen (\MigrationTestHelper.createDatabase()\ ab V2 nutzbar)
  5. Bei neuen Pflichtfeldern ohne Default: interaktiven MigrationScreen ergänzen

Verifikation

  • ./gradlew assembleDebug\ → BUILD SUCCESSFUL
  • 408 Unit-Tests → alle grün
## Abgeschlossen (2026-05-16) ### Durchgeführte Aufgaben - ✅ \ allbackToDestructiveMigration()\ aus \DatabaseModule\ entfernt – kommt im gesamten Projekt nicht mehr vor - ✅ \Migrations.kt\ mit \MIGRATION_1_2\ erstellt (Tabellen-Neubau wegen SQLite < 3.25 / minSdk 26): \kcal_per_100g\ → \kcal_per_kg\, \min_stock\ entfernt - ✅ \ddMigrations(Migrations.MIGRATION_1_2)\ in \DatabaseModule\ eingetragen - ✅ \exportSchema = true\ + KSP-Argument \ oom.schemaLocation\ gesetzt; \pp/schemas/2.json\ eingecheckt - ✅ \pp/schemas/\ als androidTest-Asset-Quelle registriert (Basis für künftige \MigrationTestHelper.createDatabase()\-Aufrufe) - ✅ \KrisenvorratDatabaseMigrationTest\ mit 4 instrumentierten Tests: - Datenerhalt nach Migration (kcalPerKg, name, notes) - Spalten-Schema korrekt (min_stock weg, kcal_per_kg da) - Indices vorhanden (category_id, location_id) - Fresh-Install funktioniert ohne Migration ### Entwickler-Checkliste für künftige Schema-Änderungen Steht als KDoc-Kommentar in \Migrations.kt\: 1. Migration(X, Y)-Objekt in \Migrations.kt\ ergänzen 2. DB-Version in \KrisenvorratDatabase\ hochzählen 3. Migration in \DatabaseModule.addMigrations()\ eintragen 4. Test in \KrisenvorratDatabaseMigrationTest\ ergänzen (\MigrationTestHelper.createDatabase()\ ab V2 nutzbar) 5. Bei neuen Pflichtfeldern ohne Default: interaktiven MigrationScreen ergänzen ### Verifikation - \./gradlew assembleDebug\ → BUILD SUCCESSFUL ✅ - 408 Unit-Tests → alle grün ✅
Sign in to join this conversation.
No description provided.