/* ===================================================================== db.js — SQLite-Datenbank (better-sqlite3), Ersatz für Cloudflare D1. Führt beim ersten Start alle Migrationen aus ../cloudflare-worker/migrations/ in der ursprünglichen Reihenfolge aus (0001 Basis-Schema, 0002 app_settings, 0003 Supporter-Abo, 0004 TikTok/Discord-Spalten, 0005 Supporter-Abstimmungen) — anders als bei VanVans Shop ist hier NIE alles in einer konsolidierten schema.sql zusammengefasst worden, deshalb müssen wir hier tatsächlich alle der Reihe nach anwenden. ===================================================================== */ import Database from "better-sqlite3"; import { readFileSync, existsSync, mkdirSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; const __dirname = dirname(fileURLToPath(import.meta.url)); const DB_PATH = process.env.DB_PATH || "/var/lib/dogfather-internal/dogfather-internal.db"; const MIGRATIONS_DIR = join(__dirname, "..", "cloudflare-worker", "migrations"); mkdirSync(dirname(DB_PATH), { recursive: true }); export const db = new Database(DB_PATH); db.pragma("journal_mode = WAL"); db.pragma("foreign_keys = ON"); const MIGRATION_FILES = [ "0001_init.sql", "0002_app_settings.sql", "0003_supporter_abo.sql", "0004_supporter_oauth_providers.sql", "0005_supporter_polls.sql", "0006_testimonials.sql", "0007_team_members.sql", "0008_team_members_rich.sql", "0009_supporter_access_code.sql", "0010_testimonials_avatar.sql", // Webdesign-Bereich (22.08.2026): Anfragen, Kunden, Projekte, Dateien, // Nachrichten, Änderungswünsche, pflegbare Inhalte, Änderungsverlauf. // Alle Tabellen tragen das Präfix "wd_" und sind fachlich vollständig // vom Universe getrennt — Begründung im Kopf der Migration. "0011_webdesign.sql", // Zahlungen im Webdesign-Bereich (22.08.2026): PayPal-Einmalzahlungen // fuer Anzahlung/Restbetrag/Zusatzangebote, PayPal-Abo fuer die // monatliche Betreuung, Webhook-Merkliste gegen Doppelverbuchung. "0012_webdesign_zahlungen.sql", // Aufgabenliste je Projekt ("was ist schon gemacht von dem, was im Plan // war") und ein allgemeines Postfach fuer Nachrichten OHNE Projektbezug // (22.08.2026). Begruendung fuer die getrennte Postfach-Tabelle steht // im Kopf der Migration. "0013_webdesign_aufgaben.sql", // Elektronische Widerrufsfunktion (§ 356a BGB, seit 19.06.2026) und der // Nachweis der Zustimmung zum vorzeitigen Leistungsbeginn (§ 356 Abs. 4 // BGB). Ausfuehrliche Begruendung im Kopf der Migration -- kurz: Im // Portal werden Zusatzangebote per Klick verbindlich angenommen, das ist // ein Vertragsschluss ueber eine Online-Benutzeroberflaeche. "0014_webdesign_widerruf.sql", // Annehmen und Ablehnen einer Anfrage: echter Liefertermin (termin_am) // fuer den Countdown, Zeitpunkt der Annahme, Ablehnungsgrund. "0015_webdesign_annahme.sql", ]; function alreadyApplied(name) { const row = db.prepare(`SELECT 1 FROM _migrations WHERE name = ?`).get(name); return !!row; } export function initDb() { db.exec(`CREATE TABLE IF NOT EXISTS _migrations (name TEXT PRIMARY KEY, applied_at TEXT NOT NULL)`); for (const file of MIGRATION_FILES) { if (alreadyApplied(file)) continue; const path = join(MIGRATIONS_DIR, file); if (!existsSync(path)) { console.warn(`⚠️ Migration ${file} nicht gefunden unter ${path}, übersprungen.`); continue; } const sql = readFileSync(path, "utf-8"); db.exec(sql); db.prepare(`INSERT INTO _migrations (name, applied_at) VALUES (?, ?)`).run(file, new Date().toISOString()); console.log(`Migration angewendet: ${file}`); } }