From f4859317fa5d2e18abaa0c389af30a579d8bd116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20F=C3=B6rtsch?= Date: Mon, 13 Apr 2026 15:16:07 +0200 Subject: [PATCH] settings: add factory reset button that wipes every table incl. config the existing clear-scan button only drops media_items + related; settings survived. useful when schema changes or corrupt state make you want a full do-over on a running container without ssh-ing in to rm data/netfelix.db. POST /api/settings/reset truncates everything (config included) then re-seeds DEFAULT_CONFIG via the exported reseedDefaults helper. env-var overrides keep working through getConfig's env fallback. ui lives next to clear-scan in the danger zone with a double confirm and reload to /, so the setup wizard shows. Co-Authored-By: Claude Opus 4.6 (1M context) --- package.json | 2 +- server/api/settings.ts | 24 +++++++++++++++++++++++- server/db/index.ts | 5 +++++ src/features/settings/SettingsPage.tsx | 26 ++++++++++++++++++++++++-- 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b57aca1..97498b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "netfelix-audio-fix", - "version": "2026.04.13.4", + "version": "2026.04.13.5", "scripts": { "dev:server": "NODE_ENV=development bun --hot server/index.tsx", "dev:client": "vite", diff --git a/server/api/settings.ts b/server/api/settings.ts index e1588b1..50688ff 100644 --- a/server/api/settings.ts +++ b/server/api/settings.ts @@ -1,5 +1,5 @@ import { Hono } from "hono"; -import { getAllConfig, getDb, getEnvLockedKeys, setConfig } from "../db/index"; +import { getAllConfig, getDb, getEnvLockedKeys, reseedDefaults, setConfig } from "../db/index"; import { getUsers, testConnection as testJellyfin } from "../services/jellyfin"; import { testConnection as testRadarr } from "../services/radarr"; import { getScheduleConfig, type ScheduleConfig, updateScheduleConfig } from "../services/scheduler"; @@ -122,4 +122,26 @@ app.post("/clear-scan", (c) => { return c.json({ ok: true }); }); +/** + * Full factory reset. Truncates every table including config, re-seeds the + * defaults so the setup wizard reappears, and returns. Env-backed config + * keys (JELLYFIN_URL, etc.) continue to resolve via getConfig's env fallback + * — they don't live in the DB to begin with. + */ +app.post("/reset", (c) => { + const db = getDb(); + db.transaction(() => { + // Order matters when ON DELETE CASCADE isn't consistent across versions. + db.prepare("DELETE FROM stream_decisions").run(); + db.prepare("DELETE FROM jobs").run(); + db.prepare("DELETE FROM subtitle_files").run(); + db.prepare("DELETE FROM review_plans").run(); + db.prepare("DELETE FROM media_streams").run(); + db.prepare("DELETE FROM media_items").run(); + db.prepare("DELETE FROM config").run(); + })(); + reseedDefaults(); + return c.json({ ok: true }); +}); + export default app; diff --git a/server/db/index.ts b/server/db/index.ts index 6f3e603..6981deb 100644 --- a/server/db/index.ts +++ b/server/db/index.ts @@ -102,6 +102,11 @@ function seedDefaults(db: Database): void { } } +/** Re-seed config defaults after a truncating reset. Caller owns the delete. */ +export function reseedDefaults(): void { + seedDefaults(getDb()); +} + export function getConfig(key: string): string | null { // Env vars take precedence over DB const fromEnv = envValue(key); diff --git a/src/features/settings/SettingsPage.tsx b/src/features/settings/SettingsPage.tsx index d2a06a8..2b2370a 100644 --- a/src/features/settings/SettingsPage.tsx +++ b/src/features/settings/SettingsPage.tsx @@ -401,6 +401,20 @@ export function SettingsPage() { setClearStatus("Cleared."); }; + const factoryReset = async () => { + if ( + !confirm( + "Reset to first-run state? This wipes EVERYTHING — scan data, settings, languages, schedule, Jellyfin/Radarr/Sonarr credentials. You'll land back on the setup wizard. This cannot be undone.", + ) + ) + return; + if (!confirm("Really reset? Type-nothing-just-click to confirm.")) return; + await api.post("/api/settings/reset"); + // Invalidate client-side caches and reload so the setup gate re-evaluates. + settingsCache = null; + window.location.href = "/"; + }; + return (
@@ -487,11 +501,19 @@ export function SettingsPage() {

These actions are irreversible. Scan data can be regenerated by running a new scan.

-
+
- Removes all scanned items, review plans, and jobs. + Removes all scanned items, review plans, and jobs. Keeps settings. +
+
+ + + Wipes everything — scan data and settings. Sends you back to the setup wizard. +
{clearStatus &&

{clearStatus}

}