import Database from 'better-sqlite3'; import { mkdirSync } from 'fs'; import { dirname } from 'path'; let db: Database.Database | null = null; function dbPath(): string { return process.env.DB_PATH || './data/arbeitszeit.db'; } /** Singleton-Zugriff auf die SQLite-Datenbank. Legt Datei + Schema beim ersten Aufruf an. */ export function getDb(): Database.Database { if (db) return db; const path = dbPath(); mkdirSync(dirname(path), { recursive: true }); db = new Database(path); db.pragma('journal_mode = WAL'); db.exec(` CREATE TABLE IF NOT EXISTS arbeitszeit ( id INTEGER PRIMARY KEY AUTOINCREMENT, datum TEXT NOT NULL, ort TEXT NOT NULL, beginn TEXT NOT NULL, ende TEXT NOT NULL, reise_beginn TEXT NOT NULL DEFAULT '', reise_ende TEXT NOT NULL DEFAULT '', pause REAL NOT NULL DEFAULT 0.5, vertriebsunterstuetzung REAL NOT NULL DEFAULT 2, kommentar TEXT NOT NULL DEFAULT '', created_at TEXT NOT NULL DEFAULT (datetime('now')) ); CREATE INDEX IF NOT EXISTS idx_arbeitszeit_datum ON arbeitszeit (datum); CREATE TABLE IF NOT EXISTS settings ( key TEXT PRIMARY KEY, value TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS passkeys ( credential_id TEXT PRIMARY KEY, public_key BLOB NOT NULL, counter INTEGER NOT NULL DEFAULT 0, transports TEXT NOT NULL DEFAULT '[]', label TEXT NOT NULL DEFAULT '', created_at TEXT NOT NULL DEFAULT (datetime('now')), last_used_at TEXT ); `); // Migration: Reise-Start/-Ende für bestehende Datenbanken ergänzen. const cols = (db.prepare(`PRAGMA table_info(arbeitszeit)`).all() as { name: string }[]).map( (c) => c.name ); if (!cols.includes('reise_beginn')) { db.exec(`ALTER TABLE arbeitszeit ADD COLUMN reise_beginn TEXT NOT NULL DEFAULT ''`); } if (!cols.includes('reise_ende')) { db.exec(`ALTER TABLE arbeitszeit ADD COLUMN reise_ende TEXT NOT NULL DEFAULT ''`); } // Reisezeit wird zur Laufzeit aus reise_beginn/reise_ende berechnet, nicht mehr gespeichert. if (cols.includes('reisezeit')) { db.exec(`ALTER TABLE arbeitszeit DROP COLUMN reisezeit`); } // Standard-Pause beim ersten Start setzen (0,5 h) db.prepare( `INSERT INTO settings (key, value) VALUES ('pause', '0.5') ON CONFLICT(key) DO NOTHING` ).run(); // Migration: Pause pro Eintrag ergänzen. Bestehende Zeilen bekommen die aktuelle // globale Pause-Einstellung als Wert. if (!cols.includes('pause')) { const row = db.prepare(`SELECT value FROM settings WHERE key = 'pause'`).get() as | { value: string } | undefined; const globalPause = row ? parseFloat(row.value) : 0.5; const def = isNaN(globalPause) ? 0.5 : globalPause; db.exec(`ALTER TABLE arbeitszeit ADD COLUMN pause REAL NOT NULL DEFAULT ${def}`); } return db; }