Database Schema & Operations Guide (Deutsch)
Warum SQLite?
Abschnitt betitelt „Warum SQLite?“OmniRoute hat sich aus mehreren Gründen für SQLite anstelle von PostgreSQL/MySQL entschieden:
| Faktor | SQLite | PostgreSQL |
|---|---|---|
| Bereitstellung | Eingebettet — kein separater Server | Erfordert die Einrichtung eines Servers |
| Verschlüsselung | Anwendungsebene (AES-256-GCM) | Integrierte TDE |
| Leistung | Schneller bei kleinen/mittleren Workloads | Besser für sehr viele gleichzeitige Schreibvorgänge |
| Nebenläufigkeit | WAL-Modus ermöglicht gleichzeitige Lesevorgänge | Vollständiges MVCC |
| Sicherung | Kopie einer einzelnen Datei | pg_dump oder Dateisystem-Snapshot |
| Anwendungsfall | Installation pro Benutzer, eingebettet | Mandantenfähiges SaaS |
Für Bereitstellungen mit einem Benutzer und einer einzelnen Instanz (der primäre Anwendungsfall von OmniRoute) ist SQLite einfacher und schneller.
WAL-Journaling
Abschnitt betitelt „WAL-Journaling“core.ts öffnet die Datenbank im WAL-Modus (Write-Ahead Logging):
db.pragma("journal_mode = WAL");db.pragma("busy_timeout = 2000");db.pragma("synchronous = NORMAL");db.pragma(`cache_size = -${DEFAULT_DATABASE_SETTINGS.optimization.cacheSize}`);WAL ermöglicht gleichzeitige Lesevorgänge während Schreibvorgängen — wichtig für das Dashboard, das Abfragen ausführt, während Anfragen aufgezeichnet werden.
Die standardmäßige Cache-Größe beträgt 65.536 KiB (64 MiB). SQLite interpretiert einen negativen
cache_size-Wert als ungefähre Obergrenze in KiB und weist Seiten nach Bedarf zu.
Unter Einstellungen > System & Speicher > Cache-Größe werden Ganzzahlwerte von 1 bis
1.000.000 KiB akzeptiert; beim Speichern der Einstellung wird sie auf die aktive Datenbankverbindung angewendet,
und OmniRoute stellt den gespeicherten Wert beim Start wieder her.
Datenbankspeicherort
Abschnitt betitelt „Datenbankspeicherort“Die SQLite-Datei wird hier gespeichert:
| Betriebssystem | Pfad |
|---|---|
| Linux | ~/.omniroute/storage.sqlite |
| macOS | ~/.omniroute/storage.sqlite |
| Windows | %USERPROFILE%\.omniroute\storage.sqlite |
| Docker | /app/data/storage.sqlite (konfigurierbar über DATA_DIR) |
Zugehörige Dateien:
storage.sqlite-wal— Write-Ahead-Logstorage.sqlite-shm— Shared-Memory-Dateicall_logs/— Artefakte von Anfrage-Payloads (sofern aktiviert)
Speicherort überschreiben:
DATA_DIR=/custom/path omnirouteArchitektur der Domänenmodule
Abschnitt betitelt „Architektur der Domänenmodule“Die Datenbank von OmniRoute umfasst 110 TypeScript-Module auf oberster Ebene in src/lib/db/. Jedes Domänenmodul:
- Ist für eine oder mehrere bestimmte Tabellen zuständig
- Exportiert typisierte CRUD-Funktionen
- Greift niemals auf die Tabellen eines anderen Moduls zu
- Verwendet
getDbInstance()auscore.ts, um auf die Datenbank zuzugreifen
Die 110 DB-Module auf oberster Ebene
Abschnitt betitelt „Die 110 DB-Module auf oberster Ebene“OmniRoute verfügt über 110 TypeScript-Dateien auf oberster Ebene in src/lib/db/. Nachfolgend finden Sie eine Auswahl der Kernmodule; die vollständige Liste finden Sie in der Verzeichnisauflistung:
| Modul | Tabellen | Zuständigkeit |
|---|---|---|
providers.ts |
provider_connections |
Registrierung und Anmeldedaten von Anbietern per OAuth/API-Schlüssel |
models.ts |
key_value (Modelldaten) |
Modelldefinitionen, Fähigkeiten und Preise |
combos.ts |
combos |
Konfigurationen und Reihenfolge des Combo-Routings |
apiKeys.ts |
api_keys |
Lebenszyklus von API-Schlüsseln, Geltungsbereiche und Kontingentverfolgung |
settings.ts |
key_value, api_keys, combos |
Systemkonfiguration und gemeinsam genutzter KV-Speicher |
backup.ts |
— | Operationen zum Exportieren und Importieren von Sicherungen |
proxies.ts |
proxy_registry, proxy_assignments, provider_connections |
Proxy-Konfigurationen und Routing-Regeln |
prompts.ts |
prompt_templates |
Wiederverwendbare Prompt-Vorlagen und Versionierung |
webhooks.ts |
webhooks |
Ereignisgesteuerte Webhook-Abonnements und Protokolle |
detailedLogs.ts |
request_detail_logs |
Audit-Protokollierung pro Anfrage (optional, hohes Volumen) |
domainState.ts |
domain_* (5 Tabellen) |
Domänenbudgets, Leistungsschalter, Sperren, Fallback-Ketten und Kostenverlauf |
registeredKeys.ts |
registered_keys, account_key_limits, provider_key_limits |
Zulässige API-Schlüssel für MCP/A2A |
quotaSnapshots.ts |
quota_snapshots |
Historische Kontingentnutzung |
modelComboMappings.ts |
model_combo_mappings |
Zuordnung von Modellen zu Combo-Standardeinstellungen |
cliToolState.ts |
cli_tool_state |
CLI-spezifischer persistenter Zustand |
encryption.ts |
— | Hilfsfunktionen zum Ver- und Entschlüsseln von Feldern |
readCache.ts |
— | In-Memory-Cache für leseintensive Operationen |
secrets.ts |
key_value (verschlüsselte Einträge) |
Verschlüsselte Speicherung geheimer Daten |
stateReset.ts |
— | Löschen/Zurücksetzen des Datenbankzustands für Tests |
contextHandoffs.ts |
context_handoffs |
Sitzungskontext für die Übergabe zwischen Agenten |
usage*.ts |
usage_history, call_logs, proxy_logs |
Nutzungsverfolgung |
compression*.ts |
compression_settings, compression_combos |
Komprimierungskonfiguration |
Modulgrenzen
Abschnitt betitelt „Modulgrenzen“Eine zentrale Architekturregel lautet: Module greifen nicht direkt auf die Tabellen anderer Module zu. Um mit den Daten eines anderen Moduls zu arbeiten, importieren Sie die Funktion aus diesem Modul.
// ❌ FALSCH: direktes SQL aus einem anderen Moduldb.prepare("SELECT * FROM provider_connections").all();
// ✅ RICHTIG: Funktion des providers-Moduls verwendenimport { listProviders } from "@/lib/db/providers";const providers = await listProviders();Diese Regel wird bei Code-Reviews durchgesetzt — es gibt keine statische Prüfung, Verstöße werden jedoch beanstandet.
Basisschema (17 Tabellen)
Abschnitt betitelt „Basisschema (17 Tabellen)“core.ts definiert die 17 Basistabellen in SCHEMA_SQL. Diese werden durch die Migration 001_initial_schema.sql erstellt und bilden das Kernschema.
Kerntabellen (in der initialen Migration erstellt)
Abschnitt betitelt „Kerntabellen (in der initialen Migration erstellt)“| Tabelle | Zweck | Schlüsselspalten |
|---|---|---|
provider_connections |
Provider-Anmeldedaten (verschlüsselt) | id, provider, auth_type, api_key, is_active |
provider_nodes |
Routing-Informationen für Provider-Knoten | id, type, name, base_url, created_at |
key_value |
Allgemeiner KV-Speicher | namespace, key, value |
combos |
Definitionen von Routing-Kombinationen | id, name, data, sort_order |
api_keys |
API-Schlüssel für das Gateway | id, name, key, machine_id, allowed_models |
db_meta |
Datenbankmetadaten | key, value |
usage_history |
Datensätze zur Anfragenutzung | id, provider, model, tokens_input, tokens_output, timestamp |
call_logs |
Anfrage-Payloads und Antworten | id, timestamp, status, model, provider, latency_ms |
proxy_logs |
Protokolle von Proxy-Anfragen | id, timestamp, proxy_type, status, provider |
domain_fallback_chains |
Modell-zu-Provider-Ketten | model, chain |
domain_budgets |
Ausgabenbudgets pro Domäne | api_key_id, daily_limit_usd, warning_threshold, reset_interval |
domain_budget_reset_logs |
Verlauf der Budgetzurücksetzungen | id, api_key_id, reset_interval, previous_spend, reset_at |
domain_cost_history |
Kostenverfolgung pro Domäne | id, api_key_id, cost, timestamp |
domain_lockout_state |
Ratenbegrenzungsstatus der Domäne | identifier, attempts, locked_until |
domain_circuit_breakers |
Circuit-Breaker-Status pro Domäne | name, state, failure_count, last_failure_time |
semantic_cache |
Cache für LLM-Antworten | id, signature, model, prompt_hash, response |
quota_snapshots |
Historische Kontingent-Snapshots | id, provider, connection_id, window_key, remaining_percentage |
Zusätzliche Tabellen (durch spätere Migrationen hinzugefügt)
Abschnitt betitelt „Zusätzliche Tabellen (durch spätere Migrationen hinzugefügt)“Nachfolgende Migrationen fügen unter anderem folgende Tabellen hinzu:
cli_tool_state(Migration 011) — Status des CLI-Toolsmcp_*-Tabellen — MCP-Server-Audita2a_*-Tabellen — A2A-Aufgabenstatususage_*-Tabellen — Nutzungsverfolgungplugin_*-Tabellen — Plugin-Systemskill_executions— Ausführungsverlauf von Skillsmemory_*-Tabellen — Speichersystemcompression_*-Tabellen — Komprimierungssystemwebhook_*-Tabellen — Webhook-Zustellungsprotokollacp_*-Tabellen — Agent Client Protocoloneproxy_*-Tabellen — 1proxy-Marktplatzproxy_assignments— Bindungen des Proxy-Gültigkeitsbereichsdetailed_call_artifacts— Metadaten zu Artefakten von Aufrufprotokollenquota_alert_history— Audit von Kontingentwarnungencommand_code_auth_sessions— Command Code-OAuth-Sitzungen
Die vollständige Liste mit über 30 Tabellen befindet sich in src/lib/db/migrations/.
Migrationen
Abschnitt betitelt „Migrationen“OmniRoute verwendet versionierte, idempotente Migrationen in src/lib/db/migrations/. Jede Migration ist eine einzelne SQL-Datei mit dem Namen NNN_description.sql.
Benennung von Migrationen
Abschnitt betitelt „Benennung von Migrationen“001_initial_schema.sql002_mcp_a2a_tables.sql003_provider_node_custom_paths.sql...021_combo_call_log_targets.sqlAusführung von Migrationen
Abschnitt betitelt „Ausführung von Migrationen“Beim Start führt migrationRunner.ts folgende Schritte aus:
- Erstellt die Tabelle
_omniroute_migrations, falls sie nicht existiert - Fragt bereits angewendete Migrationen ab
- Wendet alle neuen Migrationen der Reihe nach an, jeweils innerhalb einer Transaktion
- Zeichnet jede angewendete Migration mit einem Zeitstempel auf
// src/lib/db/migrationRunner.ts (vereinfacht)export async function runMigrations(db: SqliteDatabase, migrationsDir: string) { const applied = getAppliedMigrations(db); const available = readMigrationFiles(migrationsDir);
for (const migration of available) { if (applied.includes(migration.id)) continue; db.transaction(() => { db.exec(migration.sql); recordAppliedMigration(db, migration.id); })(); }}Idempotenz
Abschnitt betitelt „Idempotenz“Migrationen müssen idempotent sein — eine zweimalige Ausführung sollte keine Auswirkungen haben:
-- 004_proxy_registry.sqlCREATE TABLE IF NOT EXISTS proxy_registry ( id TEXT PRIMARY KEY, host TEXT NOT NULL, port INTEGER NOT NULL, ...);Verwenden Sie großzügig die Klauseln IF NOT EXISTS, IF EXISTS und OR IGNORE / OR REPLACE.
Hinzufügen einer neuen Migration
Abschnitt betitelt „Hinzufügen einer neuen Migration“- Nächste Nummer ermitteln:
ls src/lib/db/migrations/ | tail -1 - Datei erstellen:
NNN_my_change.sql - Sicheres DDL verwenden:
CREATE TABLE IF NOT EXISTS,ALTER TABLE ... ADD COLUMN - Daten sorgfältig nachpflegen: Verwenden Sie
UPDATE ... WHERE ..., um vorhandene Zeilen zu berücksichtigen - An einer Kopie testen: Führen Sie niemals ungetestete Migrationen in der Produktion aus
Beispiel:
-- 022_add_combo_priority.sqlALTER TABLE combos ADD COLUMN priority INTEGER DEFAULT 100;UPDATE combos SET priority = 100 WHERE priority IS NULL;CREATE INDEX IF NOT EXISTS idx_combos_priority ON combos(priority);Nicht abwärtskompatible Änderungen (z. B. das Löschen von Spalten) sind problematisch. OmniRoute unterstützt KEIN Downgrade — sobald eine Migration angewendet wurde, ist die Schemaänderung dauerhaft. Planen Sie entsprechend.
Verschlüsselung ruhender Daten
Abschnitt betitelt „Verschlüsselung ruhender Daten“Sensible Felder (API-Schlüssel, OAuth-Token, Verbindungszeichenfolgen) werden im Ruhezustand mit AES-256-GCM verschlüsselt.
Funktionsweise
Abschnitt betitelt „Funktionsweise“// src/lib/db/encryption.ts (vereinfacht)const key = deriveKeyFromPassphrase(passphrase, salt);const iv = randomBytes(12);const cipher = createCipheriv("aes-256-gcm", key, iv);const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);const authTag = cipher.getAuthTag();return { encrypted, iv, authTag };Verwendungsorte
Abschnitt betitelt „Verwendungsorte“provider_connections.api_key— auf Anwendungsebene verschlüsseltprovider_connections.access_token,refresh_token,id_token— auf Anwendungsebene verschlüsseltkey_value-Einträge mitnamespace = "secrets"— auf Anwendungsebene verschlüsseltproxy_registry.auth— auf Anwendungsebene verschlüsselt (falls vorhanden)
Verschlüsselungsschlüssel
Abschnitt betitelt „Verschlüsselungsschlüssel“Der Verschlüsselungsschlüssel wird aus einer Passphrase (festgelegt über die Umgebungsvariable STORAGE_ENCRYPTION_KEY) und einem Salt (in der Datenbank gespeichert) abgeleitet. Beide sind erforderlich, um Daten zu entschlüsseln.
# Eine sichere Passphrase generierenopenssl rand -hex 32
# In .env festlegenSTORAGE_ENCRYPTION_KEY=<your-key>Kritisch: Der Verlust des Verschlüsselungsschlüssels bedeutet, dass der Zugriff auf alle verschlüsselten Daten verloren geht. Sichern Sie den Schlüssel getrennt von der Datenbank.
Nicht verschlüsselte Daten
Abschnitt betitelt „Nicht verschlüsselte Daten“Aus Leistungsgründen werden folgende Daten im Klartext gespeichert:
- Anzeigenamen der Anbieter
- Modelldefinitionen (bereits öffentlich)
- Routingregeln
- Nutzungsdatensätze (keine personenbezogenen Daten)
Hinweise zur Verschlüsselung (v3.8.16+)
Abschnitt betitelt „Hinweise zur Verschlüsselung (v3.8.16+)“OmniRoute verwendet migrateLegacyEncryptedString(), um zwei Verschlüsselungsverfahren transparent zu handhaben:
- Legacy (vor v3.5.0): XOR-basierte „Verschlüsselung“ (keine echte Kryptografie)
- Aktuell: AES-256-GCM mit korrektem IV und Authentifizierungs-Tag
Die Migrationshilfsfunktion erkennt das Legacy-Format und verschlüsselt die Daten beim ersten Lesen mit dem neuen Verfahren erneut. Das bedeutet, dass Sie eine alte Datenbank aktualisieren können, ohne Zugangsdaten zu verlieren.
Lese-Cache
Abschnitt betitelt „Lese-Cache“Für häufig gelesene Daten (Modelle, Anbieter, Einstellungen) stellt readCache.ts einen In-Memory-Cache bereit:
// Beim Start zwischengespeichert, beim Schreiben invalidiertconst providers = await getCachedProviders(); // Schnell, im Arbeitsspeicherconst fresh = await listProviders(); // Langsam, greift auf die DB zu| Zwischengespeicherte Entität | Cache-Schlüssel | TTL |
|---|---|---|
models |
models:v1 |
Bis zum Schreibvorgang |
provider_connections |
providers:v1 |
Bis zum Schreibvorgang |
settings |
settings:v1 |
Bis zum Schreibvorgang |
combos |
combos:v1 |
Bis zum Schreibvorgang |
Der Cache wird bei jedem Schreibvorgang in die entsprechende Tabelle invalidiert.
Sicherung und Wiederherstellung
Abschnitt betitelt „Sicherung und Wiederherstellung“Manuelle Sicherung
Abschnitt betitelt „Manuelle Sicherung“# CLI verwenden, um eine lokale Sicherung zu erstellenomniroute backup create --name pre-migration
# Oder über die APIcurl -X PUT http://localhost:20128/api/db-backups \ -H "Authorization: Bearer $MANAGEMENT_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "pre-migration"}'Die Sicherungsdatei enthält:
- Alle DB-Tabellen (als JSON serialisiert)
- Aufrufprotokoll-Artefakte (Base64-kodiert, optional)
- Einstellungen + Geheimnisse (verschlüsselt)
- Plugin-Konfiguration
Wiederherstellung
Abschnitt betitelt „Wiederherstellung“# Über die CLIomniroute restore pre-migration
# Über die APIcurl -X POST http://localhost:20128/api/db-backups/restore \ -H "Authorization: Bearer $MANAGEMENT_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "pre-migration"}'Warnung: Die Wiederherstellung überschreibt die gesamte DB. Stoppen Sie zuerst alle Clients.
Automatisierte Sicherungen
Abschnitt betitelt „Automatisierte Sicherungen“# Automatisierte tägliche Sicherungen über die CLI aktivierenomniroute backup auto enable --cron "0 2 * * *" --retention 7Der Zeitplan wird serverseitig durch einen Hintergrundjob ausgeführt, der standardmäßig alle 30 Sekunden aktiv wird und den Cron-Ausdruck anhand der lokalen Serverzeit auswertet.
| Variable | Standardwert | Beschreibung |
|---|---|---|
OMNIROUTE_BACKUP_SCHEDULE_JOB_INTERVAL_MS |
30000 |
Intervall in ms (min. 5000). Muss kürzer als 60 s sein, damit die passende Cron-Minute zuverlässig getroffen wird. |
SQLite-Hot-Backup
Abschnitt betitelt „SQLite-Hot-Backup“Für eine Sicherung einer laufenden DB ohne Ausfallzeit:
sqlite3 ~/.omniroute/storage.sqlite ".backup /backups/omniroute-hot.db"Hierbei wird die Online-Backup-API von SQLite verwendet — die Ausführung ist sicher, während OmniRoute läuft.
Leistungsoptimierung
Abschnitt betitelt „Leistungsoptimierung“WAL-Modus
Abschnitt betitelt „WAL-Modus“WAL ist standardmäßig aktiviert. Für schreibintensive Workloads sollten Sie Folgendes in Betracht ziehen:
PRAGMA wal_autocheckpoint = 1000; -- Checkpoint alle 1000 SeitenPRAGMA journal_size_limit = 67108864; -- WAL-Obergrenze von 64 MBIndizes
Abschnitt betitelt „Indizes“Wichtige Indizes für die Leistung (werden durch Migrationen automatisch erstellt):
idx_models_provider— Modellsuche nach Anbieteridx_combo_targets_combo_id— Erweiterung von Kombinationszielenidx_usage_history_api_key_timestamp— Nutzungsanalysenidx_quota_snapshots_api_key_window— Kontingentverfolgungidx_call_logs_timestamp— Abfragen von Aufrufprotokollen
Um einen neuen Index hinzuzufügen, erstellen Sie eine Migration:
-- 023_add_my_index.sqlCREATE INDEX IF NOT EXISTS idx_my_table_my_column ON my_table(my_column);Speicherabgebildete E/A
Abschnitt betitelt „Speicherabgebildete E/A“Für sehr große Datenbanken (>10 GB) kann die Speicherabbildung über ein SQLite-Pragma angepasst werden:
-- Über SQLite-Pragma festlegen (in core.ts oder zur Laufzeit anpassen)PRAGMA mmap_size = 268435456; -- 256 MBKomprimierung
Abschnitt betitelt „Komprimierung“Lang laufende OmniRoute-Instanzen profitieren von einem gelegentlichen VACUUM:
sqlite3 ~/.omniroute/storage.sqlite "VACUUM;"Führen Sie dies monatlich in Zeitfenstern mit geringem Datenverkehr aus. (Der WAL-Modus reduziert die Notwendigkeit, beseitigt sie jedoch nicht vollständig.)
Integritätsprüfung
Abschnitt betitelt „Integritätsprüfung“src/lib/db/healthCheck.ts stellt Integritätsdiagnosen auf Datenbankebene bereit:
Beide HTTP-Methoden erfordern eine Authentifizierung (andernfalls 401). GET führt nur eine Diagnose durch; POST führt dieselbe Prüfung mit aktiviertem autoRepair aus.
GET /api/db/health # diagnostizierenPOST /api/db/health # diagnostizieren + reparierenDie Antwort ist das von runDbHealthCheck() erzeugte DbHealthCheckResult
(src/lib/db/healthCheck.ts):
{ "isHealthy": false, "issues": [ { "type": "broken_reference", "table": "domain_budgets", "description": "Domänenbudgets verwiesen auf API-Schlüssel, die nicht mehr existieren.", "count": 2 } ], "repairedCount": 0, "backupCreated": false, "autoRepair": false, "checkedAt": "2026-08-18T09:00:00.000Z", "driver": { "name": "better-sqlite3", "degraded": false }}| Feld | Bedeutung |
|---|---|
isHealthy |
true, wenn issues leer ist. driver hat niemals Einfluss darauf. |
issues[].type |
Einer der Werte integrity_check_failed, broken_reference, stale_snapshot, invalid_state. |
repairedCount |
Während dieses Durchlaufs reparierte Zeilen; immer 0, wenn autoRepair den Wert false hat. |
backupCreated |
Gibt an, ob vor der Reparatur eine Sicherung erstellt wurde. |
checkedAt |
ISO-Zeitstempel, der für den Durchlauf und jeden dabei geschriebenen Reparaturhinweis identisch ist. |
driver.name |
SQLite-Treiber, der die geprüfte Datenbank bereitstellt. |
driver.degraded |
true, wenn Schreibvorgänge nicht dauerhaft durch die Datenbankdatei gesichert werden — beim WASM-Fallback sql.js (Persistenz der gesamten Datei) oder bei einer In-Memory-Datenbank. |
Dieselbe Nutzlast wird vom MCP-Tool omniroute_db_health_check zurückgegeben.
Führen Sie PRAGMA integrity_check aus, um Beschädigungen zu erkennen:
sqlite3 ~/.omniroute/storage.sqlite "PRAGMA integrity_check;"# Sollte Folgendes ausgeben: okWenn etwas anderes als ok zurückgegeben wird, beenden Sie die Verwendung der Datenbank sofort und stellen Sie sie aus einer Sicherung wieder her.
Notfallwiederherstellung
Abschnitt betitelt „Notfallwiederherstellung“Szenario 1: WAL-Datei verloren
Abschnitt betitelt „Szenario 1: WAL-Datei verloren“Die -wal-Datei fehlt, aber -shm und die Hauptdatenbank sind intakt:
# Wird beim nächsten Öffnen automatisch wiederhergestelltomnirouteFalls SQLite keine automatische Wiederherstellung durchführen kann:
sqlite3 ~/.omniroute/storage.sqlite ".recover" > recovered.sqlsqlite3 recovered.db < recovered.sqlmv recovered.db ~/.omniroute/storage.sqliteSzenario 2: Hauptdatenbankdatei beschädigt
Abschnitt betitelt „Szenario 2: Hauptdatenbankdatei beschädigt“Aus einer Sicherung wiederherstellen:
omniroute sync pull --merge # oder: omniroute backup restore <backup-id>Szenario 3: Verschlüsselungsschlüssel verloren
Abschnitt betitelt „Szenario 3: Verschlüsselungsschlüssel verloren“Ohne den Schlüssel ist keine Wiederherstellung möglich. Die verschlüsselten Felder sind nicht lesbar. Fügen Sie alle Anbieter manuell mit neuen Zugangsdaten erneut hinzu.
Gegenmaßnahme: Sichern Sie den Verschlüsselungsschlüssel stets separat, idealerweise in einem Passwortmanager oder KMS.
Szenario 4: Datenträger voll
Abschnitt betitelt „Szenario 4: Datenträger voll“SQLite gibt SQLITE_FULL-Fehler zurück. Geben Sie Speicherplatz frei und führen Sie anschließend Folgendes aus:
# WAL-Checkpoint durchführen, um Speicherplatz freizugebensqlite3 ~/.omniroute/storage.sqlite "PRAGMA wal_checkpoint(TRUNCATE);"Häufige Vorgänge
Abschnitt betitelt „Häufige Vorgänge“Eine Tabelle untersuchen
Abschnitt betitelt „Eine Tabelle untersuchen“sqlite3 ~/.omniroute/storage.sqlite "SELECT * FROM api_keys LIMIT 5;"Zeilen in allen Tabellen zählen
Abschnitt betitelt „Zeilen in allen Tabellen zählen“sqlite3 ~/.omniroute/storage.sqlite <<EOFSELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';EOFAlle Daten zurücksetzen (löschen)
Abschnitt betitelt „Alle Daten zurücksetzen (löschen)“# Zuerst OmniRoute beendenomniroute stop
# Datenbankdatei löschenrm ~/.omniroute/storage.sqlite*
# Neu starten (erstellt eine leere Datenbank)omnirouteFür ein selektives Zurücksetzen (Anbieter beibehalten, Nutzungsdaten löschen):
DELETE FROM usage_history WHERE timestamp < datetime('now', '-30 day');DELETE FROM call_logs WHERE timestamp < datetime('now', '-30 day');DELETE FROM proxy_logs WHERE timestamp < datetime('now', '-30 day');Einzelne Tabelle exportieren
Abschnitt betitelt „Einzelne Tabelle exportieren“sqlite3 ~/.omniroute/storage.sqlite <<EOF.mode csv.output api_keys.csvSELECT * FROM api_keys;EOFFehlerbehebung
Abschnitt betitelt „Fehlerbehebung““Datenbank ist gesperrt”
Abschnitt betitelt „“Datenbank ist gesperrt”“Ein anderer Prozess hält eine Schreibsperre. Sie können:
- Warten, bis der andere Prozess abgeschlossen ist (mit
lsof | grep storage.sqliteprüfen) - Den anderen Prozess beenden
- OmniRoute neu starten, falls das Problem weiterhin besteht
“Fremdschlüsselbedingung fehlgeschlagen”
Abschnitt betitelt „“Fremdschlüsselbedingung fehlgeschlagen”“Ein Domänenmodul verletzt die referenzielle Integrität. Prüfen Sie Folgendes:
- Verwaiste Zeilen in abhängigen Tabellen
- Kaskadierende Löschvorgänge, die nicht weitergegeben wurden
- Eine kürzlich durchgeführte Migration, die einen Fremdschlüssel geändert hat
Führen Sie PRAGMA foreign_key_check; aus, um Verletzungen zu finden.
“Nicht genügend Arbeitsspeicher”
Abschnitt betitelt „“Nicht genügend Arbeitsspeicher”“Die speicherabgebildete Ein-/Ausgabe von SQLite überschreitet das Betriebssystemlimit. Reduzieren Sie sie über ein SQLite-Pragma:
PRAGMA mmap_size = 134217728; -- 128MB anstelle von 256MBOder deaktivieren Sie sie:
PRAGMA mmap_size = 0;“Migration während der Ausführung fehlgeschlagen”
Abschnitt betitelt „“Migration während der Ausführung fehlgeschlagen”“Die Migration wurde innerhalb einer Transaktion ausgeführt und sollte daher zurückgesetzt worden sein. Falls nicht:
- OmniRoute beenden (weitere Versuche verhindern)
- Datenbankstatus prüfen mit
sqlite3 - Unvollständige Migration manuell korrigieren
- OmniRoute erneut ausführen (die Migration wird erneut versucht)
Um dies zu vermeiden, testen Sie Migrationen immer zuerst an einer Kopie.
Siehe auch
Abschnitt betitelt „Siehe auch“- USAGE_QUOTA_GUIDE.md — Nutzungstabellen
- MONITORING_GUIDE.md — Systemzustandsüberwachung
- RELEASE_CHECKLIST.md — Veröffentlichungsablauf
- Quelle:
src/lib/db/(mehr als 80 Dateien, ca. 25.000 Codezeilen)
HagiCode
HagiCode ist ein agentischer Coding-Arbeitsplatz mit strukturierten Workflows, Multi-Agent-Ausführung und Hero-Dungeon-Ansichten.
Mit einem intelligenteren, schnelleren und unterhaltsameren agentischen Workflow wird aus Ideen nutzbare Software.

- SmartStrukturierte Workflows machen aus Absichten einen umsetzbaren Weg von der Idee bis zur Auslieferung.
- EfficientMulti-Agent-Workflows führen Recherche, Umsetzung und Prüfung parallel aus.
- FunHero Dungeon macht lange Coding-Sitzungen anschaulich und gemeinschaftlich.