# DB Repair Playbook ## Symptome einer korrupten DB - `POST /api/sync/push` → 500, Server-Log zeigt `SqliteError: database disk image is malformed` - `GET /api/admin/integrity` → `{ ok: false, result: "..." }` - Startup-Log: `[db] integrity_check failed:` ## Ursachen - Azure App Service hat Container während eines laufenden SQLite-Writes neugestartet - WAL-Datei (`ka-note.db-wal`) war nicht committed beim Neustart - **Hinweis:** WAL-Mode ist aktiv (`journal_mode = WAL`) — schützt vor vielen, aber nicht allen Szenarien ## Schritt 1: Integrität prüfen ``` GET /api/admin/integrity → { ok: true/false, result: "ok" | "" } ``` Oder lokal nach DB-Download: ```cmd .\sqlite3.exe ka-note.db "PRAGMA integrity_check;" ``` ## Schritt 2: DB herunterladen (Kudu REST API) Deployment-Credentials aus Portal: **App Service → Deployment Center → FTPS credentials** ```powershell $user = 'ka-note\$ka-note' # anpassen $pass = 'deinPassword' $creds = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${user}:${pass}")) Invoke-WebRequest ` -Uri "https://ka-note.scm.azurewebsites.net/api/vfs/data/ka-note.db" ` -Headers @{ Authorization = "Basic $creds" } ` -OutFile "ka-note.db" (Get-Item "ka-note.db").Length # muss > 0 sein ``` sqlite3.exe herunterladen von https://www.sqlite.org/download.html (sqlite-tools-win-x64-*.zip) ## Schritt 3: DB reparieren ```powershell # 1. Dump erzeugen .\sqlite3.exe ka-note.db ".dump" > dump.sql # 2. Doppelte INSERT-Konflikte entschärfen + ROLLBACK→COMMIT (Get-Content dump.sql) -replace '^INSERT INTO', 'INSERT OR IGNORE INTO' | Set-Content dump-fixed.sql # 3. unistr()-Calls dekodieren (nötig wenn Server neueres SQLite als lokal) node fix-unistr.js # siehe unten # 4. Importieren (cmd.exe wegen Piping-Problemen in PowerShell) cmd /c ".\sqlite3.exe ka-note-repaired.db < dump-fixed2.sql" # 5. Integrität prüfen .\sqlite3.exe ka-note-repaired.db "PRAGMA integrity_check;" .\sqlite3.exe ka-note-repaired.db ".tables" .\sqlite3.exe ka-note-repaired.db "SELECT COUNT(*) FROM contexts; SELECT COUNT(*) FROM topics; SELECT COUNT(*) FROM history_entries;" ``` ### fix-unistr.js (im sqlite-Arbeitsverzeichnis ablegen) ```js import { readFileSync, writeFileSync } from 'fs'; let sql = readFileSync('dump-fixed.sql', 'utf8'); // unistr('\uXXXX') → plain UTF-8 string sql = sql.replace(/unistr\('((?:[^'\\]|\\.)*)'\)/g, (_, inner) => { const decoded = inner.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)) ); return `'${decoded}'`; }); // ROLLBACK at end of corrupt dump → COMMIT so import doesn't discard everything sql = sql.replace(/^ROLLBACK;.*$/m, 'COMMIT;'); writeFileSync('dump-fixed2.sql', sql, 'utf8'); console.log('done'); ``` **Kritisch:** Ein korrupter Dump endet mit `ROLLBACK; -- due to errors` statt `COMMIT;`. SQLite verwirft dann die gesamte Transaktion → 0-Byte-Zieldatei. Das Script ersetzt `ROLLBACK` durch `COMMIT`. ## Schritt 4: Reparierte DB hochladen ```powershell # App stoppen (DB darf nicht aktiv sein) az webapp stop --name ka-note --resource-group # Hochladen Invoke-RestMethod ` -Uri "https://ka-note.scm.azurewebsites.net/api/vfs/data/ka-note.db" ` -Method PUT ` -Headers @{ Authorization = "Basic $creds"; "Content-Type" = "application/octet-stream" } ` -InFile "ka-note-repaired.db" # App starten az webapp start --name ka-note --resource-group ``` ## Schritt 5: Verifizieren ``` GET /api/admin/integrity → { ok: true } GET /api/sync/status → Anzahl contexts/topics/history_entries prüfen ``` ## Präventionsmaßnahmen (umgesetzt) - **WAL-Mode** (`journal_mode = WAL`) — aktiv seit Beginn, schützt vor den meisten Write-Crashes - **Integrity-Check beim Start** — `[db] integrity_check ok` im Startup-Log sichtbar - **Integrity-Check vor Backup** — korrupte DB wird nicht als Backup gespeichert, Fehler im Log - **`GET /api/admin/integrity`** — on-demand prüfbar ohne Server-Zugriff - **Structured Error Logging** — alle Route-Handler loggen Fehler mit Label, Method, Path, Stack ## Bekannte Fallstricke | Problem | Ursache | Lösung | |---|---|---| | Download → 0 Byte | Falscher Pfad oder Auth | Pfad mit `/api/vfs/data/` prüfen | | Import → 0 Byte | PowerShell-Piping kaputt | `cmd /c sqlite3 < file` verwenden | | `unistr()` Fehler | Versionsunterschied sqlite3 | fix-unistr.js ausführen | | UNIQUE constraint | Doppelte Rows aus Korruption | `INSERT OR IGNORE` in dump-fixed.sql | | Alles verworfen | Dump endet mit ROLLBACK | ROLLBACK → COMMIT ersetzen (fix-unistr.js macht das) |