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);
}
}