From 31c6e5cd1f7b2f7c18cf4632f046cbcb945f6b62 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Sat, 18 Apr 2026 22:41:02 +0200 Subject: [PATCH] refactor(server): IMAGE_DIR/DATABASE_PATH zentralisieren + Doku-Drift fixen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit src/lib/server/paths.ts: zentrale Auflösung der env-vars; vorher 6× IMAGE_DIR und 2× DATABASE_PATH dupliziert mit identischen Defaults. Migrierte Sites: - src/lib/server/db/index.ts (DATABASE_PATH + IMAGE_DIR) - src/routes/api/admin/backup/+server.ts - src/routes/api/domains/+server.ts - src/routes/api/domains/[id]/+server.ts - src/routes/api/recipes/import/+server.ts - src/routes/api/recipes/[id]/image/+server.ts - src/routes/images/[filename]/+server.ts ARCHITECTURE.md: - 49 Flachwitze -> 150 (waren tatsaechlich 150) - 'search/' Route entfernt — wurde nie als eigene Route gebaut, Suche laeuft direkt auf der Homepage via API-Calls Findings aus zweiter Review-Runde (siehe OPEN-ISSUES-NEXT.md) --- docs/ARCHITECTURE.md | 3 +-- src/lib/server/db/index.ts | 6 +++--- src/lib/server/paths.ts | 6 ++++++ src/routes/api/admin/backup/+server.ts | 6 ++---- src/routes/api/domains/+server.ts | 3 +-- src/routes/api/domains/[id]/+server.ts | 3 +-- src/routes/api/recipes/[id]/image/+server.ts | 2 +- src/routes/api/recipes/import/+server.ts | 3 +-- src/routes/images/[filename]/+server.ts | 3 +-- 9 files changed, 17 insertions(+), 18 deletions(-) create mode 100644 src/lib/server/paths.ts diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 111044b..ebfd775 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -31,14 +31,13 @@ src/ │ │ ├── search/ # searxng.ts (Web-Suche + Thumbnail-Cache) │ │ ├── wishlist/ # Repo │ │ └── backup/ # ZIP-Export via archiver, Import via yauzl -│ ├── quotes.ts # 49 Flachwitze für die Homepage +│ ├── quotes.ts # 150 Flachwitze für die Homepage │ └── types.ts # shared types └── routes/ ├── +layout.svelte # Header, Confirm-Dialog-Mount, Header-Search-Dropdown ├── +page.svelte # Home: Hero + Live-Search + Zuletzt-hinzugefügt ├── recipes/[id]/ # Rezept-Detail ├── preview/ # Vorschau vor dem Speichern - ├── search/ # /search (lokal), /search/web (Internet) ├── wishlist/ ├── admin/ # Whitelist, Profile, Backup/Restore ├── images/[filename] # Statische Auslieferung lokaler Bilder diff --git a/src/lib/server/db/index.ts b/src/lib/server/db/index.ts index a1e4a92..e5d516c 100644 --- a/src/lib/server/db/index.ts +++ b/src/lib/server/db/index.ts @@ -1,15 +1,15 @@ import Database from 'better-sqlite3'; import { mkdirSync } from 'node:fs'; import { dirname } from 'node:path'; +import { DATABASE_PATH, IMAGE_DIR } from '$lib/server/paths'; import { runMigrations } from './migrate'; let instance: Database.Database | null = null; -export function getDb(path = process.env.DATABASE_PATH ?? './data/kochwas.db'): Database.Database { +export function getDb(path = DATABASE_PATH): Database.Database { if (instance) return instance; mkdirSync(dirname(path), { recursive: true }); - const imageDir = process.env.IMAGE_DIR ?? './data/images'; - mkdirSync(imageDir, { recursive: true }); + mkdirSync(IMAGE_DIR, { recursive: true }); instance = new Database(path); instance.pragma('journal_mode = WAL'); instance.pragma('foreign_keys = ON'); diff --git a/src/lib/server/paths.ts b/src/lib/server/paths.ts new file mode 100644 index 0000000..1629880 --- /dev/null +++ b/src/lib/server/paths.ts @@ -0,0 +1,6 @@ +// Filesystem paths read from env at module load. Centralized so a misset +// env var only causes one place to be wrong, not six. Both defaults match +// the docker-compose volume mounts under `/app/data`. + +export const DATABASE_PATH = process.env.DATABASE_PATH ?? './data/kochwas.db'; +export const IMAGE_DIR = process.env.IMAGE_DIR ?? './data/images'; diff --git a/src/routes/api/admin/backup/+server.ts b/src/routes/api/admin/backup/+server.ts index 932c621..7b391fc 100644 --- a/src/routes/api/admin/backup/+server.ts +++ b/src/routes/api/admin/backup/+server.ts @@ -1,12 +1,10 @@ import type { RequestHandler } from './$types'; import { createBackupStream, backupFilename } from '$lib/server/backup/export'; +import { DATABASE_PATH, IMAGE_DIR } from '$lib/server/paths'; import { Readable } from 'node:stream'; -const DB_PATH = process.env.DATABASE_PATH ?? './data/kochwas.db'; -const IMAGE_DIR = process.env.IMAGE_DIR ?? './data/images'; - export const GET: RequestHandler = async () => { - const archive = createBackupStream({ dbPath: DB_PATH, imagesDir: IMAGE_DIR }); + const archive = createBackupStream({ dbPath: DATABASE_PATH, imagesDir: IMAGE_DIR }); const filename = backupFilename(); return new Response(Readable.toWeb(archive) as ReadableStream, { status: 200, diff --git a/src/routes/api/domains/+server.ts b/src/routes/api/domains/+server.ts index 7a0bf9b..1eb4608 100644 --- a/src/routes/api/domains/+server.ts +++ b/src/routes/api/domains/+server.ts @@ -5,6 +5,7 @@ import { getDb } from '$lib/server/db'; import { validateBody } from '$lib/server/api-helpers'; import { addDomain, listDomains, setDomainFavicon } from '$lib/server/domains/repository'; import { ensureFavicons, fetchAndStoreFavicon } from '$lib/server/domains/favicons'; +import { IMAGE_DIR } from '$lib/server/paths'; const CreateSchema = z.object({ domain: z.string().min(3).max(253), @@ -12,8 +13,6 @@ const CreateSchema = z.object({ added_by_profile_id: z.number().int().positive().nullable().optional() }); -const IMAGE_DIR = process.env.IMAGE_DIR ?? './data/images'; - export const GET: RequestHandler = async () => { const db = getDb(); // Favicons lazy nachziehen — beim zweiten Aufruf gibt es nichts mehr zu tun. diff --git a/src/routes/api/domains/[id]/+server.ts b/src/routes/api/domains/[id]/+server.ts index 0c22f9f..c7661d1 100644 --- a/src/routes/api/domains/[id]/+server.ts +++ b/src/routes/api/domains/[id]/+server.ts @@ -9,8 +9,7 @@ import { setDomainFavicon } from '$lib/server/domains/repository'; import { fetchAndStoreFavicon } from '$lib/server/domains/favicons'; - -const IMAGE_DIR = process.env.IMAGE_DIR ?? './data/images'; +import { IMAGE_DIR } from '$lib/server/paths'; const UpdateSchema = z.object({ domain: z.string().min(3).max(253).optional(), diff --git a/src/routes/api/recipes/[id]/image/+server.ts b/src/routes/api/recipes/[id]/image/+server.ts index e19f3b4..a666539 100644 --- a/src/routes/api/recipes/[id]/image/+server.ts +++ b/src/routes/api/recipes/[id]/image/+server.ts @@ -7,8 +7,8 @@ import { join } from 'node:path'; import { getDb } from '$lib/server/db'; import { parsePositiveIntParam } from '$lib/server/api-helpers'; import { getRecipeById, updateImagePath } from '$lib/server/recipes/repository'; +import { IMAGE_DIR } from '$lib/server/paths'; -const IMAGE_DIR = process.env.IMAGE_DIR ?? './data/images'; const MAX_BYTES = 10 * 1024 * 1024; const EXT_BY_MIME: Record = { diff --git a/src/routes/api/recipes/import/+server.ts b/src/routes/api/recipes/import/+server.ts index 6b89a2d..641c4a9 100644 --- a/src/routes/api/recipes/import/+server.ts +++ b/src/routes/api/recipes/import/+server.ts @@ -5,11 +5,10 @@ import { getDb } from '$lib/server/db'; import { validateBody } from '$lib/server/api-helpers'; import { importRecipe } from '$lib/server/recipes/importer'; import { mapImporterError } from '$lib/server/errors'; +import { IMAGE_DIR } from '$lib/server/paths'; const ImportSchema = z.object({ url: z.string().url() }); -const IMAGE_DIR = process.env.IMAGE_DIR ?? './data/images'; - export const POST: RequestHandler = async ({ request }) => { const data = validateBody(await request.json().catch(() => null), ImportSchema); try { diff --git a/src/routes/images/[filename]/+server.ts b/src/routes/images/[filename]/+server.ts index 9ad634e..e0a039e 100644 --- a/src/routes/images/[filename]/+server.ts +++ b/src/routes/images/[filename]/+server.ts @@ -2,8 +2,7 @@ import type { RequestHandler } from './$types'; import { error } from '@sveltejs/kit'; import { createReadStream, existsSync, statSync } from 'node:fs'; import { join, basename, extname } from 'node:path'; - -const IMAGE_DIR = process.env.IMAGE_DIR ?? './data/images'; +import { IMAGE_DIR } from '$lib/server/paths'; const MIME: Record = { '.jpg': 'image/jpeg',