fix(db): numbered migrations that run once and fail loudly (FLAW-13)

schema_migrations records every applied step; the former migrate() is
step 3, the baseline that builds the v0.4.1 schema and repairs older
databases. Columns are only added when missing, so every other error now
stops the start with a clear message instead of being swallowed, and the
cleanup statements no longer run on each start. migrations/001_init.sql
was never read and is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-29 14:49:35 +01:00
1 parent f57a9884d1
commit dc44f8250c
10 files changed
+222 -155

No files matched your search

+5 -4
View File
@@ -72,7 +72,7 @@ type docQueryer interface {
}
// migrateDocSync adds the columns and tables of the collaboration model and converts old flat block lists.
func (s *Store) migrateDocSync() {
func (s *Store) migrateDocSync() error {
stmts := []string{
"ALTER TABLE blocks ADD COLUMN parent_id TEXT NOT NULL DEFAULT '';",
"ALTER TABLE blocks ADD COLUMN order_key TEXT NOT NULL DEFAULT '';",
@@ -110,15 +110,16 @@ func (s *Store) migrateDocSync() {
"CREATE INDEX IF NOT EXISTS idx_doc_op_results_created ON doc_op_results(created_at);",
}
for _, q := range stmts {
if _, err := s.db.Exec(q); err != nil && !strings.Contains(err.Error(), "duplicate column") {
slog.Error("Migration der Notiz-Synchronisation fehlgeschlagen", "error", err, "statement", q)
if err := s.execSchemaStatement(q); err != nil {
return err
}
}
// Tombstones from before deleted_at existed start their retention now
if _, err := s.db.Exec(`UPDATE blocks SET deleted_at = ? WHERE deleted = 1 AND deleted_at = ''`, domain.NowISO()); err != nil {
slog.Error("Migration der Notiz-Synchronisation fehlgeschlagen", "error", err)
return err
}
s.backfillBlockTree()
return nil
}
// backfillBlockTree converts blocks stored as a flat list (level + position) into parent_id + order_key.