# Vorschau-Instanz auf dem Live-Server einrichten **Ziel:** `https://preview.b2in.eu` zeigt den neuen Stand zur Abstimmung. **Die Live-Seite bleibt unangetastet** – es wird keine einzige Datei im Live-Verzeichnis überschrieben und keine Zeile in der Live-Datenbank geändert. **Prinzip:** zweites, eigenständiges Verzeichnis · eigene `.env` · eigene Datenbank. ``` /var/www/b2in/ ← Live, bleibt wie es ist /var/www/b2in-preview/ ← Kopie davon, darauf das Update ``` > Pfade unten sind Beispiele. Ersetze `/var/www/b2in` durch das echte Live-Verzeichnis und > `b2in_live` / `b2in_preview` durch die echten Datenbanknamen. --- ## 0. Warum nicht einfach die Live-Dateien tauschen Zwei Gründe, die diesen Aufwand rechtfertigen: 1. **Der Relaunch-Seeder überschreibt CMS-Sektionen.** `InteriorRelaunchCmsSeeder` schreibt 23 Sektionen mit den neuen Texten. Auf der Live-Datenbank ausgeführt wäre der alte Stand weg. 2. **Migrationen sind nicht umkehrbar.** `cms_brands` und die beiden Spalten `summary` / `highlights` kommen neu dazu. Mit einer eigenen Datenbank kann beim Testen nichts passieren, was die Live-Seite betrifft. --- ## 1. Voraussetzungen - [ ] DNS-Eintrag `preview.b2in.eu` → dieselbe Server-IP wie `b2in.eu` - [ ] SSL-Zertifikat für die Subdomain (Let's Encrypt genügt) - [ ] vhost mit `DocumentRoot /var/www/b2in-preview/public` - [ ] Zweite MySQL-Datenbank plus Benutzer - [ ] Genug Plattenplatz für eine Kopie des Live-Verzeichnisses (vor allem `storage/`) --- ## 2. Sicherung ziehen Auch wenn wir live nichts anfassen – der Dump ist zugleich die Grundlage für die Vorschau-DB. ```bash cd /var/www/b2in mysqldump -u USER -p b2in_live > ~/b2in_live_$(date +%F_%H%M).sql ls -lh ~/b2in_live_*.sql # Größe prüfen, darf nicht 0 sein ``` --- ## 3. Vorschau-Verzeichnis anlegen Kopie des Live-Standes, **inklusive `vendor/`**. Das erspart ein `composer install` auf dem Server – für `livewire/flux-pro` bräuchte es sonst die Zugangsdaten aus `auth.json`. ```bash cp -a /var/www/b2in /var/www/b2in-preview cd /var/www/b2in-preview # Laufzeit-Reste der Kopie entfernen rm -rf bootstrap/cache/*.php rm -f public/storage # Symlink wird in Schritt 7 neu gesetzt ``` **Zu `storage/app/public` (Medienbibliothek, Display-Videos):** Durch `cp -a` liegt eine echte Kopie in der Vorschau – sauber getrennt, kostet aber den Speicherplatz. Wenn das zu groß ist: ```bash rm -rf storage/app/public ln -s /var/www/b2in/storage/app/public storage/app/public ``` ⚠️ Mit dem Symlink landen **Uploads aus der Vorschau in den Live-Dateien**. Zum Anschauen in Ordnung, zum Testen von Uploads nicht. Im Zweifel kopieren. --- ## 4. `.env` der Vorschau anpassen Der wichtigste Schritt. Der `ThemeServiceProvider` sucht den aufgerufenen Host in `config/domains.php` und setzt `URL::forceRootUrl()` samt Asset-Origin auf die dort hinterlegte URL. Fehlt `DOMAIN_B2IN_URL`, greift der Vorgabewert **`https://b2in.test`** – eine Domain, die es im Internet nicht gibt. Dann laden Bilder, Favicon und `livewire.min.js` nicht mehr. ```bash cd /var/www/b2in-preview nano .env ``` Diese Werte ändern: ```dotenv APP_ENV=preview APP_DEBUG=false APP_URL=https://preview.b2in.eu APP_DOMAIN_NAME=preview.b2in.eu # Vorschau-Domain, damit Routing, Links und Assets stimmen DOMAIN_B2IN=preview.b2in.eu DOMAIN_B2IN_URL=https://preview.b2in.eu # Assets ebenfalls auf die Vorschau-Domain, sonst laedt der Browser sie von woanders ASSET_URL=https://preview.b2in.eu # Eigene Datenbank DB_DATABASE=b2in_preview DB_USERNAME=… DB_PASSWORD=… # Eigener Cache-/Session-Namensraum, damit sich Live und Vorschau nicht ins Gehege kommen CACHE_PREFIX=b2in_preview SESSION_COOKIE=b2in_preview_session # Keine Mails aus der Vorschau verschicken MAIL_MAILER=log ``` `APP_ENV=preview` sorgt automatisch für `noindex, nofollow` in jeder Seite (`config/app.php` → `app.indexable`). Wer ganz sichergehen will, setzt zusätzlich `SITE_INDEXABLE=false`. **Nicht ändern:** `APP_KEY` – sonst sind verschlüsselte Werte in der kopierten Datenbank nicht mehr lesbar. --- ## 5. Datenbank der Vorschau befüllen ```bash mysql -u USER -p -e "CREATE DATABASE b2in_preview CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" mysql -u USER -p b2in_preview < ~/b2in_live_JJJJ-MM-TT_HHMM.sql ``` Gegenprobe, dass die Vorschau wirklich auf ihrer eigenen DB steht: ```bash cd /var/www/b2in-preview php artisan tinker --execute="echo config('database.connections.mysql.database');" # muss b2in_preview ausgeben – wenn hier b2in_live steht: STOPP ``` --- ## 6. Update einspielen Das Archiv `dev/2026-08-28/deploy/b2in-interior-update.tar.gz` enthält genau die geänderten und neuen Dateien plus die gebauten Assets (`public/build/b2in`, `public/build/portal`). **Node wird auf dem Server nicht gebraucht.** Die enthaltene Dateiliste steht in `deploy/dateiliste.txt`. ```bash # Archiv hochladen, dann: cd /var/www/b2in-preview tar xzf ~/b2in-interior-update.tar.gz ``` Das Archiv enthält bewusst **keine** `.env`, kein `vendor/` und nichts aus `storage/`. --- ## 7. Artisan-Schritte ```bash cd /var/www/b2in-preview php artisan config:clear php artisan storage:link php artisan migrate --force # legt cms_brands an, ergänzt summary/highlights # Kernmarken anlegen – überschreibt nichts, was schon gepflegt ist php artisan db:seed --class=CmsBrandSeeder --force # Die neuen Texte ins CMS: genau die 23 umgetexteten Sektionen php artisan db:seed --class=InteriorRelaunchCmsSeeder --force # Magazin: die zwei neuen Beiträge plus Reihenfolge php artisan db:seed --class=CmsArticleSeeder --force # Markenseiten CABINET, Rotpunkt und Febrü – nur Textfelder, Bilder und Galerie bleiben php artisan db:seed --class=BrandPageTextSeeder --force # Entfernt den Vermerk „BEISPIEL – “ aus vorhandenen Bildunterschriften (Nachtrag 5). # Nur nötig, wenn die Demogalerien schon eingespielt sind. Mehrfach ausführbar. php artisan db:seed --class=BrandGalleryCaptionNormalizerSeeder --force # Markenlogos nachtragen. Setzt `logo` nur, wenn das Feld leer ist. php artisan db:seed --class=BrandLogoSeeder --force # Display-Branding auf das Interior-Logo php artisan db:seed --class=DisplayInteriorBrandingSeeder --force # Medien-URLs host-unabhängig (sonst zeigen vier Playlists auf b2in.test) php artisan db:seed --class=DisplayMediaUrlNormalizerSeeder --force php artisan config:cache php artisan route:cache php artisan view:clear ``` > **Assets:** Das Archiv bringt `public/build/b2in` fertig mit. Wird auf dem Server selbst > gebaut, gilt: `npm run build:web` baut **nur** die vier Frontend-Themes, nicht das Portal. > Ohne `npm run build:portal` liefert das Admin-Portal danach 500. **Optional, nur für die Abstimmung:** Beispielbilder in die Markengalerien, damit Galerie, Referenzen-Seite und Lightbox nicht leer sind. > ⚠️ Es sind Stockmotive und KI-Renderings, kein einziges echtes Projekt. Der frühere Vermerk > „BEISPIEL" in der Bildunterschrift ist auf Kundenwunsch entfallen – die Bilder der Rubrik > „Realisiertes Projekt" geben sich damit als echte Referenzen aus. Für die Abstimmung in > Ordnung, **vor dem Livegang zwingend ersetzen**. ```bash php artisan db:seed --class=DemoBrandGallerySeeder --force ``` Wieder entfernen: ```bash php artisan tinker --execute="App\Models\CmsBrand::query()->update(['gallery' => null]);" ``` --- ## 8. Vorschau abschirmen **Suchmaschinen** – `noindex` kommt schon aus `APP_ENV=preview`, die `robots.txt` gehört zusätzlich umgestellt: ```bash printf 'User-agent: *\nDisallow: /\n' > /var/www/b2in-preview/public/robots.txt ``` **Passwortschutz** (empfohlen, damit die Vorschau nicht zufällig gefunden wird): ```bash htpasswd -c /etc/apache2/.htpasswd-preview vorschau ``` Apache: ```apache AuthType Basic AuthName "B2in Vorschau" AuthUserFile /etc/apache2/.htpasswd-preview Require valid-user ``` Nginx: ```nginx auth_basic "B2in Vorschau"; auth_basic_user_file /etc/nginx/.htpasswd-preview; ``` --- ## 9. Prüfen | Seite | Erwartung | |---|---| | `/` | Hero → Marken-Teaser → Vision → Sponsoring → Showroom-Display → Immobilien → CTA | | `/marken` | Grauer Seitenkopf mit Bild, drei gerahmte Markenblöcke | | `/marken/cabinet` | Detailseite, Galerie mit den zwei Rubriken (falls Demo-Seeder lief) | | `/marken/rotpunkt` | Neun Abschnitte, vier davon mit aufklappbarer Vertiefung; Button unten rechts heißt „Persönliche Küchenberatung vereinbaren" | | `/marken/februe` | Elf Abschnitte, Zitat von Marcel; Button heißt „Persönliche Arbeitsplatzberatung vereinbaren" | | `/referenzen` | Realisierte Projekte, darunter das Showroom-Display im Hochformat | | `/magazin` | Die zwei Interior-Beiträge stehen oben | | `/faq` | Rubriken „Für Ihr Zuhause" und „Für Projekte und Objekte" | | `/about` | Werte: Beratung statt Verkauf, Maßarbeit, … | | `/contact` | Betreffliste beginnt mit Beratungstermin | | `/immobilien` | unverändert | Und diese vier Punkte: - [ ] Terminanfrage-Widget unten rechts öffnet sich, Absenden zeigt die Bestätigung - [ ] Alle Links bleiben auf `preview.b2in.eu` – **springt einer auf `b2in.eu`, stimmt Schritt 4 nicht** - [ ] Seitenquelltext enthält `` - [ ] Die Live-Seite `https://b2in.eu` sieht unverändert aus --- ## 10. Aufräumen Vorschau wieder abbauen: ```bash rm -rf /var/www/b2in-preview mysql -u USER -p -e "DROP DATABASE b2in_preview;" # vhost und DNS-Eintrag entfernen ``` Beim späteren echten Livegang gilt **Abschnitt 8 des Entwicklungsplans**, nicht dieses Dokument. Vorher offen: Rechtstexte, OG-Bild, Seeder-Passwort rotieren. --- ## Wenn etwas nicht stimmt | Symptom | Ursache | |---|---| | **„Kein Server mit dem angegebenen Hostnamen gefunden" für Bilder, Favicon, `livewire.min.js`** | `DOMAIN_B2IN_URL` fehlt oder ist falsch geschrieben → Vorgabewert `https://b2in.test`. Siehe Diagnose unten. | | Links springen auf `b2in.eu` | `DOMAIN_B2IN` / `DOMAIN_B2IN_URL` in Schritt 4 nicht gesetzt, oder `config:cache` fehlt | | Seite ohne Styles | `public/build/b2in` fehlt – Archiv nicht vollständig entpackt | | „Vite manifest not found" | dasselbe, oder `build/portal` fehlt für das Admin-Panel | | Bilder fehlen | `php artisan storage:link` vergessen, oder `storage/app/public` nicht mitkopiert | | Display-Kachel bleibt leer | Kein aktives Display mit veröffentlichter Playlist – dann wird die Sektion bewusst gar nicht angezeigt | | Änderungen wirken nicht | `php artisan config:clear && php artisan config:cache` | ### Diagnose: Assets zeigen auf den falschen Host ```bash cd /var/www/b2in-preview # 1. Was steht in der .env? grep -E '^(APP_ENV|APP_URL|APP_DOMAIN_NAME|ASSET_URL|DOMAIN_B2IN|DOMAIN_B2IN_URL)=' .env # 2. Was macht die Anwendung daraus? (zeigt den zwischengespeicherten Stand) php artisan tinker --execute="echo config('domains.domains.b2in.domain_name').' -> '.config('domains.domains.b2in.url').PHP_EOL;" # 3. Liegt ein alter Config-Cache herum? ls -l bootstrap/cache/config.php 2>/dev/null ``` Steht in Zeile 2 etwas mit `.test`, fehlen die beiden `DOMAIN_B2IN*`-Zeilen. Beheben: ```bash cd /var/www/b2in-preview php artisan config:clear # zuerst den Cache weg, sonst wirkt die .env nicht nano .env # DOMAIN_B2IN, DOMAIN_B2IN_URL, ASSET_URL, APP_URL setzen php artisan config:cache php artisan view:clear ``` **Sicherheitsnetz seit dieser Runde:** Findet der `ThemeServiceProvider` den aufgerufenen Host nicht in der Konfiguration, verwendet er außerhalb von `APP_ENV=production` den tatsächlich aufgerufenen Origin – die Vorschau verlinkt sich dann auf sich selbst statt auf eine fremde Domain. In `production` bleibt es bei der konfigurierten URL, damit ein gefälschter Host-Header keine Links auf fremde Domains erzeugen kann. Die `.env` sollte trotzdem stimmen.