Refactor database handling to require PostgreSQL connection, removing fallback to JSON. Implement error handling for database unavailability in key files. Update .env.example to reflect mandatory DATABASE_URL for local development. Remove Firebase configuration and related code from the project.

This commit is contained in:
2026-05-23 10:23:28 +02:00
parent 547778bba5
commit 6577db475a
20 changed files with 823 additions and 789 deletions
+13 -7
View File
@@ -18,20 +18,26 @@ if (!$url) {
exit(1);
}
$pdo = get_db_connection();
if (!$pdo) {
fwrite(STDERR, "Keine DB-Verbindung zu: {$url}\n");
try {
$pdo = require_database();
} catch (DatabaseUnavailableException $e) {
fwrite(STDERR, $e->getMessage() . "\n");
fwrite(STDERR, "Prüfe: Docker läuft? docker compose -f docker-compose.dev.yml ps\n");
exit(1);
}
init_db();
$count = (int) $pdo->query('SELECT COUNT(*) FROM recipes')->fetchColumn();
echo "Verbindung OK. Rezepte in DB: {$count}\n";
if ($count > 0) {
$stmt = $pdo->query("SELECT slug, data->'i18n'->'en'->>'title' AS title FROM recipes LIMIT 5");
if ($count === 0) {
echo "Hinweis: Leere DB einmalig seeden mit: php scripts/db-seed.php\n";
} else {
$stmt = $pdo->query(
"SELECT r.slug, t.title
FROM recipes r
LEFT JOIN recipe_translations t ON t.recipe_slug = r.slug AND t.lang = 'en'
LIMIT 5"
);
echo "\nBeispiel-Zeilen:\n";
while ($row = $stmt->fetch()) {
echo " - {$row['slug']}: {$row['title']}\n";
+43
View File
@@ -0,0 +1,43 @@
<?php
/**
* Einmaliger Import aus data/recipes.json in die relationale DB.
* Die Website liest zur Laufzeit nur noch aus Postgres.
*
* php scripts/db-seed.php
*/
require_once dirname(__DIR__) . '/helpers.php';
$seedPath = dirname(__DIR__) . '/data/recipes.json';
if (!file_exists($seedPath)) {
fwrite(STDERR, "Seed-Datei fehlt: data/recipes.json\n");
exit(1);
}
$raw = file_get_contents($seedPath);
$recipes = json_decode($raw, true);
if (!is_array($recipes)) {
fwrite(STDERR, "Ungültiges JSON in data/recipes.json\n");
exit(1);
}
try {
$pdo = require_database();
} catch (DatabaseUnavailableException $e) {
fwrite(STDERR, $e->getMessage() . "\n");
exit(1);
}
$count = 0;
foreach ($recipes as $recipe) {
if (!is_array($recipe) || empty($recipe['slug'])) {
continue;
}
if (save_recipe($recipe, $pdo)) {
$count++;
echo " + {$recipe['slug']}\n";
} else {
fwrite(STDERR, " ! Fehler bei {$recipe['slug']}\n");
}
}
echo "\nImport abgeschlossen: {$count} Rezepte.\n";
+70
View File
@@ -0,0 +1,70 @@
-- FlixCooks relational recipe schema (PostgreSQL)
CREATE TABLE IF NOT EXISTS recipes (
slug VARCHAR(255) PRIMARY KEY,
hero TEXT NOT NULL DEFAULT '',
prep_time INTEGER NOT NULL DEFAULT 0,
cook_time INTEGER NOT NULL DEFAULT 0,
total_time INTEGER NOT NULL DEFAULT 0,
servings INTEGER NOT NULL DEFAULT 2,
featured BOOLEAN NOT NULL DEFAULT FALSE,
coming_soon BOOLEAN NOT NULL DEFAULT FALSE,
calories INTEGER NOT NULL DEFAULT 0,
protein INTEGER NOT NULL DEFAULT 0,
carbs INTEGER NOT NULL DEFAULT 0,
fat INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS recipe_translations (
recipe_slug VARCHAR(255) NOT NULL REFERENCES recipes(slug) ON DELETE CASCADE,
lang CHAR(2) NOT NULL CHECK (lang IN ('en', 'de')),
title TEXT NOT NULL DEFAULT '',
description TEXT NOT NULL DEFAULT '',
category TEXT NOT NULL DEFAULT '',
difficulty TEXT NOT NULL DEFAULT '',
PRIMARY KEY (recipe_slug, lang)
);
CREATE TABLE IF NOT EXISTS recipe_tags (
id SERIAL PRIMARY KEY,
recipe_slug VARCHAR(255) NOT NULL REFERENCES recipes(slug) ON DELETE CASCADE,
lang CHAR(2) NOT NULL CHECK (lang IN ('en', 'de')),
tag TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_recipe_tags_slug_lang ON recipe_tags (recipe_slug, lang);
CREATE TABLE IF NOT EXISTS recipe_ingredients (
id SERIAL PRIMARY KEY,
recipe_slug VARCHAR(255) NOT NULL REFERENCES recipes(slug) ON DELETE CASCADE,
lang CHAR(2) NOT NULL CHECK (lang IN ('en', 'de')),
content TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_recipe_ingredients_slug_lang ON recipe_ingredients (recipe_slug, lang);
CREATE TABLE IF NOT EXISTS recipe_utensils (
id SERIAL PRIMARY KEY,
recipe_slug VARCHAR(255) NOT NULL REFERENCES recipes(slug) ON DELETE CASCADE,
lang CHAR(2) NOT NULL CHECK (lang IN ('en', 'de')),
content TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_recipe_utensils_slug_lang ON recipe_utensils (recipe_slug, lang);
CREATE TABLE IF NOT EXISTS recipe_steps (
id SERIAL PRIMARY KEY,
recipe_slug VARCHAR(255) NOT NULL REFERENCES recipes(slug) ON DELETE CASCADE,
lang CHAR(2) NOT NULL CHECK (lang IN ('en', 'de')),
content TEXT NOT NULL DEFAULT '',
video_url TEXT NOT NULL DEFAULT '',
timer_minutes INTEGER,
sort_order INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_recipe_steps_slug_lang ON recipe_steps (recipe_slug, lang);