chore(db): stop wiping databases with an older schema version
All installations are past schema version 2, so the one-time reset is gone; data is never deleted on start (demo mode still resets). user_version is kept for future migrations. Legal test uses an in-memory DB (cleanup race). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1df32ece92
commit
108d166990
5 files changed
+12
-25
No files matched your search
+1
-1
@@ -80,7 +80,7 @@ teams 1─n team_members n─1 users
|
||||
- `users.username` wird aus dem E-Mail-Präfix aufgefüllt.
|
||||
- Notiz-Synchronisation (`migrateDocSync`): neue Spalten an `blocks` (inkl. `deleted_at`; vorhandene Grabsteine erhalten den Migrationszeitpunkt) und `documents` (`head_seq`, `title_version`, `log_floor`), Tabellen `doc_ops` und `doc_op_results`. Blöcke im alten flachen Format (nur `level`/`position`) werden einmalig in den Baum umgewandelt.
|
||||
- Standardwerte in `system_settings` (`INSERT OR IGNORE`): `sharing_mode=organizations`, `allow_registration=false`, `instance_name=MindSift`, SMTP leer.
|
||||
- **Schema-Version:** `PRAGMA user_version` hält `schemaVersion` (derzeit 2). Ist die Datenbank älter, werden vor allem anderen **alle Tabellen gelöscht** und neu angelegt. Bewusst so, solange MindSift nicht produktiv läuft.
|
||||
- **Schema-Version:** `PRAGMA user_version` hält `schemaVersion` (derzeit 2), damit spätere Versionen erkennen, welche Migrationen eine Datenbank schon hat. Daten werden beim Start nie gelöscht (das einmalige Zurücksetzen auf Version 2 ist entfernt, alle Installationen sind darüber hinweg). Nur der Demo-Modus leert die Datenbank bei jedem Start.
|
||||
|
||||
## Sicherung
|
||||
|
||||
|
||||
+1
-1
@@ -115,7 +115,7 @@ Schweregrade: **Hoch** (Datenabfluss oder Rechteumgehung möglich), **Mittel** (
|
||||
- **Maßnahme:** Fälligkeit mit Uhrzeit speichern, `alarm_sent` bei Änderung von `due_date` zurücksetzen, Wiederholungen begrenzen.
|
||||
|
||||
### FLAW-13: Migrationen
|
||||
- **Teilweise behoben:** Das Schema hat eine Version (`PRAGMA user_version`, `schemaVersion` in `sqlite.go`). Ist eine Datenbank älter, wird sie beim Start **komplett gelöscht** und neu angelegt (vor dem produktiven Einsatz bewusst so gewählt). Die übrigen Punkte unten gelten weiter.
|
||||
- **Teilweise behoben:** Das Schema hat eine Version (`PRAGMA user_version`, `schemaVersion` in `sqlite.go`), auf die künftige Migrationen aufsetzen können. Die übrigen Punkte unten gelten weiter.
|
||||
- **Fundstellen:** `Store.migrate` in [`internal/storage/sqlite.go`](../internal/storage/sqlite.go), [`migrations/001_init.sql`](../migrations/001_init.sql).
|
||||
- **Probleme:**
|
||||
- Es gibt keine Versionstabelle. Alle `ALTER TABLE`-Anweisungen laufen bei jedem Start erneut; Fehler werden pauschal ignoriert (`_, _ = s.db.Exec(q)`), echte Fehler fallen nicht auf.
|
||||
|
||||
@@ -1369,7 +1369,8 @@ func TestFirstBootSetupWithSampleData(t *testing.T) {
|
||||
|
||||
// Impressum and Datenschutz must be reachable without login; unset texts stay hidden.
|
||||
func TestLegalTextsArePublic(t *testing.T) {
|
||||
dbPath := filepath.Join(t.TempDir(), "legal.db")
|
||||
// In memory: no files the cleanup could race with
|
||||
dbPath := ":memory:"
|
||||
store, err := storage.NewStore(dbPath)
|
||||
if err != nil {
|
||||
t.Fatalf("NewStore: %v", err)
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
@@ -58,22 +57,11 @@ func (s *Store) Close() error {
|
||||
return s.db.Close()
|
||||
}
|
||||
|
||||
// schemaVersion is stored in PRAGMA user_version. Databases from an older version are wiped and rebuilt
|
||||
// on start: MindSift is not in production yet, so breaking changes need no migration path.
|
||||
// schemaVersion is stored in PRAGMA user_version so later releases can tell which migrations a database
|
||||
// already has. (Version 2 once wiped older databases on start; all installations are past that now.)
|
||||
const schemaVersion = 2
|
||||
|
||||
func (s *Store) resetOutdatedSchema() error {
|
||||
var version int
|
||||
if err := s.db.QueryRow(`PRAGMA user_version`).Scan(&version); err != nil {
|
||||
return err
|
||||
}
|
||||
if version >= schemaVersion {
|
||||
return nil
|
||||
}
|
||||
slog.Warn("Veraltetes Datenbankschema: alle Daten werden gelöscht und neu angelegt", "version", version, "neu", schemaVersion)
|
||||
return s.dropAllTables()
|
||||
}
|
||||
|
||||
// dropAllTables removes every table; used by the demo mode reset.
|
||||
func (s *Store) dropAllTables() error {
|
||||
conn, err := s.db.Conn(context.Background())
|
||||
if err != nil {
|
||||
@@ -107,9 +95,6 @@ func (s *Store) dropAllTables() error {
|
||||
}
|
||||
|
||||
func (s *Store) migrate() error {
|
||||
if err := s.resetOutdatedSchema(); err != nil {
|
||||
return fmt.Errorf("reset outdated schema: %w", err)
|
||||
}
|
||||
schema := `
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA synchronous = NORMAL;
|
||||
|
||||
@@ -144,8 +144,9 @@ func TestVisibilityFollowsOrganizations(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutdatedSchemaIsWiped(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "old.db")
|
||||
// Existing data must survive a restart, whatever user_version the database carries.
|
||||
func TestDataSurvivesRestart(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "keep.db")
|
||||
store, err := NewStore(path)
|
||||
if err != nil {
|
||||
t.Fatalf("NewStore failed: %v", err)
|
||||
@@ -159,8 +160,8 @@ func TestOutdatedSchemaIsWiped(t *testing.T) {
|
||||
t.Fatalf("reopen failed: %v", err)
|
||||
}
|
||||
defer store.Close()
|
||||
if n, _ := store.CountUsers(); n != 0 {
|
||||
t.Fatalf("outdated database should start empty, found %d users", n)
|
||||
if n, _ := store.CountUsers(); n != 1 {
|
||||
t.Fatalf("data must be kept on restart, found %d users", n)
|
||||
}
|
||||
var v int
|
||||
_ = store.db.QueryRow(`PRAGMA user_version`).Scan(&v)
|
||||
|
||||
Reference in new issue
Block a user