From 618a32182c9e5073b4f0f8d06d872c45c527f927 Mon Sep 17 00:00:00 2001 From: Maaxxs <61059039+MaaxxsDev@users.noreply.github.com> Date: Sun, 5 Jul 2026 14:23:30 +0200 Subject: [PATCH] Make base path configurable for root-domain deployment (IONOS) Bisher war /hifi an mehreren Stellen fest einprogrammiert (vite base, Router basename, API-Client, Upload-URLs, .htaccess). Fuer den geplanten Deploy auf IONOS unter der Domain-Wurzel wird das jetzt ueber VITE_BASE_PATH (Frontend-Build) bzw. eine optionale base_path.php (Backend, gleiches Muster wie db.php/setup.php) gesteuert - lokal ohne diese Werte bleibt alles unveraendert bei /hifi. .htaccess.ionos enthaelt die Root-Domain-Variante fuer den CI-Build. Co-Authored-By: Claude Sonnet 5 --- .gitignore | 4 +++ hifi-src/src/api/client.js | 4 ++- hifi-src/src/main.jsx | 2 +- .../admin/settings/ExportImportSettings.jsx | 4 +-- hifi-src/vite.config.js | 7 ++++- hifi/.htaccess | 3 +++ hifi/.htaccess.ionos | 15 +++++++++++ hifi/api/config/config.php | 6 +++-- .../src/Controllers/SettingsController.php | 26 ++++++++++++------- hifi/api/src/Controllers/UploadController.php | 5 +++- 10 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 hifi/.htaccess.ionos diff --git a/.gitignore b/.gitignore index 68182b7..60f20b1 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,10 @@ # pro Umgebung unterschiedlich und darf nicht öffentlich einsehbar sein /hifi/api/config/setup.php +# Wird nur im IONOS-Deploy-Now-Build-Schritt geschrieben (Root-Domain statt /hifi), +# lokal nicht vorhanden -> Fallback in config.php greift dann +/hifi/api/config/base_path.php + # Claude-Code-Tooling (Skills/lokale Einstellungen) - gehört nicht zum Website-Projekt /hifi/.claude/ /hifi/.agents/ diff --git a/hifi-src/src/api/client.js b/hifi-src/src/api/client.js index 3f68ac4..fba519a 100644 --- a/hifi-src/src/api/client.js +++ b/hifi-src/src/api/client.js @@ -1,4 +1,6 @@ -const API_BASE = '/hifi/api'; +// BASE_URL spiegelt immer den "base"-Wert aus vite.config.js wider (mit +// abschließendem Slash, z.B. "/hifi/" lokal oder "/" auf IONOS). +export const API_BASE = `${import.meta.env.BASE_URL.replace(/\/$/, '')}/api`; async function request(path, options = {}) { const res = await fetch(`${API_BASE}${path}`, { diff --git a/hifi-src/src/main.jsx b/hifi-src/src/main.jsx index fab029e..5cdf562 100644 --- a/hifi-src/src/main.jsx +++ b/hifi-src/src/main.jsx @@ -9,7 +9,7 @@ import './index.css'; ReactDOM.createRoot(document.getElementById('root')).render( - + diff --git a/hifi-src/src/pages/admin/settings/ExportImportSettings.jsx b/hifi-src/src/pages/admin/settings/ExportImportSettings.jsx index 22b67fa..ebfb4aa 100644 --- a/hifi-src/src/pages/admin/settings/ExportImportSettings.jsx +++ b/hifi-src/src/pages/admin/settings/ExportImportSettings.jsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { api } from '../../../api/client.js'; +import { api, API_BASE } from '../../../api/client.js'; export default function ExportImportSettings() { const [importFile, setImportFile] = useState(null); @@ -38,7 +38,7 @@ export default function ExportImportSettings() { herunter. Benutzerkonten und Kontaktanfragen sind bewusst nicht enthalten.

Jetzt exportieren diff --git a/hifi-src/vite.config.js b/hifi-src/vite.config.js index 1d4789f..503ce19 100644 --- a/hifi-src/vite.config.js +++ b/hifi-src/vite.config.js @@ -1,9 +1,14 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; +// Lokal (XAMPP) läuft die Seite unter /hifi/, auf IONOS Deploy Now unter der +// Domain-Wurzel. VITE_BASE_PATH wird nur im CI-Build-Schritt auf "/" gesetzt, +// lokal bleibt der Default unverändert. +const base = process.env.VITE_BASE_PATH || '/hifi/'; + export default defineConfig({ plugins: [react()], - base: '/hifi/', + base, build: { outDir: '../hifi', emptyOutDir: false, diff --git a/hifi/.htaccess b/hifi/.htaccess index e6f4fb4..61ed5f7 100644 --- a/hifi/.htaccess +++ b/hifi/.htaccess @@ -1,3 +1,6 @@ +# Für die lokale XAMPP-Entwicklung (Seite liegt unter /hifi/). Die Root-Domain- +# Variante für den IONOS-Deploy-Now-Build liegt in .htaccess.ionos und wird dort +# beim Bauen automatisch anstelle dieser Datei verwendet. RewriteEngine On RewriteBase /hifi/ diff --git a/hifi/.htaccess.ionos b/hifi/.htaccess.ionos new file mode 100644 index 0000000..7f3bdef --- /dev/null +++ b/hifi/.htaccess.ionos @@ -0,0 +1,15 @@ +RewriteEngine On +RewriteBase / + +# API-Requests an den PHP-Front-Controller weiterleiten +RewriteCond %{REQUEST_URI} ^/api/ +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule ^api/(.*)$ api/public/index.php [QSA,L] + +# Dynamische sitemap.xml (DB-generiert) +RewriteRule ^sitemap\.xml$ api/public/sitemap.php [L] + +# Alles andere: SPA-Fallback auf index.html (React Router übernimmt das Routing) +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule ^ index.html [QSA,L] diff --git a/hifi/api/config/config.php b/hifi/api/config/config.php index 0306e7e..a4ad324 100644 --- a/hifi/api/config/config.php +++ b/hifi/api/config/config.php @@ -24,8 +24,10 @@ return [ 'to_email' => 'kontakt@example.com', ], 'app' => [ - // Muss zum Vite "base" passen und wird für Session-Cookie-Pfad genutzt. - 'base_path' => '/hifi', + // Muss zum Vite "base" passen und wird für Session-Cookie-Pfad und Upload-URLs + // genutzt. Lokal (XAMPP) ist das /hifi, im IONOS-Deploy-Now-Build wird beim + // Bauen eine base_path.php mit '/' geschrieben (siehe .github Workflow). + 'base_path' => is_file(__DIR__ . '/base_path.php') ? require __DIR__ . '/base_path.php' : '/hifi', 'session_name' => 'hifi_admin_session', // Öffentliche Domain der Seite (für sitemap.xml, robots.txt, Canonical-URLs). Ohne abschließenden Slash. 'site_url' => 'https://hifi-planet.de', diff --git a/hifi/api/src/Controllers/SettingsController.php b/hifi/api/src/Controllers/SettingsController.php index 372faaf..342dd8c 100644 --- a/hifi/api/src/Controllers/SettingsController.php +++ b/hifi/api/src/Controllers/SettingsController.php @@ -21,7 +21,13 @@ class SettingsController 'services' => ['id', 'icon_name', 'title', 'description', 'image_path', 'cta_label', 'cta_url', 'sort_order', 'created_at', 'updated_at'], ]; - private const UPLOADS_URL_PREFIX = '/hifi/api/uploads/'; + // Kein const, da abhängig von der Umgebung (base_path unterscheidet sich + // zwischen lokalem /hifi und der Root-Domain auf IONOS). + private static function uploadsUrlPrefix(): string + { + $config = require __DIR__ . '/../../config/config.php'; + return rtrim($config['app']['base_path'], '/') . '/api/uploads/'; + } public static function exportData(): void { @@ -164,7 +170,7 @@ class SettingsController private static function collectImage(?string $path, array &$images): void { - if (!$path || isset($images[$path]) || !str_starts_with($path, self::UPLOADS_URL_PREFIX)) { + if (!$path || isset($images[$path]) || !str_starts_with($path, self::uploadsUrlPrefix())) { return; } $filename = basename($path); @@ -190,14 +196,14 @@ class SettingsController private static function defaultServices(): array { return [ - ['car', 'Car-Hifi', 'Individuelle Sound-Umbauten vom dezenten Upgrade bis zum kompromisslosen High-End-System – konfigurierbar direkt auf unserer Seite.', self::UPLOADS_URL_PREFIX . 'seed-leistung-car-hifi.jpg', 'Fahrzeug konfigurieren', '/fahrzeuge', 0], - ['caravan', 'Wohnmobil & Caravan', 'Sound- und Elektronik-Lösungen speziell für Reisemobile und Caravans – reversibel oder fest verbaut.', self::UPLOADS_URL_PREFIX . 'seed-leistung-wohnmobil.jpg', null, null, 1], - ['car-front', 'Oldtimer', 'Zeitgemäßer Klang für Klassiker – wir modernisieren die Anlage, ohne den Charakter deines Oldtimers zu verlieren.', self::UPLOADS_URL_PREFIX . 'seed-leistung-oldtimer.jpg', null, null, 2], - ['cog', 'CNC Zerspanen', 'Fräsen, Bohren, Schneiden und Schleifen auf einer Fläche von 1500 × 3000 mm – für Prototypen, Kleinserien und Großauflagen. Massivholz, Verbundwerkstoffe, Plattenmaterial und mehr.', self::UPLOADS_URL_PREFIX . 'seed-leistung-cnc-zerspanen.jpg', null, null, 3], - ['zap', 'CNC Lasertechnik', 'Präzises Laserschneiden und -gravieren für Leder, Glas, Acryl, Holz, Karton und mehr – für Einzelstücke ebenso wie Serienfertigung.', self::UPLOADS_URL_PREFIX . 'seed-leistung-cnc-laser.jpg', null, null, 4], - ['boxes', '3D-Druck', 'Über 20 Drucker (FDM & SLA) für individuelle Halterungen, Blenden und Kleinserien – Fertigung meist in 1–3 Tagen, auf Wunsch auch farbig.', self::UPLOADS_URL_PREFIX . 'seed-leistung-3d-druck.jpg', null, null, 5], - ['shield-alert', 'Alarmanlagen', 'Zuverlässiger Diebstahlschutz für dein Fahrzeug, abgestimmt auf deine Ansprüche und dein Budget.', self::UPLOADS_URL_PREFIX . 'seed-leistung-alarmanlagen.jpg', null, null, 6], - ['video', 'Dash Cams', 'Beweissichere Aufzeichnung fürs Auto – wir beraten dich zur passenden Kamera und übernehmen den unauffälligen Einbau.', self::UPLOADS_URL_PREFIX . 'seed-leistung-dashcam.jpg', null, null, 7], + ['car', 'Car-Hifi', 'Individuelle Sound-Umbauten vom dezenten Upgrade bis zum kompromisslosen High-End-System – konfigurierbar direkt auf unserer Seite.', self::uploadsUrlPrefix() . 'seed-leistung-car-hifi.jpg', 'Fahrzeug konfigurieren', '/fahrzeuge', 0], + ['caravan', 'Wohnmobil & Caravan', 'Sound- und Elektronik-Lösungen speziell für Reisemobile und Caravans – reversibel oder fest verbaut.', self::uploadsUrlPrefix() . 'seed-leistung-wohnmobil.jpg', null, null, 1], + ['car-front', 'Oldtimer', 'Zeitgemäßer Klang für Klassiker – wir modernisieren die Anlage, ohne den Charakter deines Oldtimers zu verlieren.', self::uploadsUrlPrefix() . 'seed-leistung-oldtimer.jpg', null, null, 2], + ['cog', 'CNC Zerspanen', 'Fräsen, Bohren, Schneiden und Schleifen auf einer Fläche von 1500 × 3000 mm – für Prototypen, Kleinserien und Großauflagen. Massivholz, Verbundwerkstoffe, Plattenmaterial und mehr.', self::uploadsUrlPrefix() . 'seed-leistung-cnc-zerspanen.jpg', null, null, 3], + ['zap', 'CNC Lasertechnik', 'Präzises Laserschneiden und -gravieren für Leder, Glas, Acryl, Holz, Karton und mehr – für Einzelstücke ebenso wie Serienfertigung.', self::uploadsUrlPrefix() . 'seed-leistung-cnc-laser.jpg', null, null, 4], + ['boxes', '3D-Druck', 'Über 20 Drucker (FDM & SLA) für individuelle Halterungen, Blenden und Kleinserien – Fertigung meist in 1–3 Tagen, auf Wunsch auch farbig.', self::uploadsUrlPrefix() . 'seed-leistung-3d-druck.jpg', null, null, 5], + ['shield-alert', 'Alarmanlagen', 'Zuverlässiger Diebstahlschutz für dein Fahrzeug, abgestimmt auf deine Ansprüche und dein Budget.', self::uploadsUrlPrefix() . 'seed-leistung-alarmanlagen.jpg', null, null, 6], + ['video', 'Dash Cams', 'Beweissichere Aufzeichnung fürs Auto – wir beraten dich zur passenden Kamera und übernehmen den unauffälligen Einbau.', self::uploadsUrlPrefix() . 'seed-leistung-dashcam.jpg', null, null, 7], ]; } } diff --git a/hifi/api/src/Controllers/UploadController.php b/hifi/api/src/Controllers/UploadController.php index 2a341d2..c0e8c81 100644 --- a/hifi/api/src/Controllers/UploadController.php +++ b/hifi/api/src/Controllers/UploadController.php @@ -40,6 +40,9 @@ class UploadController Http::error('Datei konnte nicht gespeichert werden', 500); } - Http::send(['path' => '/hifi/api/uploads/' . $filename], 201); + $config = require __DIR__ . '/../../config/config.php'; + $prefix = rtrim($config['app']['base_path'], '/') . '/api/uploads/'; + + Http::send(['path' => $prefix . $filename], 201); } }