- dev/betrieb/deploy.sh: Deploy nur per Tag, mit --seed (Seeder im Wartungsmodus) und --initial (Vorschau/Live einmalig an Ort und Stelle auf Git umstellen) - dev/betrieb/vorschau-auffrischen.sh: Live-DB und Live-Medien in die Vorschau (Generalprobe) - InteriorReleaseSeeder: alle Inhaltsschritte des Relaunchs in einem Lauf, idempotent; Displays, Playlists und Mediathek bleiben unberührt - DisplayInteriorBrandingSeeder überschreibt keinen inzwischen gepflegten Claim mehr - Monitoring: GlitchTip (Server + Browser), /health mit Token, Scheduler-Herzschlag, Alarme per Mail und ntfy, Version in about und /health - public/build versioniert; .gitignore: macOS-Muster Icon traf resources/views/flux/icon/ - Runbook: dev/betrieb/README.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2519 lines
160 KiB
Markdown
2519 lines
160 KiB
Markdown
# Entwicklungsplan: B2in Interior – Neuausrichtung Website & CMS
|
||
|
||
**Erstellt:** 28.08.2026 · zuletzt aktualisiert 28.08.2026
|
||
**Basis:** `B2in_Interior-Konzept.md`, `umsetzungliste.md`, `umsetzung-inhalte.md`
|
||
**Vorgänger:** `dev/2026-02-27/b2in-website-umsetzungsplan.md`
|
||
**Rahmen:** 37–39 Std. freigegeben (18 + 8 + 4 + 3 + 4–6)
|
||
**Status:** Revision 14 – **AP0–AP6 umgesetzt**, Seite abgestimmt, Markentexte Rotpunkt und Febrü
|
||
eingearbeitet. **Arbeitsplan 14.09. (`umsetzungen-14-09-2026.md`), Punkt 1.1 Farbwelt und Logo
|
||
umgesetzt (Nachtrag 6).** Offen: Bildmaterial, Rechtstexte und die Herstellerfreigaben.
|
||
**Umgebung:** Dev Container, `php artisan …` (nicht `vendor/bin/sail …`)
|
||
|
||
> **Verbindliche Schreibweisen:** **Interior** (nicht „Interieur"), **Febrü**, **Rotpunkt Küchen**, **CABINET**.
|
||
> Das Konzeptpapier schreibt durchgehend „Interieur" – die Umsetzungsliste überschreibt das. Gilt für Code,
|
||
> Texte, Commit-Messages und Datenbank-Inhalte.
|
||
|
||
---
|
||
|
||
## 0. Stand & nächste Schritte
|
||
|
||
**Stand 03.09.2026:** T1 und B1–B13 abgearbeitet, **alle Arbeitspakete AP0–AP6 umgesetzt**, die
|
||
Bestandsinhalte auf den Interior-Auftritt umgestellt, die Seite abgestimmt und alle vier Punkte
|
||
der Abstimmungsrunde vom 03.09. umgesetzt (Nachtrag 5). Alle drei Markenseiten haben jetzt einen
|
||
ausführlichen Text. `php artisan test --compact`: **873 grün** (3217 Assertions), Pint sauber,
|
||
`npm run build:b2in` gebaut.
|
||
**Die Seite ist testbereit** – die ausstehenden Zulieferungen trägt Marcel selbst im CMS nach.
|
||
|
||
| Paket | Stand |
|
||
|---|---|
|
||
| AP0 Vorbereitung | ✅ |
|
||
| AP1 Umstrukturierung & Umtextung | ✅ |
|
||
| AP2 Kernmarken-Modul + `/marken` + Galerie | ✅ |
|
||
| AP3 Terminanfrage-Widget + WhatsApp-Link | ✅ (Nummer fehlt noch) |
|
||
| AP6 Sponsoring | ✅ |
|
||
| Bestandsinhalte FAQ / About / Kontakt / Magazin | ✅ |
|
||
| Markenseiten Rotpunkt und Febrü (Zulieferung 31.08.) | ✅ |
|
||
| Abstimmungsrunde 03.09.: korrigierte Texte, CABINET-Seite, Galerie-Hinweise, Abschluss-CTA | ✅ |
|
||
| AP4 Display-Spiegelung | ✅ |
|
||
| AP5 Rubrik-Seite „Referenzen" | ✅ |
|
||
| Arbeitsplan 14.09. · 1.1 Farbwelt, Logo je Welt, Welten-Wechsler | ✅ (Nachtrag 6) |
|
||
| Welten-Trennung: Navigation, Magazin, Über uns, FAQ, Widget je Welt | ✅ (Nachtrag 7, Erweiterung zu 1.1) |
|
||
| Arbeitsplan 14.09. · 1.2 Tischlerei als vierte Marke | ✅ Otterpohl mit Text und Logo (Nachtrag 9 + 15) |
|
||
| Arbeitsplan 14.09. · 1.4 Akkordeon und Widget-Beschriftung je Marke | ✅ (bereits seit 03.09., CABINET-Text fehlt im CMS) |
|
||
| Arbeitsplan 14.09. · 1.3 Herkunfts-Sektion „Aus der Region gefertigt“ | ✅ (Nachtrag 10 + 11: Standorte an der Marke, Ablauf CABINET von Marcel bestätigen lassen) |
|
||
| Abstimmung 23.09. · WhatsApp zuerst im Widget, Business-Nummer, Farbvariante „Modern“ mit Schalter | ✅ (Nachtrag 18, Palette von Marcel entscheiden lassen) |
|
||
| Briefing 24.09. · Entwurf Startseite „Greige“ mit Gold-Logo, Hero-Slideshow, Projekttext | ✅ Entwurf unter /entwurf (Nachtrag 19); offen: Foto Marcel, Slides selbst pflegen, Logo-Verläufe |
|
||
| Zulieferung 24.09. · Otterpohl Text v2, Bilder (Werkstatt + Referenzen) | ✅ (Nachtrag 19, Unterschriften und Referenzen-Fallback von Marcel bestätigen lassen) |
|
||
|
||
### Nächste Schritte
|
||
|
||
**Vor dem Versand des Testlinks — nichts.** Alle Seiten laden, die Suite ist grün, die Assets sind
|
||
gebaut. Was fehlt, ist Material, kein Code.
|
||
|
||
**Was Marcel selbst nachträgt (alles im CMS, ohne Codeänderung):**
|
||
|
||
| Was | Wo im Admin |
|
||
|---|---|
|
||
| Stimmungsbilder der drei Marken (Logos liegen seit 03.09. vor) | Kernmarken → Marke bearbeiten |
|
||
| Echte Projektfotos statt der Demobilder (siehe Warnung unten) | Kernmarken → Bildergalerie |
|
||
| Herstellerseiten-URLs | Kernmarken → Herstellerseite |
|
||
| Motiv für den Kopf von `/marken` | Inhalte → `marken` → `hero` |
|
||
| WhatsApp-Nummer – seit Nachtrag 18 per Seeder gesetzt (0521-98620100), Änderung weiter hier | Inhalte → `global` → `contact` → `whatsapp` |
|
||
| Welches Display auf der Website läuft | Inhalte → `referenzen` → `display_feed` → `display_id` |
|
||
|
||
**Beim Deployment mit erledigen (Abschnitt 8):**
|
||
|
||
1. **Rechtstexte** – AGB und Datenschutzerklärung beschreiben weiter das alte Geschäft
|
||
(„Connecting Design and Property", Dubai/Lissabon, Supply-Chain-Management,
|
||
`resources/lang/de/b2in_legal.php` Zeilen 117 und 221). Marcel lässt die Formulierung prüfen,
|
||
danach eintragen. Der WhatsApp-Absatz kommt im selben Zug dazu.
|
||
2. **OG-Bild** – das Layout verweist auf `img/assets/b2in-og-default.jpg`, die Datei existiert
|
||
nicht. Bis dahin zeigt jede geteilte Seite eine Vorschau ohne Bild.
|
||
3. **Seeder-Passwort rotieren** (B8) – steht weiter in der Git-Historie.
|
||
4. Die zwei Magazin-Beiträge und die Sponsoren-Kurztexte gegenlesen lassen.
|
||
5. **CABINET-Seitentext freigeben lassen** – für CABINET lag keine Zulieferung vor, der Text ist
|
||
von uns nach dem Muster der beiden abgestimmten Seiten verfasst (Nachtrag 5).
|
||
6. **Demobilder der Rubrik „Realisiertes Projekt" ersetzen.** Seit dem Entfallen der
|
||
„BEISPIEL"-Kennzeichnung geben sie sich als echte Referenzen aus.
|
||
|
||
**Danach offen, aber nicht Teil dieses Auftrags:** YouTube-Einbindung mit Consent-Gate auf der
|
||
Referenzen-Seite (Abschnitt 4). Sinnvoll, sobald es Videos gibt – vorher wäre es ein Consent-Gate
|
||
ohne Inhalt.
|
||
|
||
---
|
||
|
||
## 1. Ist-Architektur (relevanter Ausschnitt)
|
||
|
||
### 1.1 Content-Pipeline
|
||
|
||
```
|
||
resources/lang/de/b2in.php (themes.b2in.<section>) ← Quelltexte / Fallback
|
||
├─ config/cms_section_map.php section → [group, key]
|
||
├─ database/seeders/CmsContentSeeder.php
|
||
▼
|
||
flux_cms_contents (group, key, type, value:JSON, translatable de/en)
|
||
├─ FluxCms\Core\Services\CmsContentService (Cache: flux_cms.content.__all__)
|
||
▼
|
||
cms_theme_section('hero') → CMS gewinnt, sonst trans('b2in.themes.b2in.hero')
|
||
```
|
||
|
||
Redaktion unter `admin/flux-cms/content` → [`content-index.blade.php`](../../resources/views/livewire/admin/cms/content-index.blade.php)
|
||
(Volt, 782 Z.): Group/Key-Editor mit JSON-Repeater-Modal, Medien-Picker, Flux-Editor für HTML.
|
||
**Kann Werte ändern, aber keine Sektion neu anlegen.**
|
||
|
||
### 1.2 Seiten & Sektionen
|
||
|
||
- Startseite: `routes/web.php` → `resources/views/web/home.blade.php`
|
||
- Sektionen = Livewire-Komponenten unter `app/Livewire/Web/Components/Sections/`,
|
||
Muster `mount() { $this->content = cms_theme_section('<key>'); }`
|
||
- Ist-Reihenfolge: `header → hero → founder-bar → content-section(synergie) → vision-section → ecosystem-core → cta-section → footer`
|
||
- Navigation und Ankündigungsleiste liegen **bereits im CMS** (`global.header.navigation`, `global.announcement_bar`)
|
||
→ Umbau ist Redaktion, kein Code.
|
||
- SEO: `@section('title')` / `@section('meta_description')` je View; OG-Tags leiten sich
|
||
in `web-master.blade.php` automatisch daraus ab → **OG kostet keinen Extra-Aufwand** (aber siehe B6).
|
||
- Immobilien rendern statisch aus `resources/lang/de/immobilien-azizi.json` – wie gefordert.
|
||
|
||
### 1.3 Display-CMS
|
||
|
||
`Display` (Gerät) → `DisplayPlaylist` (draft/published) → `DisplayVersion` („Modul", Enum
|
||
`DisplayVersionType`: `video-display` | `b2in` | `offers`) → `DisplayVersionItem`.
|
||
[`DisplayPlaylistConfigBuilder`](../../app/Services/DisplayPlaylistConfigBuilder.php) erzeugt das
|
||
Player-JSON. Player: `public/_cabinet/display/index.html`, festes 1080×1920-Raster (9:16), per Scale eingepasst.
|
||
API vorhanden: `/api/display/{display}/config`, `/api/display/preview/{token}`,
|
||
`/api/display/module/{module}/preview` – registriert für Portal-Domain **und** als Fallback für alle Domains.
|
||
|
||
### 1.4 Sonstiges
|
||
|
||
- Kontaktformular: `packages/acme/contact-form` – **unterstützt bereits `customFields` + Presets,
|
||
Honeypot, Rate-Limit und `SpamDetector`.** Das Terminanfrage-Widget kann darauf aufsetzen.
|
||
- Tests: Pest, SQLite in-memory, `php artisan test --compact`.
|
||
|
||
---
|
||
|
||
## 2. Gefundene Bugs & Optimierungen
|
||
|
||
Beim Abgleich der Umsetzungsliste mit dem Code aufgefallen.
|
||
|
||
**Stand 28.08.2026: alle Befunde behoben, Suite grün (699 Tests, 2715 Assertions).**
|
||
|
||
| # | Befund | Status |
|
||
|---|---|---|
|
||
| T1 | Info-Tablet: Leeren per X wird nicht gespeichert | ✅ behoben |
|
||
| B1 | CMS-Seeder überschreibt redaktionelle Inhalte | ✅ behoben |
|
||
| B2 | Magazin-CMS nicht ans Frontend angeschlossen | ✅ behoben (Variante A: Slug-Routen + 301) |
|
||
| B3 | Ankündigungsleiste bleibt nach Umtexten unsichtbar | ✅ behoben |
|
||
| B4 | Footer hartkodiert, nicht pflegbar | ✅ behoben |
|
||
| B5 | Englische Footer-Labels auf deutscher Seite | ✅ behoben |
|
||
| B6 | 19 Seiten erben alte Dubai-Beschreibung | ✅ behoben (Fallback + canonical) |
|
||
| B7 | Content-Seeder nicht registriert | ✅ behoben |
|
||
| B8 | Klartext-Passwort im Seeder | ✅ behoben |
|
||
| B9 | Medien-Picker greift bei leeren Logo-Feldern nicht | ✅ behoben |
|
||
| B10 | Alt-Begriffe im Seiteninhalt | ✅ behoben in AP1 |
|
||
| B12 | `/service` und `/portfolio` lieferten 500 | ✅ behoben (301) |
|
||
| B11 | `/magazin/{unbekannt}` liefert 200 statt 404 | ✅ behoben |
|
||
|
||
---
|
||
|
||
### T1 · Info-Tablet: Leeren der Öffnungszeiten wird nicht gespeichert ✅
|
||
|
||
Gemeldet am 28.08.2026: „Wenn ich den Inhalt weg-X, kommt nicht Geschlossen. Der Wert kommt
|
||
wieder, wenn ich in ein anderes Feld klicke. Setze ich Öffnung und Schluss auf X und speichere,
|
||
ist Öffnung wieder der alte Wert."
|
||
|
||
**Drei Ursachen, alle in `cabinet-info-tablet.blade.php` bzw. `CabinetInfoTablet.php`:**
|
||
|
||
1. **Zwei Submit-Handler auf demselben Formular.** `wire:submit.prevent="save"` **und**
|
||
`x-on:submit.prevent="… $wire.save(hours)"` waren gleichzeitig gebunden – `save()` lief pro
|
||
Klick zweimal, einmal mit den DOM-Werten und einmal ohne. Welcher Aufruf zuletzt schrieb,
|
||
war nicht deterministisch. Das erklärt „speichert nur den letzten".
|
||
2. **`wire:model.live` auf den Zeit-Pickern.** Jede Änderung löste einen Roundtrip aus; beim
|
||
erneuten Rendern hat Livewire ein zuvor geleertes Feld mit dem unveränderten Serverwert
|
||
überschrieben. Das erklärt „der Wert kommt wieder, wenn ich in ein anderes Feld klicke".
|
||
3. **Geöffnet/Geschlossen wurde serverseitig gerechnet** und konnte deshalb erst nach einem
|
||
Roundtrip umspringen. Das erklärt „es kommt nicht Geschlossen".
|
||
|
||
**Behoben:** nur noch ein Submit-Pfad (das DOM ist die Quelle der Wahrheit), `.live` entfernt,
|
||
die Geöffnet/Geschlossen-Anzeige rechnet clientseitig per Alpine und reagiert damit sofort auf das X.
|
||
|
||
**Zusätzlich:** `save(array $hours)` hat über `property_exists()` **jede** öffentliche Property
|
||
aus dem Client-Payload beschreibbar gemacht – auch `storeStatus` und `contactEmail`. Jetzt greift
|
||
eine Allowlist auf die 14 Zeitfelder.
|
||
|
||
**Tests:** 5 neue Fälle in `tests/Feature/CabinetInfoTabletTest.php` (15 grün) – u. a. mehrere Tage
|
||
in einem Submit leeren, nur die Öffnung leeren, Fallback ohne DOM-Payload, Allowlist.
|
||
|
||
**Noch am Gerät zu prüfen:** die drei Ursachen liegen im Browser-Verhalten; die Tests sichern den
|
||
Serverpfad ab. Bitte im Portal einmal gegenprüfen: mehrere Tage leeren → speichern → neu laden.
|
||
|
||
### B1 · Der CMS-Seeder überschreibt alles, was Marcel pflegt ✅
|
||
|
||
`database/seeders/CmsContentSeeder.php:76-90` – bestehende Einträge werden bedingungslos
|
||
per `$content->update()` mit den Werten aus der Lang-Datei überschrieben. Geschützt sind nur
|
||
die zwei Sektionen in `$skipSections`.
|
||
|
||
**Wirkung:** Jeder erneute Seeder-Lauf – auch der geplante nach der Umtextung – setzt sämtliche
|
||
redaktionellen Änderungen zurück. Die Zusage „von Marcel selbst pflegbar" hält so nicht.
|
||
|
||
**Behoben:** Default ist jetzt „nur anlegen, wenn nicht vorhanden". Überschreiben nur noch über
|
||
`$seeder->overwriteExisting = true`. Der Lauf meldet, wie viele Einträge unangetastet blieben, und
|
||
leert den CMS-Cache, wenn er etwas geändert hat.
|
||
**Tests:** 3 neue Fälle in `tests/Feature/Cms/CmsContentSeederTest.php` – gepflegter Inhalt bleibt,
|
||
fehlende Sektionen werden trotzdem angelegt, bewusstes Überschreiben funktioniert.
|
||
|
||
### B2 · Das Magazin-CMS ist nicht mit dem Frontend verbunden ✅
|
||
|
||
- Admin `admin/flux-cms/articles` schreibt nach `cms_articles` (Model `CmsArticle`).
|
||
- Frontend liest `trans('b2in.articles')`:
|
||
`app/Livewire/Web/Components/Sections/MagazinList.php:20` und `MagazinDetail.php:48`.
|
||
- `CmsArticle` wird **außerhalb des Admin-Bereichs nirgends verwendet** (verifiziert per Grep).
|
||
|
||
**Wirkung 1:** Was Marcel im Magazin-CMS bearbeitet, erscheint nicht auf der Website.
|
||
**Wirkung 2 (für dieses Projekt entscheidend):** Die Umsetzungsliste sagt für die Kernmarken
|
||
„adaptiert vom **Magazin-Muster**". Das Admin-CRUD ist als Vorlage brauchbar, die
|
||
Frontend-Anbindung fehlt dort aber – **dieser Fehler darf nicht mitkopiert werden.**
|
||
|
||
**Bei der Umsetzung aufgefallen – das ist kein reiner Verdrahtungsfehler:**
|
||
Die Artikel liegen in beiden Quellen (5 in `cms_articles`, 5 in der Lang-Datei, inhaltsgleich),
|
||
**aber unter verschiedenen Schlüsseln**: die Lang-Datei nutzt 1–5, die Datenbank die IDs 8–12.
|
||
Die öffentlichen URLs lauten heute `/magazin/1` … `/magazin/5`. Eine Umstellung auf das Model
|
||
**ändert damit die öffentlichen URLs** und braucht eine Slug-Route plus Weiterleitungen von den
|
||
alten numerischen IDs – sonst brechen bestehende Links und die Google-Indexierung.
|
||
|
||
**Deshalb bewusst nicht einfach umgestellt.** Entscheidung nötig:
|
||
|
||
| Variante | Aufwand | Wirkung |
|
||
|---|---|---|
|
||
| A · Slug-Routen `/magazin/{slug}` + 301 von den alten IDs | ≈3–4 Std. | sauber, CMS wird wirksam, URLs werden sprechend |
|
||
| B · Numerische Route beibehalten, Auflösung über die DB-ID | ≈2 Std. | CMS wird wirksam, aber `/magazin/1` … `/magazin/5` werden zu 404 |
|
||
| C · Vorerst so lassen | 0 | Magazin funktioniert, das Magazin-CMS bleibt aber wirkungslos |
|
||
|
||
**Umgesetzt: Variante A.**
|
||
|
||
- `CmsArticle::forFrontend()` liefert die veröffentlichten Artikel nach Slug indiziert.
|
||
Das CMS gewinnt; solange keine Artikel gepflegt sind, greift die Lang-Datei als Fallback –
|
||
dieselbe Reihenfolge wie bei `cms_theme_section()`, damit das Magazin auf einer frischen
|
||
Installation nicht leer ist.
|
||
- Die ID→Slug-Zuordnung lag als private Konstante im `CmsArticleSeeder` und ist jetzt
|
||
`CmsArticle::LEGACY_ID_TO_SLUG` – eine Quelle für Seeder, Fallback und Weiterleitung.
|
||
- `MagazinList` und `MagazinDetail` lesen aus dem Model statt aus `trans('b2in.articles')`;
|
||
die Übersicht verlinkt über `route('magazin.detail')` statt über die numerische ID.
|
||
- Neue Route `/magazin/{slug}`. Die alten `/magazin/1` … `/magazin/5` leiten dauerhaft (301)
|
||
auf den Slug um; sie stehen per `whereNumber()` **vor** der Slug-Route, sonst würde diese
|
||
die Ziffern selbst schlucken. Numerische IDs ohne Zuordnung liefern 404.
|
||
- Die Detailseite fragte die Artikel zweimal ab (Artikel + verwandte Artikel) – jetzt gemerkt,
|
||
eine Abfrage pro Seitenaufruf.
|
||
|
||
**Tests:** `tests/Feature/MagazinPageTest.php` auf 13 Fälle erweitert – Slug-Auslieferung,
|
||
301 von jeder alten ID, 404 bei unbekanntem Slug, CMS schlägt Lang-Datei, unveröffentlichte
|
||
Artikel sind unsichtbar, Fallback bei leerer Tabelle. `LiveSiteReviewTest` prüft für jede alte
|
||
ID die Weiterleitung **und** dass das Ziel lädt.
|
||
|
||
⚠️ **Beim Deployment:** `/magazin/1` … `/magazin/5` sind indexiert. Die 301 fängt sie ab, aber
|
||
nach dem Livegang bitte einmal in der Search Console gegenprüfen. Externe Links, die noch auf
|
||
die alten URLs zeigen, bleiben funktionsfähig.
|
||
|
||
**Nebenbefund, nicht angefasst:** `MagazinDetail::$relatedArticles` wird berechnet, aber von
|
||
keiner View gerendert – entweder die Sektion „verwandte Artikel" nachziehen oder die Property
|
||
entfernen. Deine Entscheidung.
|
||
|
||
### B3 · Ankündigungsleiste: alte Wegklicker sehen die neue Leiste nie ✅
|
||
|
||
`announcement-bar.blade.php:2` merkt sich das Wegklicken in
|
||
`localStorage['announcement_dismissed_<id>']`. Bleibt die `id` beim Umtexten gleich, bleibt die
|
||
Leiste für alle Wiederkehrer unsichtbar.
|
||
|
||
**Behoben:** Der Dismiss-Schlüssel wird jetzt aus Inhalt **und** `id` abgeleitet
|
||
(`AnnouncementBar::getDismissKeyProperty()`). Wird die Leiste im CMS neu belegt, sehen auch
|
||
Wiederkehrer die neue Meldung – ohne dass jemand daran denken muss, die `id` mitzuändern.
|
||
**Tests:** 2 neue Fälle in `tests/Feature/AnnouncementBarTest.php`.
|
||
|
||
### B4 · Der Footer ist vollständig hartkodiert ✅
|
||
|
||
`footer.blade.php` – Claim „Connecting Design and Property" steht in Zeile 15 im Markup,
|
||
`Footer.php` lädt überhaupt keinen Content. Es gibt keine `footer`-Sektion in `cms_section_map.php`.
|
||
|
||
**Wirkung:** Sowohl „Footer-Claim ersetzen" als auch „FAQ in den Footer" aus der Umsetzungsliste
|
||
erfordern einen kleinen Umbau; Marcel kann den Claim danach ohne CMS-Anbindung weiterhin nicht ändern.
|
||
**Behoben:** Neue CMS-Sektion `global.footer` (Claim, Byline, Linkliste) in `cms_section_map.php`
|
||
und in beiden Lang-Dateien. `Footer.php` lädt sie über `cms_theme_section('footer')`, die View
|
||
rendert Claim und Links daraus und fällt ohne CMS-Eintrag auf sinnvolle Defaults zurück.
|
||
Der Claim lautet jetzt „Premium-Einrichtung. Persönlich gemacht.", FAQ ist als erster Link drin.
|
||
**Tests:** `tests/Feature/FooterTest.php` (4 Fälle).
|
||
|
||
### B5 · Englische Footer-Labels auf der deutschen Seite ✅
|
||
|
||
„Privacy Policy", „Terms of Service", „Cookie Policy" waren hartkodiert englisch, während
|
||
„Impressum" korrekt über `__('ui.legal_notice')` lief.
|
||
**Behoben:** neue Keys `privacy_policy`, `terms_of_service`, `cookie_policy`, `faq` in
|
||
`resources/lang/{de,en}/ui.php`; die deutsche Seite zeigt jetzt Datenschutz / AGB /
|
||
Cookie-Richtlinie / Häufige Fragen / Impressum.
|
||
|
||
### B6 · 19 Seiten tragen die alte Dubai-Beschreibung ✅
|
||
|
||
`web-master.blade.php:11` und `:18` haben als Fallback fest verdrahtet:
|
||
„B2in – Connecting Design and Property. Exklusive Immobilien in Dubai & europäisches Einrichtungsnetzwerk."
|
||
19 Views unter `resources/views/web/` setzen **kein** `@section('meta_description')` und erben damit
|
||
diesen Text – darunter die Live-Seite `magazin-detail.blade.php`.
|
||
|
||
**Behoben:** Der Fallback in `web-master.blade.php` (Description **und** OG-Description) trägt
|
||
jetzt den Interior-Text aus `umsetzung-inhalte.md` §0. Zusätzlich `<link rel="canonical">` ergänzt,
|
||
das fehlte komplett.
|
||
**Offen als B10:** Der Alt-Begriff-Bestand im Seiteninhalt („Supply-Chain", „Local-for-Local",
|
||
„Ökosystem", „Investment", „Connecting Design") – **90 Treffer in 14 Dateien**, u. a. der
|
||
Hero-`card_text`. Das ist Content-Arbeit mit den freigegebenen Texten und gehört in AP1, nicht
|
||
in einen Bugfix.
|
||
|
||
### B7 · Content-Seeder sind nirgends registriert ✅
|
||
|
||
`DatabaseSeeder::run()` ruft nur `TestDisplaySeeder`. `CmsContentSeeder`, `CmsArticleSeeder`,
|
||
`CmsProjectSeeder`, `CmsLegalSeeder`, `NetzwerkPageCmsSeeder` müssen von Hand aufgerufen werden;
|
||
ein frisch aufgesetztes System hat keine CMS-Inhalte.
|
||
**Behoben:** `CmsContentSeeder`, `CmsLegalSeeder`, `NetzwerkPageCmsSeeder`, `CmsArticleSeeder`
|
||
und `CmsProjectSeeder` sind in `DatabaseSeeder::run()` registriert – nach dem B1-Fix gefahrlos,
|
||
weil bestehende Inhalte unangetastet bleiben.
|
||
|
||
### B8 · Klartext-Passwort im Seeder ✅
|
||
|
||
`database/seeders/DatabaseSeeder.php` enthielt ein echtes Passwort im Repo.
|
||
**Behoben:** Zugangsdaten kommen jetzt aus `config/seeding.php` bzw. `SEED_ADMIN_*` in der `.env`;
|
||
`.env.example` ist ergänzt.
|
||
⚠️ **Das alte Passwort steht weiterhin in der Git-Historie – bitte rotieren, falls es irgendwo
|
||
sonst benutzt wird.**
|
||
|
||
### B9 · Medien-Picker greift bei leeren Logo-Feldern nicht ✅
|
||
|
||
`content-index.blade.php` → `_cmsFieldLooksLikeImage()` erkennt Bildfelder an einer festen
|
||
Feldnamen-Liste **oder** an der Dateiendung **im Wert**. `logo` steht nicht in der Liste, und ein
|
||
noch leeres Feld hat keinen Wert → wird als reines Textfeld gerendert.
|
||
|
||
**Wirkung:** Marcel kann bei einer neu angelegten Marke bzw. bei den Sponsoring-Logos das Bild
|
||
nicht per Picker setzen, sondern müsste den Dateinamen abtippen. Betrifft AP2 und AP6 direkt.
|
||
**Behoben:** `logo` in die Feldnamen-Liste und `_logo$` in die Suffix-Regex aufgenommen. Zusätzlich
|
||
prüft `_cmsFieldLooksLikeImage()` den Feldnamen jetzt **vor** dem Wert – ein noch leeres Bildfeld
|
||
wird dadurch als Bild erkannt und bekommt den Picker. (`logo_width` bleibt korrekt ein Textfeld.)
|
||
|
||
### B11 · `/magazin/{unbekannte-id}` liefert 200 statt 404 ✅
|
||
|
||
`MagazinDetail::loadArticle()` fiel bei unbekannten IDs still auf Artikel 1 zurück
|
||
(`$articles[$this->articleId] ?? $articles[1]`). `/magazin/999` lieferte damit Status 200 mit dem
|
||
Inhalt von Artikel 1 – beliebig viele URLs mit identischem Inhalt, schlecht für die Indexierung,
|
||
und bei fehlendem Artikel 1 ein Fehler statt einer 404.
|
||
|
||
**Behoben:** `abort_unless(isset($articles[$this->articleId]), 404)`.
|
||
**Tests:** 2 neue Fälle in `tests/Feature/MagazinPageTest.php`.
|
||
|
||
---
|
||
|
||
## 3. Arbeitspakete
|
||
|
||
Gliederung folgt der Umsetzungsliste. Reihenfolge nach dem Vorschlag aus `umsetzung-inhalte.md`.
|
||
|
||
### AP0 · Vorbereitung (im Rahmen von AP1)
|
||
|
||
Branch `feature/b2in-interior`, DB-Backup, Backup der Startseite (Muster
|
||
`dev/2026-02-27/backup-before-relaunch/`), `php artisan test --compact` als Referenzstand.
|
||
|
||
### AP1 · Website-Umstrukturierung & Umtextung — ✅ umgesetzt
|
||
|
||
**Global**
|
||
- Meta-Title und Description auf Interior umgestellt; fünf Live-Seiten hatten gar keine eigene
|
||
Description und erbten den Fallback – jetzt gesetzt (`magazin-detail`, `impressum`, `privacy`,
|
||
`terms`, `cookie-policy`). OG-Tags leiten sich automatisch ab.
|
||
- Navigation: `Home · Marken · Magazin · Immobilien · Über B2in`. „Netzwerk" ist raus (Seite bleibt
|
||
erreichbar), FAQ steht im Footer. „Referenzen" kommt mit AP5 dazu.
|
||
- Footer-Claim „Premium-Einrichtung. Persönlich gemacht." (siehe B4).
|
||
|
||
**Startseite** – neue Reihenfolge in `resources/views/web/home.blade.php`:
|
||
`header → hero → marcel-badge → weiche → kernmarken → über-marcel → sponsoring → immobilien-teaser → abschluss-cta → footer`
|
||
- Ankündigungsleiste neu belegt (Rotpunkt Küchen), inkl. neuer `id`.
|
||
- Hero: neue Headline, Subline, zwei Buttons, drei Checkmarks, Bild-Badge „Einrichtung, die bleibt."
|
||
- Marcel-Badge umgetextet.
|
||
- **Neu:** `Sections/AudienceSwitch` (Weiche Privat/Geschäft) – ersetzt „Zwei Welten. Ein Netzwerk."
|
||
- **Neu:** `Sections/CoreBrands` mit CABINET, Rotpunkt Küchen, Febrü (Anker `#marken`).
|
||
Febrü bewusst mit Home-Office zuerst. **Datenquelle ist vorerst das CMS-Sektionsfeld –
|
||
in AP2 wird sie durch das Model `CmsBrand` samt Detailseiten ersetzt.** Das Markup bleibt.
|
||
- **Neu:** `Sections/Sponsoring` (AP6) und `Sections/ImmobilienTeaser`.
|
||
- „Ein Ökosystem, drei Säulen" ist von der Startseite genommen, die Komponente bleibt als Archiv.
|
||
|
||
**Sponsoring-Logos:** je Verein eine Datei gewählt, auf max. 400 px Breite herunterskaliert
|
||
(326 KB → 130 KB) und nach `public/img/assets/sponsoring/` übernommen. Die drei Seitenverhältnisse
|
||
sind sehr unterschiedlich (500×262, 689×689, 2443×741), deshalb eine feste Box je Logo.
|
||
`tc-bad-waldliesborn-horn` liegt nur als JPG vor und hat damit keinen transparenten Hintergrund.
|
||
|
||
**Durchgang Alt-Begriffe:** auf allen Live-Seiten bereinigt – Startseite, `/about`, `/contact`,
|
||
`/immobilien` sind sauber; `/netzwerk` und `/faq` ebenfalls. Nicht angefasst: die
|
||
**Magazin-Artikel**, die inhaltlich über Supply-Chain und Investments handeln – das sind
|
||
redaktionelle Beiträge, keine Seitentexte.
|
||
|
||
**Tests:** `tests/Feature/HomePageStructureTest.php` (11 Fälle: Reihenfolge, Hero-Buttons und
|
||
-Checkmarks, Kernmarken samt Anker, Febrü-Gewichtung, Navigation, SEO, Sponsoring-Logos);
|
||
`AnnouncementBarTest` und `LiveSiteReviewTest` auf die neuen Inhalte gezogen.
|
||
|
||
---
|
||
|
||
#### ⚠️ Wichtig fürs Deployment: der Relaunch-Seeder
|
||
|
||
`cms_theme_section()` bevorzugt das CMS gegenüber der Lang-Datei. 14 der neu getexteten Sektionen
|
||
lagen bereits mit den **alten** Texten im CMS und hätten die neuen Inhalte überdeckt – der reguläre
|
||
`CmsContentSeeder` fasst bestehende Einträge seit B1 bewusst nicht mehr an.
|
||
|
||
Deshalb gibt es `InteriorRelaunchCmsSeeder`: er überschreibt **genau die 19 in AP1 geänderten
|
||
Sektionen** aus den Lang-Dateien und lässt alles andere in Ruhe.
|
||
|
||
```
|
||
php artisan db:seed --class=InteriorRelaunchCmsSeeder
|
||
```
|
||
|
||
Auf der lokalen Datenbank bereits gelaufen (5 angelegt, 14 aktualisiert). **Auf dem Live-System
|
||
vor dem Lauf ein DB-Backup ziehen** – er überschreibt in diesen Sektionen auch redaktionelle
|
||
Änderungen. Danach `npm run build:web`.
|
||
|
||
---
|
||
|
||
#### Nebenbefund B12 · `/service` und `/portfolio` lieferten 500 ✅
|
||
|
||
Beide Seiten sind öffentlich erreichbar, aber ihre Content-Sektionen (`hero_image`,
|
||
`content_section_left/right`, `portfolio`) existieren in keiner Lang-Datei mehr – vermutlich seit
|
||
dem Februar-Relaunch. Sie warfen seitdem einen 500er; da sie in keinem Test vorkamen, ist es
|
||
niemandem aufgefallen. **Verifiziert: älter als AP1, keine Regression.**
|
||
|
||
**Behoben** wie bei den anderen stillgelegten Seiten per 301 (`/service` → `/netzwerk`,
|
||
`/portfolio` → `/immobilien`); die Views bleiben als Archiv liegen. Beide Ziele sind eine
|
||
Zeile in `routes/web.php`, falls Du woandershin umleiten möchtest.
|
||
|
||
---
|
||
|
||
#### Was in AP1 offen bleibt
|
||
|
||
| Punkt | Grund |
|
||
|---|---|
|
||
| Hero-Bildmotiv, Kachelbilder, OG-Image | Zulieferung offen, Bestandsbild bleibt |
|
||
| Navigationspunkt „Referenzen" | kommt mit der Seite in AP5 |
|
||
| Teaser „Aktuelles aus unseren Showrooms" | kommt mit AP5, sonst zeigt er ins Leere |
|
||
|
||
---
|
||
|
||
#### Logo mit Zusatz „Interior" ✅ (Zulieferung eingetroffen)
|
||
|
||
Marcel hat die Dateien geliefert (`dev/2026-08-28/logos/`) – die typografische Eigenlösung
|
||
entfällt damit. Beide Varianten sind identisch aufgebaut und unterscheiden sich nur im Füllwert:
|
||
positiv `#314052`, negativ `#FFFFFF`; der blaue Akzent `#2C9FDA` bleibt in beiden. Trotz „CMYK"
|
||
im Dateinamen enthalten die SVGs RGB-Hexwerte, die Schrift liegt in Pfaden.
|
||
|
||
**Zuschnitt war nötig:** Die Lieferung lag auf einem A4-Artboard (595,3 × 419,5) – gemessen
|
||
**74 % leerer Weißraum**. Ungeschnitten hätte das Logo bei gleicher CSS-Höhe rund halb so groß
|
||
gerendert wie das bisherige. Der Inhaltsrahmen wurde durch Rendern ermittelt und das viewBox auf
|
||
`153 96 289.3 227.5` gezogen (98 % Füllgrad, gleichmäßige Randluft, Verhältnis 1,27:1).
|
||
|
||
Abgelegt als `public/img/logos/b2in-interior-logo-{positive,negative}.{svg,png}`; die alten
|
||
`b2in-logo-*`-Dateien bleiben als Archiv liegen.
|
||
|
||
**Angepasst:** `ThemeHelper` (b2in → neue Dateien) · Header `h-10` → `h-12` und Footer `h-14` →
|
||
`h-16`, weil das neue Lockup gestapelt ist und die Wortmarke bei gleicher Höhe kleiner wirkt ·
|
||
Footer- und Mail-`width`/`height`-Attribute auf das neue Verhältnis korrigiert (standen auf
|
||
2,14:1 bzw. 3,5:1 und passten schon vorher nicht) · Mail-Header nutzt das neue PNG.
|
||
|
||
**Display ebenfalls umgestellt** (Marcel möchte es laut Mail einheitlich):
|
||
|
||
- Beide Varianten liegen jetzt auch unter `public/_cabinet/assets/`.
|
||
- `DisplayModuleSettings`: Default-Logo und Claim getauscht. Der Claim stand dort noch auf
|
||
„Connecting Design & Property".
|
||
- **Variante nach Theme:** Das Standard-Theme ist `dark`, dort liegt das Logo auf einem dunklen
|
||
Scrim – bislang stand da die **dunkle** Variante (deshalb der `drop-shadow` im Player). Jetzt
|
||
dunkles Theme → negativ/weiß, helles Theme → positiv.
|
||
- Logo-Höhe im Player von `3.5vh` auf `4.6vh`, weil das neue Lockup gestapelt ist.
|
||
- `DisplayInteriorBrandingSeeder` vereinheitlicht die bestehenden Module. Vorher liefen dort
|
||
**vier verschiedene Logo-Quellen** nebeneinander (zwei Dateien aus der Medienbibliothek, ein
|
||
relativer und ein absoluter Asset-Pfad) und zwei Module trugen den Claim „Hello".
|
||
|
||
---
|
||
|
||
#### B13 · Live-Displays zeigten auf eine lokale Entwicklungsdomain ⛔→✅
|
||
|
||
Beim Vereinheitlichen aufgefallen: Medien-URLs lagen als **absolute URLs mit fest verdrahtetem
|
||
Host** in den Moduleinstellungen und Item-Inhalten – teils `b2in.eu`, teils **`b2in.test`**.
|
||
Der Player gibt absolute URLs unverändert zurück, ein auf `b2in.test` verweisendes Medium kann auf
|
||
dem Live-Display also nicht laden.
|
||
|
||
**Betroffen waren vier veröffentlichte Playlists:** „Display 4 – Innen", „Kundenstopper",
|
||
„Display 2" und „Test-Display" – unter anderem über das Modul „Cabinet-Influencerin", das auf
|
||
drei der vier Displays läuft.
|
||
|
||
**Behoben:** `DisplayMediaUrlNormalizerSeeder` schreibt Schema + Host auf einen reinen Pfad um.
|
||
Relative Pfade löst der Player über `resolveDisplayUrl()` gegen die Portal-Basis auf und
|
||
funktionieren damit auf Test- **und** Live-System. 23 Verweise umgeschrieben, 0 verblieben.
|
||
|
||
Ziel-Links (Footer-URL, QR-Ziel wie `cabinet-bielefeld.de`) bleiben bewusst absolut – der Filter
|
||
greift nur bei einem B2in-Host **und** einem Pfad unterhalb von `/storage/`. Nachgeprüft: die
|
||
fünf Ziel-Links stehen unverändert.
|
||
|
||
**Tests:** `DisplayInteriorBrandingTest` (6) und `DisplayMediaUrlNormalizerTest` (6).
|
||
|
||
⚠️ **Wichtig:** Ob die betroffenen Mediendateien auf dem Live-Server überhaupt vorhanden sind,
|
||
kann ich von hier nicht prüfen. Wurden sie nur lokal hochgeladen, fehlen sie dort weiterhin –
|
||
der relative Pfad ist dann trotzdem richtig, aber die Datei muss nachgezogen werden.
|
||
Nach dem Deployment bitte die vier Displays einmal sichten.
|
||
|
||
**Deployment-Reihenfolge:**
|
||
```
|
||
php artisan db:seed --class=InteriorRelaunchCmsSeeder
|
||
php artisan db:seed --class=DisplayInteriorBrandingSeeder
|
||
php artisan db:seed --class=DisplayMediaUrlNormalizerSeeder
|
||
npm run build:web
|
||
```
|
||
|
||
### AP2 · Kernmarken-Modul im CMS — ✅ umgesetzt
|
||
|
||
**Model + Migration:** `CmsBrand` / Tabelle `cms_brands`.
|
||
⚠️ Bewusst **nicht** `Brand` – das Model existiert bereits im Produkt-/Partner-Kontext
|
||
(`Partner::brand()`, `Product::brand()`) und bleibt unangetastet. Ein Test hält das fest.
|
||
|
||
Felder: `slug`, `name`, `tagline`, `teaser`, `description` (HTML), `logo`, `image`, `services`,
|
||
`gallery`, `website_url`, `showroom`, `is_published`, `order`.
|
||
Übersetzt werden `name`, `tagline`, `teaser`, `description`.
|
||
|
||
**Die Lehre aus B2 ist eingebaut:** Das Frontend liest direkt aus dem Model, nicht aus einer
|
||
Lang-Datei. `CmsBrand::forFrontend()` liefert die veröffentlichten Marken nach Slug indiziert;
|
||
solange keine Marke gepflegt ist, greift die Lang-Sektion `core_brands` als Fallback. Die
|
||
Fallback-Einträge tragen `has_detail_page = false`, damit die Kachel dann nicht auf eine
|
||
Detailseite verlinkt, die es noch nicht gibt.
|
||
|
||
**Admin:** `admin/flux-cms/brands` → `brands-index.blade.php` (Volt), aufgebaut nach dem
|
||
Magazin-Muster. Medien über den bestehenden `MediaPicker` (Logo, Stimmungsbild, Galerie), die
|
||
Einleitung über den Flux-Editor mit `CmsFluxEditorHtmlTransformer`. Slug wird auf Format und
|
||
Eindeutigkeit geprüft. Eigene Karte im CMS-Dashboard.
|
||
|
||
**Frontend:**
|
||
- `Sections/CoreBrands` rendert die Kacheln aus dem Model (Anker `#marken`).
|
||
- Neue Route `/marken/{slug}` mit `Sections/BrandDetail` und der Vorlage-Struktur aus
|
||
`umsetzung-inhalte.md` §5: Header (Logo + Claim + Stimmungsbild) → Einleitung → Leistungen →
|
||
Galerie → CTA, dazu eine Leiste mit den übrigen Marken.
|
||
- Eigener Title und eigene Description je Marke.
|
||
- Unveröffentlichte Marken liefern 404 und verschwinden von der Startseite.
|
||
|
||
**Seeder:** `CmsBrandSeeder` legt CABINET, Rotpunkt Küchen und Febrü mit den Texten aus
|
||
`umsetzung-inhalte.md` §5 sowie je vier Leistungen an – Febrü mit Home-Office zuerst.
|
||
Bestehende Marken werden **nicht** überschrieben, Marcel pflegt sie im Admin.
|
||
|
||
**Tests:** `Cms/CmsBrandTest` (8), `BrandPageTest` (11), `Admin/Cms/CmsBrandsIndexTest` (11) –
|
||
darunter die Gegenprobe zu B2: eine im CMS neu angelegte Marke erscheint ohne Codeänderung auf
|
||
der Startseite **und** bekommt ihre Detailseite.
|
||
|
||
#### Nachtrag: eigene Unterseite `/marken`
|
||
|
||
Auf Wunsch nach der Sichtung – Grundlage `dev/2026-08-28/unterseite_marke.md`. Die Startseite
|
||
bleibt wie sie ist, die Kernmarken-Sektion dort ist jetzt ein **Teaser**.
|
||
|
||
- **Neue Seite `/marken`** mit dem Aufbau aus der Spec: Seitenkopf mit Breadcrumb (Home → Marken)
|
||
→ Kernmarken → Partnernetzwerk → „Markenwelt wächst" → Abschluss-CTA. Eigener Title und eigene
|
||
Description.
|
||
- **Zwei Textebenen je Marke.** Dafür kamen zwei Felder dazu (`summary`, `highlights`):
|
||
|
||
| Feld | Wo |
|
||
|---|---|
|
||
| `teaser` | Kachel auf der Startseite (gekürzt) |
|
||
| `summary` | Text auf `/marken` (zwei Absätze) |
|
||
| `highlights` | die drei Merkmale auf `/marken` |
|
||
| `description` | Einleitung der Detailseite |
|
||
| `services` | Leistungen der Detailseite |
|
||
|
||
- **Startseite:** Kacheln verlinken direkt auf die Detailseite, darunter der Button
|
||
„Alle Marken ansehen" → `/marken`.
|
||
- **Navigation:** „Marken" zeigt auf `/marken` statt auf den Anker `/#marken`; der Hero-Button
|
||
ebenfalls. Der Anker `#marken` bleibt für Direktsprünge erhalten.
|
||
- **Slug korrigiert:** Die Spec nennt `/marken/rotpunkt`, geseedet war `rotpunkt-kuechen`.
|
||
Angepasst, solange nichts live ist – später wäre das ein Redirect gewesen.
|
||
- **`/netzwerk` stillgelegt.** Der Inhalt geht im Abschnitt „Mehr als Marken: unser Netzwerk" auf
|
||
`/marken` auf. `/netzwerk`, `/interior`, `/partner` und `/service` leiten jetzt **direkt** auf
|
||
`/marken` – vorher liefen `/interior` und `/partner` über `/netzwerk`, also eine Redirect-Kette.
|
||
Die View bleibt als Archiv liegen.
|
||
- **WhatsApp-Button:** erscheint nur, wenn im CMS unter `global.contact.whatsapp` eine Nummer
|
||
hinterlegt ist (`whatsapp_link()`). Solange die Nummer nicht bestätigt ist, zeigt der CTA nur
|
||
„Termin anfragen" – kein Button auf eine erfundene Nummer.
|
||
|
||
**Tests:** `MarkenPageTest` (9), `InteriorPageTest` neu geschnitten (4), dazu zwei Fälle in
|
||
`Admin/Cms/CmsBrandsIndexTest` – darunter die Gegenprobe, dass eine im Admin angelegte Marke
|
||
mitsamt Text und Merkmalen auf `/marken` erscheint.
|
||
|
||
> **Notiz für spätere Reihenfolge-Tests:** `wire:snapshot` serialisiert die Komponentendaten als
|
||
> JSON ins Attribut und escaped Umlaute zu `\uXXXX`. Ein `strpos`-Vergleich auf dem rohen HTML
|
||
> misst dann den Snapshot statt des sichtbaren Textes. In `MarkenPageTest` werden die Snapshots
|
||
> vorher entfernt.
|
||
|
||
**Offen:** Logos, Stimmungsbilder und Galerien fehlen als Zulieferung – Kacheln und Detailseiten
|
||
zeigen so lange einen Platzhalter. Der WhatsApp-Button im CTA-Block kommt mit AP3, sobald die
|
||
Nummer bestätigt ist.
|
||
|
||
---
|
||
|
||
#### Nachtrag 2: Galerie je Marke – realisierte Projekte und Inspirationen getrennt
|
||
|
||
Aus Marcels Mail: „Der Bereich Referenzen ist mir wichtig … Entscheidend ist für mich, dass dieser
|
||
Bereich langfristig mitwachsen und von mir selbst gepflegt werden kann. Für den Start können wir
|
||
ergänzend mit hochwertigen Visualisierungen und KI-unterstützten Darstellungen arbeiten. Dabei
|
||
sollte allerdings klar zwischen tatsächlich realisierten Referenzen und Entwürfen beziehungsweise
|
||
Inspirationen unterschieden werden."
|
||
|
||
Umgesetzt als Galerie **auf der Detailseite jeder Kernmarke**, mit zwei Rubriken.
|
||
|
||
- **Datenform.** Das bestehende JSON-Feld `cms_brands.gallery` bekommt je Eintrag
|
||
`image`, `category` (`project` | `inspiration`) und `caption`. **Keine Migration nötig.**
|
||
- **Sicherheitsnetz gegen die schädlichere Verwechslung:** `CmsBrand::normalizeGallery()` stuft
|
||
jeden Eintrag ohne oder mit unbekannter Kategorie als **Inspiration** ein – nie als Projekt.
|
||
Ein Entwurf, der versehentlich als Referenz durchgeht, wäre der teurere Fehler. Die
|
||
Normalisierung greift beim Laden, beim Speichern und beim Ausspielen.
|
||
- **Frontend** (`brand-detail.blade.php`): Abschnitt „Referenzen und Inspirationen" mit Umschalter,
|
||
sobald beide Rubriken gefüllt sind; ist nur eine gefüllt, steht sie mit eigener Überschrift da.
|
||
Jede Kachel trägt ein sichtbares Label („Realisiertes Projekt" / „Visualisierung"), über den
|
||
Inspirationen zusätzlich der Satz „Diese Darstellungen sind Entwürfe und Visualisierungen –
|
||
keine ausgeführten Projekte." Lightbox mit Pfeiltasten und Esc, Muster übernommen aus
|
||
`immobilien-show.blade.php`.
|
||
- **Admin** (`brands-index.blade.php`): zwei getrennte Buttons „+ Projekt" und „+ Inspiration", je
|
||
Eintrag ein Auswahlfeld und eine Bildunterschrift, dazu ein Hinweis, was in welche Rubrik gehört.
|
||
Die Kategorie wird beim Anlegen entschieden, nicht per stillem Vorgabewert.
|
||
- **Abgrenzung zu AP5:** AP5 bleibt die Rubrik-Seite „Referenzen" mit dem zweiten Display. Die
|
||
markenbezogene Galerie hier ist die pflegbare Grundlage dafür und ersetzt AP5 nicht.
|
||
|
||
**Tests:** 5 Fälle in `BrandPageTest` (keine Galerie → kein Abschnitt; beide Rubriken beschriftet;
|
||
kein Umschalter bei nur einer Rubrik; Eintrag ohne Kategorie erscheint als Visualisierung; Hinweis
|
||
sichtbar), 5 in `Cms/CmsBrandTest` (Normalisierung, Gruppierung), 4 in
|
||
`Admin/Cms/CmsBrandsIndexTest` (Anlegen je Rubrik, Speichern, unbekannte Kategorie, Löschen).
|
||
|
||
**Offen:** Bildmaterial. Marcel setzt Projektfotos und Visualisierungen selbst ein.
|
||
|
||
---
|
||
|
||
### AP3 · Terminanfrage-Widget + WhatsApp — ✅ umgesetzt
|
||
|
||
**Korrektur gegenüber Revision 1:** kein Inline-Abschnitt, sondern ein **schwebendes Element
|
||
unten rechts auf allen Seiten** → gehört ins Layout `web-master.blade.php`, nicht in `home.blade.php`.
|
||
|
||
- Aufsetzen auf `Acme\ContactForm\Livewire\ContactForm` per `customFields` – Honeypot,
|
||
Rate-Limit und `SpamDetector` kommen damit geschenkt.
|
||
- Felder: Name*, E-Mail*, Telefon, Anliegen/Marke (Auswahl), Wunschtermin, Nachricht.
|
||
- **Markenauswahl speist sich aus `CmsBrand`** → Abhängigkeit zu AP2 (Reihenfolge einhalten),
|
||
plus feste Einträge „Projektausstattung" und „Sonstiges".
|
||
- WhatsApp-Button daneben, Nummer als CMS-Wert (`global.contact.whatsapp`), Link `https://wa.me/<nummer>`.
|
||
- Cookie-Consent beachten (`packages/acme/CookieConsent`).
|
||
|
||
**Tests:** `AppointmentWidgetTest` (17 Fälle: Einbindung auf allen Seiten, Markenauswahl aus
|
||
`CmsBrand`, Validierung inkl. Wunschtermin in der Vergangenheit, Übergabe an den
|
||
`ContactFormService`, Honeypot, WhatsApp sichtbar/unsichtbar); `ContactFormTest` bleibt grün.
|
||
|
||
#### Umsetzungsnotizen
|
||
|
||
- **Abweichung vom Plan:** nicht auf `Acme\ContactForm\Livewire\ContactForm` per `customFields`
|
||
aufgesetzt. Dessen mitgelieferte View bringt ein eigenes, blaues Layout mit, das nicht zum
|
||
Auftritt passt. Stattdessen eine eigene Komponente wie `ContactForm` und `ImmobilienContactForm`
|
||
der Seite, die `ContactFormService` und `SpamDetector` aus dem Paket nutzt – Honeypot,
|
||
Rate-Limit und Spam-Erkennung sind damit trotzdem drin.
|
||
- **Platzierung:** `web-master.blade.php`, unten rechts, `z-40`. Der Cookie-Button des
|
||
Consent-Managers sitzt unten links (ebenfalls `z-40`), sein Dialog auf `z-50` – die Einwilligung
|
||
bleibt also immer erreichbar und wird nie verdeckt.
|
||
- **Kein eigener Consent nötig:** Das Widget setzt nichts im Browser, der WhatsApp-Link ist ein
|
||
ausgehender Link ohne Einbettung.
|
||
- Die `[x-cloak]`-Regel liegt jetzt einmal zentral im Layout – die Seiten brachten sie bisher nur
|
||
teilweise selbst mit, das Widget braucht sie überall.
|
||
- Felder: Name*, E-Mail*, Telefon, Anliegen (Auswahl), Wunschtermin, Nachricht, Einwilligung*.
|
||
Der Wunschtermin ist auf heute oder später begrenzt, im Browser über `min` und serverseitig
|
||
über `after_or_equal:today`.
|
||
- Betreff der Mail: `Terminanfrage B2in Interior: <Anliegen>`, Log-Kontext `appointment-widget` –
|
||
so lassen sich Widget-Anfragen von den übrigen Formularen unterscheiden. Die Seite, von der die
|
||
Anfrage kam, steht als `source` in der Mail.
|
||
- **WhatsApp** erscheint weiterhin nur, wenn unter `global.contact.whatsapp` eine Nummer im CMS
|
||
steht. Ohne Nummer zeigt das Widget allein den Termin-Button.
|
||
|
||
#### WhatsApp: was technisch geht und was nicht
|
||
|
||
Eine echte WhatsApp-Anbindung (Nachrichten empfangen, im CMS beantworten, Verlauf speichern)
|
||
setzt die WhatsApp Business Platform voraus: Meta-Verifizierung des Unternehmens, ein Anbieter
|
||
für den API-Zugang, laufende Kosten je Konversation. Das ist nicht Teil dieses Auftrags.
|
||
|
||
Umgesetzt ist die dafür übliche Alternative, ein **Klick-zum-Chat-Link** (`wa.me`):
|
||
|
||
- Der Button sitzt im Terminanfrage-Panel unter dem Absenden-Button.
|
||
- Auf dem Handy öffnet die installierte WhatsApp-App, am Rechner WhatsApp Web bzw. die
|
||
Desktop-App. Ist WhatsApp nirgends vorhanden, landet man auf der Hinweisseite von `wa.me`.
|
||
- Der Nachrichtentext ist **vorbereitet** und wird im Browser aus dem zusammengesetzt, was im
|
||
Formular schon steht (Anliegen, Wunschtermin, Name). Der Einstiegssatz ist im CMS pflegbar
|
||
(`global.appointment_widget.whatsapp_text`).
|
||
- **Abgeschickt wird die Nachricht vom Besucher selbst** – das steht auch so unter dem Button.
|
||
|
||
Was das bedeutet, bewusst festgehalten:
|
||
|
||
| | |
|
||
|---|---|
|
||
| Wo landet die Nachricht | in Marcels WhatsApp, nicht im CMS und nicht per Mail |
|
||
| Was sehen wir davon | nichts – kein Eintrag, keine Statistik, kein Spamschutz |
|
||
| Voraussetzung | eine Mobilnummer, die WhatsApp empfangen kann (sinnvoll: WhatsApp Business) |
|
||
| Datenschutz | ausgehender Link zu Meta. In die Datenschutzerklärung gehört ein Absatz dazu; ein Consent-Banner braucht es nicht, weil nichts eingebettet wird und nichts gesetzt wird |
|
||
|
||
Wer eine Anfrage im System dokumentiert haben will, nutzt weiterhin das Formular – der
|
||
WhatsApp-Weg ist die schnelle, aber unprotokollierte Abkürzung.
|
||
|
||
### Nachtrag 3 · Bestandsinhalte auf den Interior-Auftritt umgestellt ✅
|
||
|
||
Nach der Sichtung: Drei verlinkte Seiten erzählten noch die Dubai-/Plattform-Geschichte.
|
||
`/immobilien` bleibt bewusst unverändert – die Seite ist der „Außerdem"-Bereich.
|
||
|
||
**`/faq`** – die beiden Rubriken „Fokus: Immobilien-Investoren (B2C)" und „Fokus: B2B-Partner"
|
||
sind ersetzt durch **„Für Ihr Zuhause"** und **„Für Projekte und Objekte"** (je vier Fragen:
|
||
Einstieg mit einem einzelnen Möbelstück, Kosten der Maßanfertigung, Montage, Showroom –
|
||
bzw. Projektgröße, Termintreue, Architekten, Netzwerk). Von den allgemeinen Fragen waren zwei
|
||
noch Dubai-lastig, die sind jetzt Beratungsablauf und Verlässlichkeit. Die englische Fassung war
|
||
noch komplett auf dem alten Stand und ist mitgezogen.
|
||
|
||
**`/about`** – das Mission-Zitat sprach von „digitalen Werkzeugen" und „Brücken zwischen Märkten".
|
||
Neu: wenige ausgewählte Hersteller, Fachbetriebe aus der Region, ein Ansprechpartner. Die sechs
|
||
Werte waren Plattform-Vokabular (Innovation, Konnektivität, Design-Exzellenz) und heißen jetzt
|
||
Beratung statt Verkauf, Maßarbeit, Ausgewählte Marken, Regional verwurzelt, Ein Ansprechpartner,
|
||
Verlässlichkeit. In der Zeitleiste sind „Die Idee", „Das Fundament" und „Die Vision" umgeschrieben.
|
||
|
||
**`/contact`** – die Betreffliste beginnt jetzt mit Beratungstermin, Maßanfertigung und
|
||
Küchenplanung; „Internationale Immobilien" rutscht nach hinten, bleibt aber erhalten.
|
||
|
||
**`/magazin`** – zwei neue Beiträge, die **an erster Stelle** stehen:
|
||
`massanfertigung-warum-der-millimeter-zaehlt` und `kueche-planen-vom-wunsch-zum-grundriss`.
|
||
Die vier Dubai-Beiträge bleiben, sie gehören zum Immobilienbereich.
|
||
|
||
> ⚠️ Die beiden Beiträge sind **Platzhalter**. Bewusst ohne Referenzen, Zahlen oder Namen
|
||
> geschrieben, damit nichts behauptet wird, was nicht belegt ist – vor dem Livegang von Marcel
|
||
> gegenlesen lassen. Als Bilder dienen vorhandene Motive aus dem Altbestand.
|
||
|
||
**Zwei technische Punkte dabei:**
|
||
|
||
- Neue Lang-Artikel bringen ihren Slug jetzt selbst mit (`'slug' => …`, aufgelöst über
|
||
`CmsArticle::slugForLangArticle()`). `LEGACY_ID_TO_SLUG` bleibt damit das, was der Name sagt:
|
||
die Karte für die alten `/magazin/{id}`-URLs. `/magazin/6` ist korrekt ein 404, weil es diese
|
||
URL nie gab.
|
||
- `CmsArticleSeeder` sortiert nicht mehr per `ksort`. Die Reihenfolge in der Lang-Datei bestimmt
|
||
jetzt die Reihenfolge im Magazin – im CMS über `order`, im Lang-Fallback über die
|
||
Array-Reihenfolge. Vorher konnten beide Wege auseinanderlaufen.
|
||
|
||
**Tests:** vier Fälle in `MagazinPageTest` (Reihenfolge, beide Slugs, kein erfundener Legacy-Link,
|
||
Slug-Auflösung), drei in `LiveSiteReviewTest` (FAQ ohne Dubai mit neuen Rubriken, About mit den
|
||
neuen Werten, Kontakt mit den neuen Betreffen).
|
||
|
||
**Nachkontrolle:** Gegen die Live-Seiten geprüft, nicht nur gegen die Sprachdatei – dabei fiel in
|
||
der FAQ eine dritte Frage auf, die noch vom „Local for Local"-Netzwerk sprach. Ebenfalls korrigiert.
|
||
|
||
**Noch offen auf diesen Seiten:** eigene Beitragsbilder für die zwei neuen Artikel; die vier
|
||
Dubai-Beiträge bleiben inhaltlich unverändert stehen.
|
||
|
||
---
|
||
|
||
### Nachtrag 4 · Markenseiten Rotpunkt und Febrü aus der Zulieferung ✅
|
||
|
||
**Grundlage:** zunächst `Rotpunkt_Kuechen_Webseitentext_B2in_FINAL.pdf` und
|
||
`Februe_Webseitentext_B2in_FINAL.pdf` (Stand 31.08.2026, im selben Ordner). Beide enthalten neben
|
||
dem Seitentext einen Abschnitt „UMSETZUNGSHINWEIS FÜR KEVIN – WEBSTRUKTUR UND CTA“.
|
||
|
||
> Die als Aufgabenliste angekündigte Datei `umsetzung-03-09-2026.md` war zu diesem Zeitpunkt leer
|
||
> (0 Byte). Sie wurde nachgereicht – **die Auswertung steht in Nachtrag 5**, der auch die
|
||
> korrigierten Textfassungen (`*_FINAL.md`) einarbeitet. Für den Textstand gilt Nachtrag 5.
|
||
|
||
**Was die Zulieferung verlangt:**
|
||
|
||
1. Der normale Seitentext bleibt direkt sichtbar.
|
||
2. Die mit „AUFKLAPPBARER DETAILBEREICH“ gekennzeichneten Vertiefungen werden aufklappbar.
|
||
3. **Kein zweiter CTA-Button.** Stattdessen bekommt das vorhandene schwebende
|
||
Terminanfrage-Widget auf der jeweiligen Markenseite eine kontextbezogene Beschriftung.
|
||
4. Das Widget bleibt beim Scrollen sichtbar und darf auf dem Smartphone nichts verdecken.
|
||
5. Die internen Quellenhinweise am Ende der PDFs werden **nicht** veröffentlicht.
|
||
|
||
#### Umsetzung
|
||
|
||
**Datenstruktur.** `description` (Einleitung) und `services` (Kacheln) reichten für diese Texte
|
||
nicht aus. Neu in `cms_brands`:
|
||
|
||
| Feld | Inhalt |
|
||
|---|---|
|
||
| `sections` | Abschnitte der Seite: Titel, Absätze, optional Schlusszeile, Zitat und Vertiefung |
|
||
| `widget_label` | Beschriftung des Terminanfrage-Widgets auf dieser Markenseite |
|
||
| `cta_title` / `cta_text` | Abschlussblock der Seite |
|
||
|
||
`sections` ist – wie `services`, `highlights` und `gallery` – bewusst **nicht** übersetzbar; die
|
||
Texte liegen nur auf Deutsch vor. Die drei Textfelder folgen den übrigen Textfeldern und sind
|
||
übersetzbar. `CmsBrand::normalizeSections()` bringt jeden Eintrag in eine feste Form und nimmt
|
||
Absätze wahlweise als Liste oder als Textblock entgegen (Leerzeile trennt) – dadurch lässt sich im
|
||
Admin einfach in ein Textfeld schreiben.
|
||
|
||
**Darstellung.** Die Abschnitte stehen zwischen Einleitung und Leistungen. Vertiefungen sind
|
||
aufklappbar, mit `aria-expanded` und `aria-controls`. Bewusst `x-transition` statt `x-collapse`:
|
||
Das Collapse-Plugin ist in diesem Projekt nicht registriert, die Bewegung entspricht jetzt dem
|
||
FAQ-Akkordeon. Zitate stehen abgesetzt mit Nennung des Sprechers, Schlusszeilen hervorgehoben.
|
||
|
||
**Widget-Beschriftung.** Das Widget steckt im Layout, nicht in der Seite – es liest den Kontext
|
||
deshalb aus der Route: Auf `marken.show` greift `widget_label` der Marke, sonst die allgemeine
|
||
Beschriftung. Ein Test prüft gegen, dass dabei **kein zweiter Button** entsteht.
|
||
|
||
**Platz auf dem Smartphone.** Der Footer bekommt unten zusätzlichen Abstand (`pb-28 sm:pb-16`),
|
||
und der Button bricht lange Beschriftungen um, statt über den Bildschirmrand zu laufen – „Persönliche
|
||
Arbeitsplatzberatung vereinbaren“ ist deutlich länger als das vorherige „Termin anfragen“.
|
||
|
||
**Pflegbarkeit.** Die Abschnitte sind vollständig im Admin pflegbar: hinzufügen, löschen, per Pfeil
|
||
sortieren, je Abschnitt Überschrift, Text, Schlusszeile, Zitat und Vertiefung. Dazu die drei neuen
|
||
Felder für Abschluss und Widget-Beschriftung.
|
||
|
||
**Einspielen.** `BrandPageTextSeeder` schreibt die Texte. Er fasst **nur** `tagline`,
|
||
`description`, `sections`, `widget_label`, `cta_title` und `cta_text` an – Bilder, Galerie,
|
||
Leistungen und Reihenfolge bleiben unangetastet. Ein Test prüft genau das.
|
||
|
||
**Nebenbei korrigiert:** Febrüs Claim hieß „Arbeiten, wo man gerne ist.“, die Zulieferung schreibt
|
||
„Arbeiten, wo man gerne **bleibt**.“
|
||
|
||
**Tests:** `BrandPageSectionsTest` (17 Fälle: Abschnitte beider Marken, Anzahl der aufklappbaren
|
||
Bereiche, Zitat, Schlusszeilen, keine Quellenhinweise im Ausgabe-HTML, markenspezifischer
|
||
Abschlussblock mit Rückfall auf den allgemeinen, Widget-Beschriftung je Marke, kein zweiter Button,
|
||
Normalisierung, Redaktionsschutz des Seeders) und vier neue Fälle in `Admin/Cms/CmsBrandsIndexTest`.
|
||
|
||
> ⚠️ **Vor der Veröffentlichung freigeben lassen.** Die PDFs halten fest: Aussagen nur im belegten
|
||
> Umfang veröffentlichen, Herstellerfreigabe einholen, und die Rotpunkt-Aussage zur jährlich
|
||
> erhaltenen **Waldfläche von ungefähr 50 Fußballfeldern** nur mit ausdrücklicher Bestätigung
|
||
> verwenden. Sie steht als eigener Absatz in der Vertiefung „Zahlen, Zertifizierungen und
|
||
> Raumklima“ und lässt sich dort einzeln entfernen. Als Punkt in Abschnitt 8 aufgenommen.
|
||
|
||
**Offen:** CABINET hat noch keinen ausführlichen Seitentext – die Seite läuft weiter über
|
||
Einleitung und Leistungskacheln. Bilder fehlen weiterhin für alle drei Marken.
|
||
|
||
---
|
||
|
||
### AP4 · Display-Spiegelung auf der Website — ✅ umgesetzt
|
||
|
||
**Korrektur gegenüber Revision 1:** Revision 1 empfahl, die Slides nativ zu rendern. Bei 3 Std.
|
||
ist das nicht zu halten, und die Umsetzungsliste schreibt „nutzt die vorhandene Display-/Player-API
|
||
als Datenquelle". → **Einbettung des vorhandenen Players im 9:16-Container.**
|
||
|
||
- Sektion `Sections/DisplayFeed` mit `aspect-ratio: 9/16`, darin der Player.
|
||
- **Vorher zu klären:** Die `/preview/…`-Routen sind token- bzw. modulbasiert und für den internen
|
||
Gebrauch gedacht. Für die öffentliche Domain braucht es eine schmale, read-only Route
|
||
(z. B. `/embed/display/{display}`), die keine Preview-Tokens nach außen gibt.
|
||
- Keine doppelte Pflege: Marcel pflegt weiterhin nur im Display-CMS.
|
||
|
||
#### Umsetzung
|
||
|
||
- **Route `GET /embed/display/{display}`** (`DisplayEmbedController`), bewusst getrennt von den
|
||
Preview-Routen: Die arbeiten mit `preview_token` und zeigen den **Entwurf**. Nach außen darf
|
||
weder ein Token noch ein unveröffentlichter Stand gelangen. Die Embed-Route kennt nur die
|
||
numerische ID, liefert 404 bei inaktivem Display, bei reinem Entwurf und bei leerer Playlist,
|
||
und setzt `X-Robots-Tag: noindex`.
|
||
- **Kein Proxy, keine CORS-Frage:** Der Player liest die ID aus dem Pfad (`/display/{id}` steckt in
|
||
`/embed/display/{id}`) und holt seine Konfiguration über die bereits öffentliche Route
|
||
`/api/display/{display}/config` – dieselbe Quelle wie das physische Display. Da die API-Routen
|
||
für alle Domains registriert sind, läuft der Abruf gleichursprünglich über `b2in.test`.
|
||
Möglich wurde das durch **B13**: Vorher standen absolute `b2in.test`-URLs in den Playlists.
|
||
- **Sektion `Sections/DisplayFeed`** im 9:16-Rahmen. Welches Display gezeigt wird, steht im CMS
|
||
(`referenzen.display_feed.display_id`); ohne Eintrag greift das erste aktive Display mit
|
||
veröffentlichter Playlist. Gibt es keins, rendert die Sektion **nichts** – lieber keine Sektion
|
||
als ein Rahmen mit ewigem Ladebalken. Auch die Texte bleiben dann leer, sonst stünden sie
|
||
im Livewire-Snapshot der Seite.
|
||
- Eingebunden auf der Startseite (an der dafür vorgesehenen Stelle) und auf `/referenzen`.
|
||
|
||
**Tests:** `DisplayWebFeedTest` (10 Fälle: Embed liefert die Datei, kein Token im Ausgabe-Inhalt,
|
||
404 bei inaktiv/Entwurf/leer/unbekannt, Einbindung auf der Startseite, CMS-Auswahl und Fallback).
|
||
|
||
### AP5 · Rubrik-Seite „Referenzen" — ✅ umgesetzt (Pflege seit Nachtrag 13 als eigenes Modul)
|
||
|
||
**Korrektur gegenüber Revision 1:** Revision 1 schlug einen neuen `DisplayVersionType`-Case vor.
|
||
Die Umsetzungsliste sagt „zweites, separates **Display** im Display-CMS" – das ist ein weiterer
|
||
`Display`-Datensatz und braucht **keine Enum-Änderung**. Damit entfallen die Folgeänderungen an
|
||
`DisplayPlaylistConfigBuilder::moduleData()`, `DisplayModuleSettings` und den
|
||
`version-editor-*`-Partials. Deutlich risikoärmer und billiger.
|
||
|
||
- Zweites `Display` anlegen, Route `/referenzen`, View + Sektion, Aufnahme in die Navigation.
|
||
- Startseiten-Teaser „Aktuelles aus unseren Showrooms" mit Button „Alle Referenzen ansehen →".
|
||
- 2–3 Platzhalter-Einträge.
|
||
- YouTube-Verlinkungen mit Consent-Gate.
|
||
- Inhaltliche Regel dokumentieren: unter „Referenzen" nur realisierte Projekte; Visualisierungen
|
||
und Entwürfe gehören in die Kernmarken-Detailseiten.
|
||
- **Bereits vorhanden:** die markenbezogene Galerie mit den Rubriken „Realisierte Projekte" und
|
||
„Inspirationen und Entwürfe" (siehe Nachtrag 2 zu AP2). AP5 baut darauf auf, statt eine zweite
|
||
Pflegestelle für dieselben Bilder zu schaffen.
|
||
|
||
#### Umsetzung
|
||
|
||
- Seite `/referenzen`: Seitenkopf → realisierte Projekte → Showroom-Display → Abschluss-CTA.
|
||
Navigationspunkt zwischen „Marken" und „Magazin".
|
||
- **Kein zweites Display nötig, keine zweite Pflegestelle:** Die Projekte kommen aus den
|
||
Markengalerien (AP2) und werden über alle Marken hinweg gesammelt. Es erscheinen ausschließlich
|
||
Einträge der Rubrik **„Realisiertes Projekt"** – Visualisierungen bleiben draußen, damit
|
||
„Referenzen" hält, was das Wort verspricht. Jede Kachel verlinkt zurück auf ihre Markenseite.
|
||
- **Ehrlicher Leerzustand:** Solange keine Projekte gepflegt sind, steht dort ein Satz dazu und ein
|
||
Terminlink – keine erfundene Referenz und keine leere Fläche.
|
||
- Der Seitenkopf ist jetzt eine wiederverwendbare Sektion (`PageHero` mit `section` und
|
||
`breadcrumb`), vorher war er auf `/marken` festgelegt.
|
||
|
||
**Tests:** `ReferenzenPageTest` (6 Fälle: Seite lädt mit eigenem Titel, Navigationspunkt,
|
||
Projekte aus allen Marken, Visualisierungen bleiben draußen, Rückverlinkung, Leerzustand).
|
||
|
||
### AP6 · Engagement / Sponsoring — ✅ umgesetzt (im Rahmen von AP1)
|
||
|
||
Schlanke Sektion „Regional verbunden" nach der Marcel-Sektion: ein Einleitungssatz plus drei
|
||
Logos in ruhiger Reihe (Graustufen/gedeckt).
|
||
|
||
Logos liegen bereits unter `dev/2026-08-28/sponsoren-logos/` – **7 Dateien für 3 Vereine**
|
||
(Arminia, TCBWH, TCH in mehreren Varianten und Formaten). Vor der Umsetzung je Verein **eine**
|
||
Datei auswählen, nach `public/img/assets/` bzw. in die Medienbibliothek übernehmen und
|
||
vereinheitlichen (gleiche Höhe, transparenter Hintergrund – die `.jpg`-Varianten haben keinen).
|
||
Setzt **B9** voraus, damit die Logos per Picker pflegbar sind.
|
||
|
||
---
|
||
|
||
---
|
||
|
||
### Nachtrag 5 · Abstimmungsrunde 03.09.2026 ✅
|
||
|
||
**Grundlage:** `dev/2026-08-28/umsetzung-03-09-2026.md`. Die Datei war beim ersten Zugriff leer
|
||
und wurde nachgereicht. Dazu kamen die korrigierten Textfassungen als Markdown:
|
||
`Rotpunkt_Webseitentext_FINAL.md` und `Februe_Webseitentext_FINAL.md`. **Sie lösen die PDFs vom
|
||
31.08. ab** – die PDFs bleiben nur als Beleg im Ordner liegen.
|
||
|
||
Vier Punkte, alle umgesetzt:
|
||
|
||
| # | Punkt | Stand |
|
||
|---|---|---|
|
||
| 1 | Markenseiten umfangreicher: Rotpunkt und Febrü korrigiert, CABINET neu | ✅ |
|
||
| 2 | „BEISPIEL"-Kennzeichnung bei Visualisierungen entfernen | ✅ |
|
||
| 3 | Hinweis zu Visualisierungen eleganter formulieren | ✅ |
|
||
| 4 | Abschluss-CTA hochwertiger | ✅ |
|
||
|
||
#### 1a · Korrigierte Fassungen Rotpunkt und Febrü
|
||
|
||
Die beiden Markdown-Dateien führen ihre Änderungen gegenüber dem 31.08. selbst auf. Übernommen:
|
||
|
||
- **Rotpunkt:** „Nachhaltigkeit mit konkreter Substanz" und „Greenline hält dem Vergleich stand"
|
||
sind **zusammengeführt**; der doppelte Satz „Nachhaltigkeit braucht keine großen Versprechen…"
|
||
steht nur noch einmal. Rotpunkt hat damit **8 statt 9 Abschnitte**, weiterhin 4 Vertiefungen.
|
||
- **Febrü:** Der erklärende Satz zum Blauen Engel („Die Aussage bezieht sich ausdrücklich auf die
|
||
offiziell gelisteten Produktgruppen…") ist aus dem Kundentext **entfernt** – der Produktbezug
|
||
steckt jetzt im Satz selbst („Ausgewählte Febrü-Tischsysteme und Stauraummöbel"). Ein Test
|
||
hält diese Formulierung fest, damit sie beim Redigieren nicht pauschal wird.
|
||
- Die Schlusszeile „Nachhaltig ist nicht das Möbelstück mit dem längsten Werbetext…" steht laut
|
||
korrigierter Fassung **innerhalb** der Vertiefung, nicht als Abschnitts-Claim.
|
||
|
||
Ein Prüfskript hat jeden veröffentlichten Satz des Seeders gegen die Markdown-Datei gehalten:
|
||
0 Abweichungen, alle Überschriften der Vorlage vorhanden. Einzige bewusste Abweichung sind
|
||
typografische Anführungszeichen („…“ statt „…").
|
||
|
||
#### 1b · CABINET nach demselben Muster
|
||
|
||
Für CABINET **lag keine Zulieferung vor**. Die Seite ist nach dem Vorbild der beiden abgestimmten
|
||
Texte von uns verfasst: Einleitung mit Claim, 8 Abschnitte, 3 davon mit Vertiefung, eigener
|
||
Abschlussblock „Ihr Raum. Persönlich geplant." und die Widget-Beschriftung „Persönliche
|
||
Schrankplanung vereinbaren".
|
||
|
||
> ⚠️ **Bewusste Zurückhaltung:** Der Text beschreibt ausschließlich die eigene Arbeitsweise –
|
||
> Aufmaß, Planung, Innenausstattung, Fronten, Montage, Schnittstelle zur Tischlerei. Er enthält
|
||
> **keine Zahlen, Zertifizierungen oder Herstelleraussagen**, weil es dafür keine Quelle gibt.
|
||
> Die Rotpunkt- und Febrü-Seiten stützen solche Aussagen auf die Quellenhinweise der Zulieferung;
|
||
> für CABINET wäre das erfunden. **Der Text braucht Marcels Freigabe** (Punkt in Abschnitt 8).
|
||
|
||
**Nebenbei korrigiert:** Febrüs Claim stand in `CmsBrandSeeder` und `b2in.php` weiter als
|
||
„Arbeiten, wo man gerne ist." – die Zulieferung schreibt „…gerne **bleibt**."
|
||
|
||
#### 2 · „BEISPIEL"-Kennzeichnung entfernt
|
||
|
||
Die Demobilder trugen den Vermerk „BEISPIEL – " in der Bildunterschrift, damit ein Stockmotiv
|
||
nicht versehentlich als echte Referenz durchgeht. Der Vermerk ist entfallen.
|
||
|
||
Zwei Stellen waren nötig, weil die Bilder auf Vorschau und Live **bereits in der Datenbank
|
||
stehen**:
|
||
|
||
- `DemoBrandGallerySeeder` – Bildunterschriften ohne Vermerk (für frische Installationen).
|
||
- `BrandGalleryCaptionNormalizerSeeder` **(neu)** – entfernt den Vermerk in vorhandenen Daten.
|
||
Fasst **ausschließlich den Text** an; Bild, Kategorie und Reihenfolge bleiben. Mehrfaches
|
||
Ausführen ist unbedenklich.
|
||
|
||
> ⚠️ Die Unterscheidung hängt damit allein an der **Kategorie** (Badge „Realisiertes Projekt" /
|
||
> „Visualisierung"). Die Demobilder der Kategorie `project` sind Stockmotive und KI-Renderings –
|
||
> sie behaupten jetzt ohne den Vermerk, echte Referenzen zu sein. **Vor dem Livegang ersetzen
|
||
> oder auf „Inspiration" umstellen** (Punkt in Abschnitt 8).
|
||
|
||
#### 3 · Hinweis zu Visualisierungen
|
||
|
||
| Wo | Vorher | Jetzt |
|
||
|---|---|---|
|
||
| Markengalerie, Rubrik Inspirationen | „Diese Darstellungen sind Entwürfe und Visualisierungen – keine ausgeführten Projekte." | „Entwürfe und Visualisierungen. Sie zeigen gestalterische Möglichkeiten, noch bevor das erste Möbel steht." |
|
||
| Markengalerie, Einleitung | „…und Visualisierungen, die zeigen, was möglich ist." | „…und Visualisierungen, die zeigen, was in einem Raum möglich ist." |
|
||
| `/referenzen`, Seitenkopf | „…keine Entwürfe und keine Visualisierungen." | „Hier zeigen wir ausschließlich Arbeiten, die wir tatsächlich ausgeführt haben." |
|
||
| `/referenzen`, Projektliste | „…finden Sie bewusst getrennt davon auf den Markenseiten." | „…zeigen wir bewusst getrennt davon – auf den Markenseiten." |
|
||
|
||
Die Trennung bleibt inhaltlich unverändert, sie wird nur nicht mehr über eine Verneinung
|
||
transportiert. Der Badge am Bild („Visualisierung") trägt die Unterscheidung ohnehin.
|
||
|
||
#### 4 · Abschluss-CTA
|
||
|
||
Der Block war eine einfarbige Fläche mit Überschrift, Text, Button und einem unterstrichenen
|
||
Textlink. Neu:
|
||
|
||
- Eine schmale Linie über der Überschrift setzt den Abschluss ab.
|
||
- Hauptbutton weiß auf Markenfarbe, mit Pfeil, der beim Hovern mitgeht.
|
||
- Die Herstellerseite ist jetzt ein gleichwertiger Outline-Button statt eines Textlinks.
|
||
- Der Showroom steht als kleine Zeile mit Pin-Symbol darunter.
|
||
|
||
**Nachgebessert (dritte Rückmeldung):** Nach dem Build stand der Abschluss hellgrau mit weißer
|
||
Schrift da. Ursache: `.variante-glass-flow section` in `shared-styles.css` färbt **jede** Sektion
|
||
in diesem Wrapper hell ein und ist mit `(0,1,1)` spezifischer als `.cta-band` mit `(0,1,0)`. Für
|
||
`.bg-secondary` und `.bg-accent` gibt es dort längst Ausnahmen – die neue Klasse brauchte
|
||
dieselbe. `/marken/{slug}` hängt in genau diesem Wrapper, deshalb fiel es erst dort auf. Der
|
||
Verlauf steht jetzt in `--cta-band-gradient` und wird von beiden Regeln benutzt, damit er nicht
|
||
doppelt gepflegt werden muss. Ein Test hält die Ausnahme fest.
|
||
|
||
**Nachgebessert (zweite Rückmeldung):** Der erste Versuch legte zwei weiche Kreise (`blur-3xl`)
|
||
über das Hellblau – die wirkten als sichtbare Flecken, besonders der dunkle rechts unten. Ersetzt
|
||
durch einen durchgehenden Verlauf über die volle Breite: `.cta-band` in `shared-styles.css`, von
|
||
Anthrazit (`--primary-dark`) diagonal in das Dynamic Blue (`--secondary-dark`). Die Tiefe kommt
|
||
aus dem Verlauf selbst, die Kontur aus zwei Haarlinien – eine oben über die Breite, eine als
|
||
Auftakt über der Überschrift, beide zu den Seiten auslaufend. Buttons und Fußzeile dabei
|
||
zurückhaltender: dünnerer Rahmen, weicherer Schatten.
|
||
|
||
> Der Verlauf liegt bewusst als CSS-Klasse vor und nicht als Utility-Kette im Blade: er arbeitet
|
||
> mit den Theme-Variablen und bleibt so über alle Themes hinweg stimmig.
|
||
|
||
Die Textinhalte kommen unverändert aus dem CMS (`cta_title` / `cta_text`) – Punkt 4 der Liste war
|
||
inhaltlich bereits durch die neuen Texte erledigt („Ihre Küche. Persönlich geplant.").
|
||
|
||
#### 5 · Akkordeons weicher (Nachreichung aus derselben Runde)
|
||
|
||
Rückmeldung: Die Klappelemente springen zu schnell auf und zu, der Hover-Effekt ist zu stark.
|
||
|
||
Ursache war `x-show` mit einer Opacity-Bewegung: Das Element nimmt sofort seine volle Höhe ein
|
||
und blendet nur den Inhalt ein – es sieht aus wie ein Sprung. Ersetzt durch eine Animation von
|
||
`grid-template-rows: 0fr → 1fr` über 500 ms mit `cubic-bezier(0.33, 1, 0.68, 1)`, die die
|
||
tatsächliche Höhe bewegt. Das Alpine-Collapse-Plugin ist in diesem Projekt nicht registriert;
|
||
diese Lösung kommt ohne neue Abhängigkeit aus.
|
||
|
||
- Der zugeklappte Zustand steht **auch statisch im `class`-Attribut**, damit vor dem Start von
|
||
Alpine nichts aufgeklappt aufblitzt. Die Objekt-Schreibweise von `x-bind:class` entfernt ihn
|
||
beim Öffnen wieder.
|
||
- `aria-hidden` hängt am Zustand, weil der Inhalt jetzt dauerhaft im DOM steht.
|
||
- **Hover:** Die Flächenaufhellung (`hover:bg-muted/30`) ist raus. Geblieben ist ein feiner
|
||
Farbwechsel der Überschrift auf die Sekundärfarbe. Im FAQ entfällt zusätzlich der
|
||
Hintergrundwechsel am Icon-Kreis.
|
||
- Der Pfeil dreht in derselben Dauer und Kurve wie das Aufklappen, damit beides zusammenläuft.
|
||
|
||
Betrifft **beide** Akkordeons – die Vertiefungen auf den Markenseiten und das FAQ; sie hatten
|
||
dasselbe Verhalten.
|
||
|
||
#### 6 · Markenlogos (Zulieferung 03.09.2026)
|
||
|
||
Grundlage: `dev/2026-08-28/markenlogos/` – CABINET und Rotpunkt als SVG, Febrü als PNG. Sie
|
||
liegen jetzt unter `public/img/assets/marken/` und hängen als `logo` an der jeweiligen Marke.
|
||
|
||
| Wo | Vorher | Jetzt |
|
||
|---|---|---|
|
||
| Kopf der Markenseite | Schriftzug als `<h1>` | Logo **anstelle** des Schriftzugs, im `<h1>` |
|
||
| Kachel auf der Startseite | ohne Logo | Logo über Name und Claim |
|
||
| Block auf `/marken` | ohne Logo | Logo über Name und Claim |
|
||
| „Weitere Marken" am Seitenfuß | ohne Logo | Logo über Name und Claim |
|
||
|
||
Das Logo sitzt **im** `<h1>`, nicht daneben: So bleibt die Seitenüberschrift erhalten, den Text
|
||
liefert das `alt`-Attribut. Fehlt ein Logo, erscheint weiterhin der Schriftzug – ein Test hält
|
||
beide Wege fest.
|
||
|
||
**Feste Box statt fester Höhe.** Die drei Logos haben sehr unterschiedliche Seitenverhältnisse
|
||
(Febrü 2,3:1, Rotpunkt 1,2:1). Mit einer reinen Höhenangabe hätte Febrü doppelt so breit gewirkt
|
||
wie Rotpunkt. Jedes Logo bekommt deshalb Höhe **und** Maximalbreite plus `object-contain` – die
|
||
Konvention aus der Sponsoring-Sektion.
|
||
|
||
**Alle drei Dateien auf ihren Inhalt beschnitten.** Jede Zulieferung brachte leeren Rand mit,
|
||
und zwar unterschiedlich viel – dadurch wirkten die Logos trotz gleicher Box unterschiedlich
|
||
groß:
|
||
|
||
| Logo | genutzte Höhe der Datei | nach dem Beschnitt |
|
||
|---|---|---|
|
||
| CABINET | **29 %** | 98 % |
|
||
| Rotpunkt | 70 % | 98 % |
|
||
| Febrü | 27 % | 100 % |
|
||
|
||
CABINET ist ein 4:1-Schriftzug, der in einer nahezu quadratischen Fläche saß – im Seitenkopf
|
||
blieben davon rund 28 px sichtbare Höhe. Nach dem Beschnitt sind es 69 px bei voller Boxbreite,
|
||
also gut zweieinhalbmal so groß. Rotpunkt wächst um gut das Anderthalbfache und steht jetzt auf
|
||
derselben Höhe wie Febrü.
|
||
|
||
Bei den beiden SVGs genügte dafür der `viewBox` (Ursprung und Maße auf die Tuschekante gesetzt,
|
||
plus 1 % Luft); die Pfade selbst sind unverändert. Der Febrü-PNG wurde tatsächlich beschnitten
|
||
und auf 760 px Breite gerechnet – 53 KB → 15 KB. Die Originale liegen unverändert in
|
||
`dev/2026-08-28/markenlogos/`.
|
||
|
||
**Zweite Feinabstimmung nach Sichtung:** CABINET wirkte noch zu groß, Rotpunkt zu klein –
|
||
gewünscht waren −15 % und +20 % bei unverändertem Febrü. Rotpunkt füllte die Box bereits ganz
|
||
aus, konnte also nur über eine größere Box wachsen. Deshalb:
|
||
|
||
- Alle vier Logo-Boxen **20 % höher** (Seitenkopf 96 → 115 px, Kacheln 44 → 53 px, `/marken`
|
||
56 → 67 px). Rotpunkt füllt sie weiter aus und wächst damit um genau 20 %.
|
||
- **Febrü** gleicht das über 20 % Luft oben und unten in der Datei aus und rendert unverändert.
|
||
- **CABINET** bekommt 18 % Luft rechts – die Box begrenzt den 4:1-Schriftzug über die *Breite*,
|
||
nicht über die Höhe. Die Luft sitzt nur rechts, damit das Logo links bündig zum Text darunter
|
||
bleibt.
|
||
|
||
Nachgerechnet an allen drei Stellen: CABINET 85 %, Rotpunkt 120 %, Febrü 100 %.
|
||
|
||
> Die optische Abstimmung steckt bewusst in den **Zeichenflächen der Dateien** und nicht im
|
||
> Blade. So gilt sie an allen vier Stellen gleichzeitig, und die Boxgrößen bleiben eine reine
|
||
> Layoutentscheidung. Der Merksatz für neue Logos steht im Kopf von `BrandLogoSeeder`: knapp
|
||
> beschnitten rendert ein Logo in Rotpunkt-Größe, mit Rand entsprechend kleiner.
|
||
|
||
**Nachziehen auf bestehenden Installationen:** `CmsBrandSeeder` überspringt vorhandene Marken,
|
||
trägt die Logos also nur bei einer frischen Installation ein. `BrandLogoSeeder` **(neu)** setzt
|
||
sie auf bereits angelegten Marken nach – nur das Feld `logo` und nur, wenn es leer ist. Ein
|
||
selbst hochgeladenes Logo bleibt damit stehen; mehrfaches Ausführen ist unbedenklich.
|
||
|
||
#### Tests
|
||
|
||
`BrandPageSectionsTest` und `BrandPageTest` erweitert:
|
||
|
||
- CABINET rendert seine Abschnitte und seinen eigenen Abschlussblock.
|
||
- Widget-Beschriftung jetzt für alle drei Marken (Datensatz-Test).
|
||
- Rotpunkt: der zusammengeführte Abschnitt existiert, der alte ist weg, der doppelte Satz steht
|
||
genau einmal auf der Seite.
|
||
- Febrü: der Blaue-Engel-Satz behält seinen Produktbezug.
|
||
- Der Rückfall auf den generischen Abschlussblock funktioniert weiterhin – **beide Sprachen
|
||
müssen dafür leer sein**, sonst greift die Übersetzungs-Fallbackkette und der englische Text
|
||
erscheint auf der deutschen Seite.
|
||
- Demogalerien tragen keinen „BEISPIEL"-Vermerk mehr, dafür durchgehend eine Kategorie.
|
||
- Der Normalizer entfernt den Vermerk, ohne Bild, Kategorie oder Reihenfolge zu verändern.
|
||
- Jede Vertiefung rendert zugeklappt und mit der Höhen-Animation; die alte Sprung-Bewegung ist
|
||
weg.
|
||
- Weder Markenseite noch FAQ verwenden noch den Flächen-Hover.
|
||
- Der Abschlussblock trägt das Verlaufsband; die weichen Kreise sind weg.
|
||
- Die Ausnahme für `.variante-glass-flow` ist vorhanden – ohne sie steht der Abschluss hellgrau da.
|
||
- Das Logo steht im `<h1>` der Markenseite; ohne Logo erscheint weiter der Schriftzug.
|
||
- Alle drei Logos erscheinen auf Startseite, `/marken` und den „Weitere Marken"-Kacheln.
|
||
- Die Dateien, auf die der Seeder zeigt, liegen tatsächlich unter `public/`.
|
||
- `BrandLogoSeeder` überschreibt kein selbst hochgeladenes Logo.
|
||
- Die SVGs unter `public/` sind die beschnittenen Fassungen, nicht die Zulieferungen (erkennbar
|
||
am `viewBox`-Ursprung, der nach dem Beschnitt nicht mehr `0 0` ist).
|
||
|
||
`php artisan test --compact`: **873 grün** (3217 Assertions), Pint sauber, `npm run build:b2in`
|
||
gebaut.
|
||
|
||
---
|
||
|
||
## 4. Nicht Bestandteil dieses Auftrags ⏸
|
||
|
||
Referenzbereich voll ausgebaut · 16:9-Display-Modul · Immobilien-CMS · Dubai-Map ·
|
||
Markenrichtlinie Fahrzeug/Print · weitere frei anlegbare Rubriken · eigene Videolösung.
|
||
**Zusätzlich neu zu bewerten:** B2 (Magazin-CMS ans Frontend anschließen, ≈2–3 Std.)
|
||
und B8 (Passwort aus dem Seeder).
|
||
|
||
---
|
||
|
||
## 5. Abhängigkeiten
|
||
|
||
```
|
||
AP1 (Struktur, Umtextung, B1/B3/B4/B5/B6/B7)
|
||
├─ AP2 (Kernmarken, B9) ──┐
|
||
├─ AP4 (Display-Spiegelung)│
|
||
├─ AP5 (Referenzen) │
|
||
├─ AP6 (Sponsoring) ◄──────┤ braucht B9
|
||
└─ AP3 (Termin-Widget) ◄───┘ Markenauswahl braucht CmsBrand
|
||
```
|
||
|
||
**B1 zuerst.** Solange der Seeder überschreibt, ist jede redaktionelle Arbeit flüchtig.
|
||
|
||
---
|
||
|
||
## 6. Restrisiken & offene Punkte
|
||
|
||
| Punkt | Stand | Umgang |
|
||
|---|---|---|
|
||
| **Rechtstexte** nennen weiter „Connecting Design and Property", Dubai/Lissabon, Supply-Chain | ⚠️ offen | Formulierung freigeben lassen, dann eintragen – nicht selbst getextet |
|
||
| **OG-Bild fehlt komplett** (`b2in-og-default.jpg` existiert nicht) | ⚠️ offen | Motiv wählen, ablegen |
|
||
| WhatsApp-Nummer (+49 151 51002992?) | offen | bestätigen lassen; ohne Nummer bleibt der Button unsichtbar |
|
||
| Logos, Stimmungsbilder, Galeriefotos der drei Marken | offen | Platzhalter stehen, Marcel trägt im CMS nach |
|
||
| Zwei neue Magazin-Beiträge sind Platzhalter | offen | gegenlesen lassen |
|
||
| Sponsoren-Kurztexte sind Entwürfe | offen | gegenlesen lassen |
|
||
| Vier Dubai-Beiträge bleiben im Magazin | bewusst | gehören zum Immobilienbereich, der bestehen bleibt |
|
||
| `ecosystem_stats` behauptet „1,7K+ Partner", „510+ Projekte", „98 %" | ruhend | Sektion wird auf keiner erreichbaren Seite gerendert – vor einer Wiederverwendung prüfen |
|
||
| B1/B2 Entscheidung | ✅ erledigt | Redaktionsschutz im Seeder, Magazin am Frontend |
|
||
| Logo mit Zusatz „Interior" | ✅ erledigt | Zulieferung eingetroffen und zugeschnitten |
|
||
| Sponsoring-Logos uneinheitlich | ✅ erledigt | Kacheln mit weißer Bühne, JPG ohne Transparenz fällt nicht mehr auf |
|
||
|
||
**Spielregel aus der Umsetzungsliste:** eine Korrekturschleife je Bereich ist enthalten.
|
||
Weitere Runden vorher melden und beziffern.
|
||
|
||
---
|
||
|
||
## 7. Definition of Done
|
||
|
||
- [x] Alle Live-Seiten laden (`LiveSiteReviewTest` grün)
|
||
- [x] Marcel kann Marke anlegen, Logo per Picker setzen, Galerie pflegen – und die Änderung
|
||
erscheint auf der Website (Gegenprobe zu B2, getestet in `CmsBrandsIndexTest`)
|
||
- [x] Erneuter `CmsContentSeeder`-Lauf löscht keine redaktionellen Inhalte (Gegenprobe zu B1)
|
||
- [x] `./vendor/bin/pint`
|
||
- [x] `npm run build:b2in` (Build-Verzeichnis `build/b2in`)
|
||
- [x] `php artisan test --compact` vollständig grün — 810 Tests, 3037 Assertions
|
||
- [ ] Keine Treffer mehr für „Supply-Chain", „Local for Local", „Ökosystem", „Connecting Design"
|
||
auf den Live-Seiten. **Stand: 8 statt ursprünglich 90.** Davon
|
||
5 in `/magazin` (die vier Dubai-Beiträge, bleiben bewusst),
|
||
1 in `/privacy` und 2 in `/terms` (Rechtstexte, siehe Abschnitt 0, Schritt 2).
|
||
Erst abhakbar, wenn die Rechtstexte freigegeben sind.
|
||
- [ ] OG-Bild vorhanden
|
||
- [ ] Rechtstexte freigegeben und eingetragen
|
||
|
||
---
|
||
|
||
## 7a. Vorschau-Instanz für die Abstimmung
|
||
|
||
Für die erste Abstimmung läuft der neue Stand als **eigenständige Vorschau** unter
|
||
`preview.b2in.eu` – eigenes Verzeichnis, eigene `.env`, eigene Datenbank. Live bleibt unangetastet.
|
||
|
||
**Ablauf Schritt für Schritt: `dev/2026-08-28/preview-deployment.md`.**
|
||
Dateien dafür: `dev/2026-08-28/deploy/b2in-interior-update.tar.gz` (geänderte Dateien plus
|
||
gebaute Assets) und `deploy/dateiliste.txt`.
|
||
|
||
Zwei Punkte, die dabei leicht übersehen werden:
|
||
|
||
- **Die Vorschau braucht `DOMAIN_B2IN=preview.b2in.eu` in ihrer `.env`.** Der
|
||
`ThemeServiceProvider` setzt `URL::forceRootUrl()` auf die konfigurierte Domain; ein unbekannter
|
||
Host fällt auf `APP_URL` zurück. Ohne diesen Eintrag rendert die Vorschau zwar, aber jeder
|
||
interne Link springt auf die Live-Seite.
|
||
- **Eigene Datenbank, keine geteilte.** `InteriorRelaunchCmsSeeder` überschreibt 23 CMS-Sektionen –
|
||
auf der Live-DB ausgeführt wäre der alte Stand weg.
|
||
|
||
Neu dafür im Code: `config('app.indexable')`. Außerhalb von `APP_ENV=production` liefert jede Seite
|
||
`noindex, nofollow`, damit eine Vorschau nicht mit dem Original um Suchergebnisse konkurriert.
|
||
Über `SITE_INDEXABLE` einzeln steuerbar.
|
||
|
||
---
|
||
|
||
## 8. Deployment-Checkliste (Livegang)
|
||
|
||
> **Diese Liste beim Livegang von oben nach unten abarbeiten.** Sie wird mit jedem Arbeitspaket
|
||
> ergänzt – zuletzt aktualisiert nach AP1 und der Display-Umstellung.
|
||
|
||
### 8.1 Vorher
|
||
|
||
- [ ] **DB-Backup ziehen.** Die Seeder unter 8.2 schreiben in `flux_cms_contents`,
|
||
`display_versions` und `display_version_items`.
|
||
- [ ] `.env` prüfen: `SEED_ADMIN_NAME`, `SEED_ADMIN_EMAIL`, `SEED_ADMIN_PASSWORD` gesetzt
|
||
(neu seit B8 – vorher stand das Passwort im Repo).
|
||
- [ ] Wartungsfenster mit Marcel abstimmen: die Displays holen ihre Konfiguration zyklisch,
|
||
ein Neustart ist nicht nötig, aber ein sichtbarer Wechsel mitten im Ladengeschäft schon.
|
||
|
||
### 8.2 Deployment
|
||
|
||
```bash
|
||
php artisan migrate --force # legt u. a. cms_brands an (AP2)
|
||
|
||
# 0. Kernmarken anlegen (CABINET, Rotpunkt Küchen, Febrü).
|
||
# Überschreibt nichts – bereits gepflegte Marken bleiben unberührt.
|
||
php artisan db:seed --class=CmsBrandSeeder --force
|
||
|
||
# 1. Neue Texte ins CMS. Überschreibt GENAU die in AP1 geänderten Sektionen (seit 06.10. 15, die vier Netzwerk-Sektionen sind entfernt),
|
||
# alles andere bleibt unangetastet.
|
||
php artisan db:seed --class=InteriorRelaunchCmsSeeder --force
|
||
|
||
# 2. Display-Branding auf das Interior-Logo vereinheitlichen (Logo je Theme + neuer Claim).
|
||
php artisan db:seed --class=DisplayInteriorBrandingSeeder --force
|
||
|
||
# 3. Medien-URLs host-unabhängig machen. Ohne diesen Schritt zeigen vier veröffentlichte
|
||
# Playlists weiterhin auf b2in.test und laden auf dem Live-Display nicht.
|
||
php artisan db:seed --class=DisplayMediaUrlNormalizerSeeder --force
|
||
|
||
# 4. Ausführliche Markenseiten (CABINET, Rotpunkt, Febrü). Schreibt NUR tagline, description,
|
||
# sections, widget_label, cta_title und cta_text – Bilder, Galerie, Leistungen und
|
||
# Reihenfolge bleiben unberührt.
|
||
php artisan db:seed --class=BrandPageTextSeeder --force
|
||
|
||
# 5. Entfernt den Vermerk „BEISPIEL – “ aus vorhandenen Bildunterschriften (Nachtrag 5).
|
||
# Fasst nur den Text an, mehrfaches Ausführen ist unbedenklich.
|
||
php artisan db:seed --class=BrandGalleryCaptionNormalizerSeeder --force
|
||
|
||
# 6. Markenlogos nachtragen. Setzt `logo` nur, wenn das Feld leer ist – ein im Admin
|
||
# hochgeladenes Logo bleibt stehen. Braucht public/img/assets/marken/ aus dem Archiv.
|
||
php artisan db:seed --class=BrandLogoSeeder --force
|
||
|
||
# 7. Welten-Trennung (Nachtrag 7): Navigation und Inhalte der Immobilien-Welt anlegen,
|
||
# Interior-Navigation ohne „Immobilien“ und Magazin-Einleitung ohne Dubai-Bezug setzen.
|
||
# Die Migration ordnet die drei Dubai-Beitraege der Immobilien-Welt zu.
|
||
php artisan db:seed --class=WorldSplitCmsSeeder --force
|
||
|
||
# 8. Vierte Kernmarke Otterpohl, Slug „tischlerei“ (Nachtrag 9 + 15) – legt nur an, was fehlt.
|
||
php artisan db:seed --class=CmsBrandSeeder --force
|
||
|
||
# 9. Herkunfts-Sektion „Aus der Region gefertigt“ (Nachtrag 10) – legt die Sektion nur an, wenn sie
|
||
# fehlt. Entfernt aus einem bestehenden Eintrag nur den veralteten Schlüssel „locations“ (Nachtrag 11).
|
||
php artisan db:seed --class=OriginSectionCmsSeeder --force
|
||
|
||
# 10. Fertigungsort je Kernmarke (Nachtrag 11) – setzt Ort, Entfernung und Rolle nur bei Marken,
|
||
# deren Ort noch leer ist. Die Migration davor legt die drei Spalten an.
|
||
php artisan db:seed --class=BrandOriginSeeder --force
|
||
|
||
# 11. Otterpohl (Nachtrag 15 + 19): ersetzt den Platzhalter „Tischlerei“ durch Name, Claim, Texte,
|
||
# Leistungen, Abschnitte, Abschlussblock und Fertigungsort aus der Zulieferung v2 vom 24.09.
|
||
# Überschreibt auch einen Stand mit dem Text vom 17.09. Bild, Galerie und Reihenfolge
|
||
# bleiben; das Logo wird nur gesetzt, wenn es leer ist.
|
||
# Schritt 4 (BrandPageTextSeeder) bringt das Feedback vom 17.09. für CABINET, Rotpunkt
|
||
# und Febrü mit – er überschreibt dort wie dokumentiert die Textfelder.
|
||
php artisan db:seed --class=OtterpohlBrandSeeder --force
|
||
|
||
# 12. Bilder für CABINET, Rotpunkt, Febrü (Nachtrag 16) und Otterpohl (Nachtrag 19): Titelbild nur,
|
||
# wenn keins gepflegt ist; Galeriebilder nur, wenn die Datei noch nicht in der Galerie steht.
|
||
# Die WebP-Dateien liegen unter public/img/assets/marken/{cabinet,rotpunkt,februe,otterpohl}/
|
||
# im Repository.
|
||
php artisan db:seed --class=BrandImageSeeder --force
|
||
|
||
# 13. Demobilder aus den Galerien entfernen (Nachtrag 17) – erkennt sie am Dateinamen des
|
||
# Demo-Seeders, echte Bilder bleiben. Nach Schritt 12 ausführen.
|
||
php artisan db:seed --class=DemoBrandGalleryCleanupSeeder --force
|
||
|
||
# 14. WhatsApp-Business-Nummer 0521-98620100 (Nachtrag 18): ersetzt nur den Platzhalter
|
||
# „+49 151 00000000“, die falsche Nummer vom 23.09. (…98610020) oder ein leeres Feld –
|
||
# eine im Admin gepflegte andere Nummer bleibt.
|
||
php artisan db:seed --class=WhatsappNumberSeeder --force
|
||
|
||
# 15. Projekttext auf der Startseite (Briefing 24.09., Punkt 7; Nachtrag 19): ersetzt in
|
||
# home/audience_switch nur den Satz „Mit deutscher Vertragssicherheit …“. Idempotent.
|
||
php artisan db:seed --class=AudienceSwitchProjectTextSeeder --force
|
||
|
||
# 16. Abstimmung 01.10. (Nachtrag 20): Hero-Überschrift „Räume aus einer Hand.“ und zweiten
|
||
# Hero-Button entfernen (nur wenn noch die alte Überschrift im CMS steht), Projekttext mit
|
||
# Punkt (Schritt 15 erneut, idempotent), Otterpohl: Titelbild tauschen + Abschnitt „Montage“.
|
||
# Die Hinweisleiste ist per Standard aus (B2IN_ANNOUNCEMENT_BAR, nichts in die .env nötig).
|
||
php artisan db:seed --class=HomeHeroTextSeeder --force
|
||
php artisan db:seed --class=AudienceSwitchProjectTextSeeder --force
|
||
php artisan db:seed --class=OtterpohlBrandSeeder --force
|
||
|
||
php artisan config:cache
|
||
php artisan view:clear
|
||
|
||
# Assets. WICHTIG: `build:web` baut nur die vier Frontend-Themes, NICHT das Portal.
|
||
# Fehlt public/build/portal/manifest.json, liefert das Admin-Portal 500.
|
||
npm ci
|
||
npm run build:web
|
||
npm run build:portal
|
||
```
|
||
|
||
Danach prüfen, dass alle fünf Manifeste liegen:
|
||
|
||
```bash
|
||
for d in b2in b2a stileigentum style2own portal; do
|
||
test -f "public/build/$d/manifest.json" && echo "$d ok" || echo "$d FEHLT"
|
||
done
|
||
```
|
||
|
||
### 8.3 Nachher prüfen
|
||
|
||
- [ ] Startseite: Reihenfolge, Kernmarken-Anker `#marken`, Sponsoring-Logos
|
||
- [ ] Markenseite `/marken` – Aufbau, Merkmale, „Alle Marken ansehen" von der Startseite
|
||
- [ ] Kernmarken-Detailseiten `/marken/cabinet`, `/marken/rotpunkt`, `/marken/februe` – je mit
|
||
Logo im Kopf, ausführlichem Text, aufklappbaren Vertiefungen und eigenem Abschlussblock
|
||
- [ ] Logos erscheinen auf der Startseite, auf `/marken` und in den „Weitere Marken"-Kacheln
|
||
- [ ] Auf dem Smartphone prüfen: Das Terminanfrage-Widget trägt auf der Markenseite die längere
|
||
Beschriftung und darf keine Inhalte verdecken
|
||
- [ ] `/netzwerk`, `/interior`, `/partner`, `/service` leiten auf `/marken`
|
||
- [ ] Im Admin unter „Kernmarken" eine Marke ändern und prüfen, dass es auf der Seite ankommt
|
||
- [ ] Ankündigungsleiste erscheint (Dismiss-Key hängt seit B3 am Inhalt – wer die alte Leiste
|
||
weggeklickt hatte, sieht die neue wieder)
|
||
- [ ] Logo in Header, Footer **und** in einer Test-Mail
|
||
- [ ] Alte Magazin-URLs `/magazin/1` … `/magazin/5` leiten per 301 auf den Slug
|
||
- [ ] `/service` und `/portfolio` leiten um statt 500 zu liefern
|
||
- [ ] Terminanfrage-Widget: WhatsApp-Button oben, Link führt auf `wa.me/4952198620100`, darunter
|
||
„oder per Formular“ und das Formular
|
||
- [ ] Interior-Seiten laufen in „Neu“ (`<html class="palette-modern">`), kein Farb-Schalter;
|
||
`/immobilien` unverändert blau
|
||
- [ ] `/entwurf`: Gold-Logo in Kopf und Fuß, Hero mit Goldkante und laufender Slideshow (Marken-
|
||
Titelbilder), keine Ankündigungsleiste, ein Button im Hero, Termin-Widget unten rechts
|
||
- [ ] `/marken/tischlerei`: Text v2 (drei Abschnitte, acht Leistungen, Abschluss „Das Ganze statt
|
||
nur das Einzelne“), Werkstatt-Titelbild, Galerie „Referenzen und Einblicke“ mit den Badges
|
||
„Realisiertes Projekt“ und „Aus der Werkstatt“
|
||
- [ ] **Die vier Displays sichten:** „Display 4 – Innen", „Kundenstopper", „Display 2",
|
||
„Test-Display". Besonders das Modul „Cabinet-Influencerin" – dessen Video lag auf
|
||
`b2in.test`. Ob die Datei auf dem Live-Server überhaupt existiert, ließ sich lokal nicht
|
||
prüfen; fehlt sie, muss sie nachgeladen werden.
|
||
- [ ] Search Console: die alten Magazin-URLs waren indexiert, die 301 fängt sie ab
|
||
- [ ] Search Console: `/netzwerk` war indexiert und leitet jetzt auf `/marken`
|
||
|
||
### 8.4 Zurückrollen
|
||
|
||
Die Seeder sind nicht umkehrbar. Rückweg ist das Backup aus 8.1 – für die betroffenen Tabellen
|
||
genügt ein selektives Zurückspielen von `flux_cms_contents`, `display_versions` und
|
||
`display_version_items`.
|
||
|
||
### 8.5 Nicht vergessen
|
||
|
||
- [ ] Altes Seeder-Passwort rotieren, falls es anderswo benutzt wird – es steht weiterhin in der
|
||
Git-Historie (B8).
|
||
- [ ] WhatsApp-Nummer bestätigen lassen – erst dann erscheint der Button im Terminanfrage-Widget
|
||
und in den CTA-Blöcken (CMS: `global.contact.whatsapp`).
|
||
- [ ] `CONTACT_FORM_RECIPIENT` in der Live-`.env` prüfen: dorthin gehen auch die Terminanfragen
|
||
aus dem Widget.
|
||
- [ ] Datenschutzerklärung um einen Absatz zum WhatsApp-Link ergänzen, sobald die Nummer steht.
|
||
- [ ] **Rechtstexte:** AGB (`b2in_legal.php` Zeile 117) und Datenschutzerklärung (Zeile 221)
|
||
nennen weiter „Connecting Design and Property", Dubai/Lissabon und Supply-Chain-Management.
|
||
Von Marcel prüfen lassen, dann eintragen.
|
||
- [ ] Prüfen, welches Display auf der Website laufen soll (`referenzen.display_feed.display_id`).
|
||
Ohne Eintrag zeigt die Seite das erste aktive Display mit veröffentlichter Playlist.
|
||
- [ ] Die zwei neuen Magazin-Beiträge von Marcel gegenlesen lassen – sie sind Platzhalter.
|
||
- [ ] **Herstellerfreigabe für die Markentexte** (Rotpunkt, Febrü) einholen – so verlangt es die
|
||
Zulieferung selbst. Beide Fassungen nennen zusätzlich die EmpCo-Regeln (ab 27.09.2026):
|
||
die Umweltaussagen vorher rechtlich prüfen lassen.
|
||
- [ ] **CABINET-Seitentext von Marcel freigeben lassen.** Für CABINET lag keine Zulieferung vor;
|
||
der Text ist von uns nach dem Muster der beiden abgestimmten Seiten verfasst und beschreibt
|
||
bewusst nur die eigene Arbeitsweise (Nachtrag 5).
|
||
- [ ] **Febrü, Vertiefung „Konkrete Standards statt allgemeiner Versprechen“:** Der Blaue Engel
|
||
gilt nur für ausgewählte Tischsysteme und Stauraummöbel. Beim Redigieren darf daraus keine
|
||
pauschale Aussage über das Gesamtsortiment werden.
|
||
- [ ] **Demobilder der Rubrik „Realisiertes Projekt" ersetzen.** Der Vermerk „BEISPIEL" ist auf
|
||
Kundenwunsch entfallen (Nachtrag 5); die Stockmotive und KI-Renderings aus
|
||
`DemoBrandGallerySeeder` geben sich damit als echte Referenzen aus. Entweder durch echte
|
||
Projektfotos ersetzen oder auf „Inspiration" umstellen.
|
||
- [ ] **Rotpunkt, Vertiefung „Zahlen, Zertifizierungen und Raumklima“:** Die Aussage zur jährlich
|
||
erhaltenen Waldfläche von ungefähr 50 Fußballfeldern darf laut Zulieferung nur mit
|
||
ausdrücklicher Bestätigung veröffentlicht werden. Ohne Bestätigung den Absatz entfernen
|
||
(Admin: Kernmarken → Rotpunkt → Abschnitte → Vertiefung).
|
||
- [ ] OG-Bild anlegen: das Layout verweist auf `img/assets/b2in-og-default.jpg`, die Datei
|
||
existiert nicht. Bis dahin zeigt jede geteilte Seite eine Vorschau ohne Bild.
|
||
- [ ] Sponsoring-Logo `tc-bad-waldliesborn-horn` liegt nur als JPG vor, also ohne transparenten
|
||
Hintergrund. Falls Marcel eine PNG-Variante hat, austauschen.
|
||
- [ ] Markengalerien vor dem Livegang durchsehen: jedes Bild muss in der richtigen Rubrik stehen.
|
||
Ohne gesetzte Kategorie erscheint ein Bild als „Visualisierung" – für ein echtes Projektfoto
|
||
also bewusst „Realisiertes Projekt" wählen.
|
||
|
||
---
|
||
|
||
## Nachtrag 6 · Arbeitsplan 14.09.2026, Punkt 1.1: Farbwelt und Logo (14.09.2026)
|
||
|
||
Grundlage: `umsetzungen-14-09-2026.md` (freigegebener Umfang Phase 1) und die Shop-Screenshots
|
||
unter `_b2in_interior_shop/screenshots/web/` als optische Richtung: warme Creme-/Sandflächen,
|
||
dunkles Tannengrün als Kontrast, Serifen-Überschriften, ruhige Flächen ohne Leuchteffekte.
|
||
|
||
### Zwei Welten auf einem Themensystem
|
||
|
||
`theme-b2in.css` definiert die **Interior-Welt als Standard** auf `:root` und die
|
||
**Immobilien-Welt** als Override unter `.world-immobilien` – dieselben Token-Namen, andere Werte.
|
||
Das Layout setzt die Welt als Body-Klasse (`world-interior` / `world-immobilien`), ermittelt
|
||
über `b2in_world()` in `app/helpers.php`: Immobilien sind alle Routen `immobilien*` und
|
||
`dev.immobilien*`, alles andere ist Interior. Bestehende Sektionen mussten dafür nicht angefasst
|
||
werden – sie nutzen bereits die Tokens (`text-secondary`, `bg-accent`, `cta-band` …).
|
||
|
||
| Token | Interior (neu) | Immobilien (wie bisher) |
|
||
|---|---|---|
|
||
| `--background` | Creme `#f7f4ef` | helles Beige `#f5f4f2` |
|
||
| `--foreground` | Anthrazit `#2d2926` | `#2a2a2a` |
|
||
| `--primary` (Buttons, dunkle Sektionen, Wortmarke) | Tanne `#202c2b` | Anthracite `#2b3f51` |
|
||
| `--secondary` (Akzent, Hervorhebungen, Logo-Bogen) | Ocker `#d39e46` | Dynamic Blue `#20a0da` |
|
||
| `--accent` (Sektionswechsel) | Sand `#d9cbbf` | helles Grau |
|
||
| `--clay` (neu) | Clay `#a38f82` | gedämpftes Blau |
|
||
| `--footer-*` (neu) | Sand mit Tanne | Anthracite mit Weiß |
|
||
| `--cta-band-end` (neu) | helleres Tannengrün (Ton in Ton, Korrektur 15.09.) | Dynamic Blue |
|
||
| `--font-secondary` (Überschriften) | EB Garamond (liegt lokal vor) | IBM Plex Sans |
|
||
|
||
**Kontrast-Entscheidungen:** Ocker trägt keinen hellen Text (Creme auf Ocker ≈ 2,5:1). Deshalb
|
||
ist Ocker in der Interior-Welt Akzent, kein Flächenton unter Text: der Kontakt-Button im Kopf
|
||
und der zweite Hero-Button laufen jetzt auf Tanne (gefüllt bzw. als Kontur, `.world-interior
|
||
.btn-secondary-accent`), der Abschluss-CTA der Startseite liegt auf dem Abschlussband
|
||
(`cta-band`) mit weißem Button – wie auf den Markenseiten. **Korrektur 15.09.:** Der Verlauf
|
||
Grün → Ocker wirkte unharmonisch; das Band läuft jetzt Ton in Ton in ein helleres Tannengrün aus,
|
||
Ocker sitzt nur noch in der Haarlinie oben. Hervorgehobene Wörter im Bandtitel („Ihr nächster
|
||
Schritt") tragen im CMS `text-primary` und waren auf dem dunklen Band unlesbar – in beiden
|
||
Welten. `.cta-band .text-primary` setzt sie auf den Akzent der Welt (Ocker bzw. Blau). Ocker-Text
|
||
im Footer auf Sand nutzt die tiefe Stufe `--secondary-deep`. `--muted-foreground` ist ein
|
||
abgedunkelter Clay, damit Fließtext auf Creme lesbar bleibt (Clay pur ≈ 2,9:1).
|
||
|
||
**Aufgeräumt:** Die Glow- und Schattenklassen in `shared-styles.css` (`glow-*`, `shadow-elegant`,
|
||
`shadow-premium`, Button-Hover im Glass-Flow) hatten ein festes Blau (`rgba(0,136,204)`,
|
||
`hsla(199 …)`) – jetzt hängen sie am Akzent der Welt. Karten im Glass-Flow nutzen `--card`
|
||
statt festem Weiß.
|
||
|
||
### Logo je Welt
|
||
|
||
Zulieferung 07.09.2026 (`dev/2026-08-28/logos/`): das Interior-Logo in Tanne mit Ocker-Bogen
|
||
(positiv) bzw. Creme mit Ocker-Bogen (negativ) und das B2In-Logo ohne Zusatz mit blauem Bogen.
|
||
Beide Familien sind auf den Inhalt beschnitten (Interior `viewBox="152.5 94.5 289 228"`,
|
||
B2In `viewBox="4.5 2 301 176"`) und liegen als SVG und PNG (240 px hoch) unter
|
||
`public/img/logos/`; die Interior-Varianten zusätzlich unter `public/_cabinet/assets/` für das
|
||
Display. `ThemeHelper::getLogoPath($type, $world)` liefert die Datei je Welt.
|
||
|
||
Header und Footer halten Welt und Logo-Pfad in `mount()` fest, weil ein späterer
|
||
Livewire-Request keine Seitenroute mehr trägt. Der Interior-Footer liegt auf Sand und zeigt das
|
||
**positive** Logo; der Immobilien-Footer bleibt dunkel mit dem negativen.
|
||
|
||
**Favicons** (`public/favicon/`, alle Größen plus `favicon.ico`) neu aus der Wortmarke in
|
||
Tanne/Ocker erzeugt; `theme-color` auf Creme. Die bisher tote Referenz
|
||
`img/favicons/b2in-favicon.ico` (`ThemeHelper::getFaviconPath()`) existiert jetzt.
|
||
Mail-Kopf auf Tanne.
|
||
|
||
### Welten-Wechsler
|
||
|
||
Kopfzeile (Desktop rechts neben dem Sprachwechsel, mobil als erster Block im Menü) und Footer
|
||
tragen einen Umschalter „Interior | Immobilien" (`b2in_worlds()`, Labels in `ui.php` de/en).
|
||
Die aktive Welt ist gefüllt und trägt `aria-current="page"`.
|
||
|
||
### Tests
|
||
|
||
`tests/Feature/ColorWorldsTest.php` (neu, 14 Fälle): Body-Klasse und Logo je Welt für
|
||
Startseite, `/immobilien`, Detailseite und weitere Seiten; `ThemeHelper::getLogoPath()` je Welt
|
||
und für Fremd-Themes; Dateien und Farbwerte beider Logo-Familien; Wechsler in Kopf und Fuß mit
|
||
korrekter Markierung; Tokens im Theme; kein festes Blau mehr in den Effekten.
|
||
`HomePageStructureTest` an den neuen Zuschnitt und den Sand-Footer angepasst.
|
||
|
||
### Offen nach diesem Nachtrag
|
||
|
||
- **Freigabe Marcel:** Farbwerte sind laut Plan „blockierend für 1.1" und wurden wie geliefert
|
||
umgesetzt. Die **Serife für Überschriften** (EB Garamond) ist eine Ableitung aus den
|
||
Shop-Screenshots, kein Planpunkt – ein Token in `theme-b2in.css`, bei Ablehnung in einer Zeile
|
||
zurück auf IBM Plex Sans.
|
||
- **Bildwelt:** Die Farbwelt wirkt erst mit warmem Bildmaterial (Hero, Kacheln) vollständig; die
|
||
Bestandsbilder aus der Immobilien-Zeit sind kühl. Zulieferung weiterhin offen.
|
||
- **Display-Player:** nutzt die neuen Interior-Dateien automatisch; der Theme-Scrim im Player
|
||
ist weiter neutral dunkel, keine Anpassung an Tanne vorgenommen.
|
||
- Nächste Schritte laut Reihenfolge im Arbeitsplan: 1.2 Tischlerei-Markenseite (blockiert durch
|
||
Name, Logo, Bilder), 1.3 Herkunfts-Sektion (blockiert durch CABINET-Klärung), 1.4 Akkordeon
|
||
und Widget-Beschriftung.
|
||
|
||
---
|
||
|
||
## Nachtrag 7 · Saubere Trennung der beiden Welten (14.09.2026)
|
||
|
||
Abgestimmt mit Kevin am 14.09.: Nach der Farbwelt-Umstellung zeigte die Immobilien-Welt noch die
|
||
Interior-Navigation, und das Magazin mischte Dubai- und Einrichtungsthemen. Entscheidung: **jede
|
||
Welt hat ihre eigene Navigation, der Welten-Wechsler ist die einzige Brücke.** Umfang ist eine
|
||
Erweiterung zu 1.1 des Arbeitsplans (nicht im freigegebenen Plan enthalten, Aufwand ca. 6–9 h).
|
||
|
||
### Was je Welt getrennt ist
|
||
|
||
| Bereich | Interior | Immobilien |
|
||
|---|---|---|
|
||
| Navigation (CMS) | `global.header`: Home · Marken · Referenzen · Magazin · Über B2in | `global.header_immobilien`: Immobilien · Projekte · Magazin · Über B2in |
|
||
| Ankündigungsleiste (CMS) | `global.announcement_bar`: aktuelles Interior-Thema (Rotpunkt) | `global.announcement_bar_immobilien`: aktuelles Projekt (Azizi Creek Views 4, wie vor dem Relaunch), eigener Dismiss-Schlüssel |
|
||
| Magazin | `/magazin` – nur Interior-Beiträge | `/immobilien/magazin` – nur Immobilien-Beiträge |
|
||
| Über uns | `/about` (unverändert) | `/immobilien/ueber-b2in` – Inhalte aus der Zeit vor dem Relaunch, leicht angepasst, als „B2in Immobilien" gekennzeichnet, Claim „Connecting Design and Property" |
|
||
| FAQ | `/faq` (unverändert) | `/immobilien/faq` – Fragen zu Investment, Reisen, Steuern, Einrichtung nach dem Kauf |
|
||
| Kontakt | `/contact` (unverändert) | `/immobilien/kontakt` – gleiche Seite, eigener Einstieg und eigene Betreffe (Overlay `contact_form_immobilien` über `contact_form`), Mail-Betreff „Kontaktanfrage B2in Immobilien: …"; Kontakt-Button im Kopf und CTAs der Immobilienseite zeigen dorthin |
|
||
| Footer-Links | wie bisher | FAQ, Über uns und Magazin zeigen auf die Immobilien-Seiten |
|
||
| Terminanfrage-Widget | Anliegen offen | Anliegen „Immobilien" vorbelegt, Mail-Betreff „Terminanfrage B2in Immobilien" |
|
||
|
||
**Gemeinsam bleiben** Rechtstexte und die Cookie-Seiten. (Kontakt war zunächst gemeinsam, seit 15.09. je Welt.)
|
||
|
||
### Magazin: Beiträge haben eine Welt
|
||
|
||
Neues Feld `world` (`interior` | `immobilien`) an `cms_articles`, im Admin als Auswahl „Welt"
|
||
mit Badge in der Liste. Die Migration ordnet die drei Dubai-Beiträge (Escrow, Al Jaddaf,
|
||
Turnkey) der Immobilien-Welt zu; der Supply-Chain-Beitrag bleibt laut Abstimmung unter B2B in
|
||
Interior. `CmsArticle::forFrontend($world)` filtert, Lang-Fallback inklusive.
|
||
|
||
Die **Detailseite behält ihre URL** (`/magazin/{slug}`, SEO und 301-Weiterleitungen bleiben),
|
||
rendert aber in der Welt ihres Beitrags: die Route setzt die Welt per `b2in_world_set()` vor dem
|
||
Rendern, weil Kopf- und Fußzeile sie in `mount()` festhalten. Verwandte Beiträge und der Rückweg
|
||
zur Liste bleiben in derselben Welt.
|
||
|
||
### Technik
|
||
|
||
- `b2in_world()` prüft zuerst einen expliziten Override (`b2in_world_set()`), dann die Route.
|
||
- Header: Navigation je Welt; der aktive Pfad wird in `mount()` festgehalten (vorher ging die
|
||
Markierung bei jedem Livewire-Request verloren) und nur der spezifischste Eintrag ist aktiv
|
||
(`/immobilien/magazin` markiert „Magazin", nicht „Immobilien").
|
||
- `AboutHero`, `OurStory`, `OurValues` nehmen jetzt wie `ImageBreak` einen Sektionsschlüssel.
|
||
- Kontaktformular: Betreffe in drei Gruppen (Interior · Immobilien · B2in, `form.subject_groups`).
|
||
Die Kernmarken aus dem CMS stehen automatisch am Anfang der Interior-Gruppe, die Welt der Seite
|
||
bestimmt, welche Gruppe oben steht. Betreff wird jetzt gegen die Liste validiert. Ältere
|
||
CMS-Stände mit flacher `subjects`-Liste funktionieren weiter (Fallback ohne Gruppen).
|
||
- Abschluss-CTA („Ihr nächster Schritt") je Welt: `global.cta_section_immobilien` mit eigenem Text
|
||
und Link auf `/immobilien/kontakt`; greift automatisch auf allen Seiten der Immobilien-Welt.
|
||
- Neue CMS-Sektionen (alle im Admin pflegbar): `header_immobilien`, `announcement_bar_immobilien`, `contact_form_immobilien`, `cta_section_immobilien`, `magazin_list_immobilien`,
|
||
`faq_immobilien`, `immobilien_about_hero`, `immobilien_our_story`,
|
||
`immobilien_about_image_break`, `immobilien_our_values`.
|
||
- `WorldSplitCmsSeeder` legt die neuen Sektionen an und setzt **zwei** Interior-Sektionen aus
|
||
den Lang-Dateien zurück: `header` (ohne „Immobilien") und `magazin_list` (ohne Dubai-Bezug).
|
||
Lokal ausgeführt, beim Deployment mit erledigen (Abschnitt 8).
|
||
|
||
### Tests
|
||
|
||
`tests/Feature/WorldSplitTest.php` (neu, 18 Fälle): Navigation je Welt inkl. aktiver Markierung,
|
||
Footer-Links, beide Magazinlisten, Detailseite in der Welt des Beitrags, verwandte Beiträge,
|
||
CMS-Beiträge je Welt, Editor-Auswahl und -Validierung, Über-uns- und FAQ-Seite der
|
||
Immobilien-Welt, Widget-Vorbelegung. `MagazinPageTest`, `HomePageStructureTest`,
|
||
`LiveSiteReviewTest` und `CmsAdminTest` an die Trennung angepasst.
|
||
|
||
### Offen
|
||
|
||
- Navigationspunkt „Projekte" zeigt auf den Anker `#projekte` der Immobilienseite.
|
||
- Die Immobilien-Seite selbst nutzt weiter feste Farben (`bg-zinc-950`, Status-Badges in
|
||
emerald/sky/amber) außerhalb des Token-Systems – funktioniert in der blauen Welt, ist aber
|
||
nicht themenfähig.
|
||
- `LiveSiteReviewTest` prüft die Startseite noch auf das Wort „Netzwerk" (steht im Fließtext);
|
||
kein Navigationspunkt.
|
||
|
||
---
|
||
|
||
## Nachtrag 8 · Terminanfrage-Buttons öffnen das Widget (15.09.2026)
|
||
|
||
Auf der Seite gibt es mehrere Sektionen mit „Termin anfragen"-Buttons (Hero, Weiche, Abschluss-CTA,
|
||
`/marken`-Abschluss, Markenseiten, Referenzen, Immobilienseite). Bisher führten sie auf die
|
||
Kontaktseite. Jetzt öffnen sie das schwebende Terminanfrage-Widget; von einer Markenseite aus ist
|
||
die Marke im Anliegen vorbelegt. Die Anliegen-Auswahl des Widgets bleibt wie sie ist (Marken plus
|
||
feste Einträge, keine Gruppen – die gibt es nur auf der Kontaktseite).
|
||
|
||
**Wie:** Blade-Komponente `<x-appointment-link :href :topic>`. Zeigt `href` auf `/contact` oder
|
||
`/immobilien/kontakt`, trägt der Link `data-open-appointment` (und `data-appointment-topic`); ein
|
||
Klick-Delegat in `resources/js/app.js` fängt ihn ab und feuert `open-appointment`, das Widget
|
||
öffnet sich, übernimmt das Anliegen (nur wenn es in der Auswahl existiert) und fokussiert das
|
||
Namensfeld. Ohne JavaScript bleibt es ein normaler Link; zeigt der CMS-Link woandershin, bleibt
|
||
er ein gewöhnlicher Link. Der Kontakt-Button im Kopf bleibt bewusst ein Link zur Kontaktseite.
|
||
|
||
**Formularfelder** in Widget und Kontaktformular tragen jetzt die tokenbasierten Klassen
|
||
`.form-field` / `.form-select` (shared-styles.css): Kartenton als Grund, Fokusring im Akzent der
|
||
Welt, eigener Chevron und lesbare Gruppenüberschriften in der Betreff-Auswahl – statt
|
||
Tailwind-Grau.
|
||
|
||
**Tests:** `tests/Feature/AppointmentTriggerTest.php` (9 Fälle).
|
||
|
||
---
|
||
|
||
## Nachtrag 9 · Tischlerei als vierte Kernmarke, Platzhalter (15.09.2026)
|
||
|
||
Arbeitsplan 14.09., Punkt 1.2. Name, Logo, Basisinfos und Bilder fehlen noch (blockierend laut
|
||
Plan), Platzhalter sind ausdrücklich erlaubt. Die Marke ist deshalb als **Denkanstoß** angelegt:
|
||
|
||
- **Marke `tischlerei`** im `CmsBrandSeeder` (vierter Eintrag, wird bei bestehenden Marken nicht
|
||
doppelt angelegt). Inhalte entlang der Ausrichtung aus dem Plan – Aufbau, Sonderlösungen,
|
||
Veredelung, Maßarbeit; ergänzt CABINET und Rotpunkt, steht nicht daneben; Werkstatt in
|
||
Ostwestfalen ohne Nennung des Partnerbetriebs. Drei Abschnitte mit Vertiefungen, eigener
|
||
Abschlussblock, Widget-Beschriftung „Persönliche Beratung zur Maßarbeit vereinbaren“.
|
||
- **Ohne Logo**: der Seitenkopf zeigt den Schriftzug, Kacheln kommen ohne Logo aus. Kein
|
||
Stimmungsbild, die Kacheln zeigen den Platzhalter.
|
||
- **Kachelraster** der Startseite: `sm:grid-cols-2` – 2×2 auf allen Breiten. Vier nebeneinander
|
||
war kurz drin, wurde aber als zu schmal verworfen (Abstimmung 15.09.). „Weitere Marken“ auf den
|
||
Detailseiten: drei nebeneinander ab `lg`.
|
||
- Automatisch dabei: `/marken`, Anliegen im Widget, Betreff-Gruppe Interior der Kontaktseite.
|
||
- Seitentitel von `/marken` nennt die vierte Marke.
|
||
- Lang-Fallback (`core_brands.brands`) um die Tischlerei ergänzt.
|
||
|
||
**Lokal ausgeführt:** `php artisan db:seed --class=CmsBrandSeeder` (legt nur die fehlende Marke an).
|
||
Beim Deployment mit erledigen (Abschnitt 8).
|
||
|
||
**Was Marcel nachträgt (alles im Admin):** Name der Marke, Logo, Stimmungsbild, echte Texte –
|
||
die Platzhalter sind bewusst so geschrieben, dass sie ohne Änderung nicht live gehen sollten
|
||
(„Tischlerei“ ist kein Markenname). Slug `tischlerei` bleibt stabil, auch wenn der Name kommt.
|
||
|
||
**Tests:** `tests/Feature/FourthBrandTest.php` (7 Fälle).
|
||
|
||
---
|
||
|
||
## Nachtrag 10 · Herkunfts-Sektion „Aus der Region gefertigt“ (15.09.2026)
|
||
|
||
Arbeitsplan 14.09., Punkt 1.3. Die Klärung „CABINET Hersteller oder Vertrieb“ kam am 15.09. von
|
||
Kevin nach seinem Verständnis: CABINET **fertigt selbst in Köln** und **vertreibt über die
|
||
CABINET Stores**; der Store Bielefeld ist einer davon. Dort laufen Beratung und Planung für
|
||
Bielefeld und Umkreis, gefertigt wird in Köln, aufgebaut beim Kunden – und hier kommt die
|
||
Tischlerei ins Spiel, die den Aufbau übernimmt und Sonderwünsche umsetzt. ⚠️ **Von Marcel
|
||
bestätigen lassen** (bietet CABINET selbst Aufbau an? Läuft der Aufbau immer über die eigene
|
||
Tischlerei?). Die Sektion ist so formuliert, dass sie diesem Verständnis folgt.
|
||
|
||
### Aufbau
|
||
|
||
- **Neue Sektion `origin_section`** (`OriginSection`, CMS-Gruppe `home`), eingebunden auf der
|
||
Startseite zwischen Kernmarken und „Gebaut auf Expertise“ sowie auf `/marken` zwischen
|
||
Markenübersicht und „Mehr als Marken: unser Netzwerk“. Anker `#herkunft`.
|
||
- **Schematische Karte** (SVG, ab `md`): Bielefeld als Drehscheibe in Ocker, die vier Standorte
|
||
als Punkte in Tanne mit gestrichelten Speichen und Entfernungsangabe, gestrichelte Ellipse
|
||
„Ostwestfalen“ um die drei OWL-Standorte. Keine Geografie, nur Richtung und Entfernung.
|
||
Positionen und Beschriftungsseite lagen zunächst im Inhalt; seit Nachtrag 11 stehen sie im
|
||
Code, die Standorte kommen aus den Marken. Unter `md` entfällt die Karte, die Kacheln tragen alles.
|
||
- **Vier Standort-Kacheln** (2×2 ab `sm`): Stadt, Marke, Rolle, Entfernung „von Bielefeld“ und
|
||
Link „Zur Marke“. Ursprünglich lagen die Standorte im Sektions-JSON, der Link kam aus den
|
||
veröffentlichten Marken. Seit Nachtrag 11 gilt: Standort = Marke, siehe dort.
|
||
- **Ablauf-Block „Gefertigt in Köln, geplant in Bielefeld“**: drei nummerierte Schritte am
|
||
Beispiel CABINET (Beratung und Planung in Bielefeld → Fertigung in Köln → Aufbau vor Ort mit
|
||
Sonderwünschen aus der Tischlerei). Das ist die saubere Trennung „gefertigt“ / „vertrieben“
|
||
aus dem Plan. Entfällt, wenn `steps` im CMS leer ist.
|
||
- **Entfernungen** gerundet, Straße ab Bielefeld Mitte: Herford rund 20 km, Bünde rund 30 km,
|
||
Rheda-Wiedenbrück rund 35 km, Köln rund 200 km. Bei Bedarf im Admin anpassen.
|
||
- Styles `.origin-map-*` in `shared-styles.css` (Token-basiert, in beiden Welten gültig, die
|
||
Sektion liegt aber nur in der Interior-Welt). Build `npm run build:b2in` ausgeführt.
|
||
|
||
**Lokal ausgeführt:** `php artisan db:seed --class=OriginSectionCmsSeeder` (legt nur an, was
|
||
fehlt, überschreibt nichts). Beim Deployment mit erledigen (Abschnitt 8, Schritt 9).
|
||
|
||
**Offen:** Bestätigung des CABINET-Ablaufs durch Marcel; Wortlaut der Tischlerei-Kachel folgt
|
||
dem Platzhalter aus Nachtrag 9 und wandert mit dem echten Markennamen.
|
||
|
||
**Tests:** `tests/Feature/OriginSectionTest.php` (12 Fälle, mit Nachtrag 11 umgeschrieben).
|
||
|
||
---
|
||
|
||
## Nachtrag 11 · Standorte an der Marke, Marken in der Sidebar (15.09.2026)
|
||
|
||
Prüfung der Inhaltspflege im Admin auf Kevins Frage, ob Marken wie das Magazin einen eigenen
|
||
Punkt brauchen. Ergebnis: **Die Markenverwaltung gab es schon** („Kernmarken verwalten“, AP2),
|
||
sie war nur nicht in der Sidebar verlinkt – erreichbar allein über die Kachel auf der
|
||
CMS-Übersicht. Die Herkunfts-Sektion aus Nachtrag 10 lag dagegen komplett im generischen
|
||
Inhalte-Editor, inklusive der Kartenkoordinaten `x`/`y` und der Beschriftungsseite als nackte
|
||
Felder. Das war für Marcel nicht pflegbar. Abgestimmt mit Kevin: **Weg 1**, Standort an die Marke.
|
||
|
||
### Was sich ändert
|
||
|
||
- **Sidebar:** neuer Eintrag „Marken“ unter CMS → Website-Inhalte, zwischen Projekte und
|
||
Magazin. Die Gruppe klappt auf der Markenseite jetzt auch auf.
|
||
- **Drei neue Felder je Marke** (Migration `add_origin_to_cms_brands_table`, übersetzbar wie die
|
||
übrigen Textfelder): `origin_city` (Fertigungsort), `origin_distance` (Entfernung als Text,
|
||
„rund 30 km“), `origin_role` (ein Satz zur Rolle). Im Admin als Block „Fertigungsort“ unter
|
||
den Stammdaten, mit Hinweis: ohne Ort erscheint die Marke nicht in der Sektion.
|
||
- **`OriginSection` liest die Standorte aus `CmsBrand::forFrontend()`**: nur veröffentlichte
|
||
Marken mit Ort, in der Reihenfolge der Marken. Eine unveröffentlichte Marke fällt damit ganz
|
||
heraus (vorher blieb ihr Standort ohne Link stehen – jetzt gibt es keinen Standort ohne
|
||
Marke mehr). Der Link „Zur Marke“ hängt an `has_detail_page`, der Text `link_text` liegt
|
||
einmal auf Sektionsebene statt je Standort.
|
||
- **Kartenpositionen im Code:** `OriginSection::MAP_POSITIONS`, je Slug `x`/`y`/`label`. Eine
|
||
neue Marke mit Ort, aber ohne Position, erscheint in den Kacheln, nicht in der Karte – dafür
|
||
muss ein Entwickler eine Position ergänzen. Das ist gewollt: die Karte ist Zeichnung, kein
|
||
Inhalt.
|
||
- **Sektions-JSON `home/origin_section`** enthält nur noch Überschrift, Untertitel, Alt-Text,
|
||
Regionslabel, Entfernungs-Suffix, Drehscheibe, Link-Text und Ablauf-Block. Der alte Schlüssel
|
||
`locations` wird von `OriginSectionCmsSeeder` aus einem bestehenden Eintrag entfernt, damit er
|
||
im Inhalte-Editor nicht mehr als Pflegefeld auftaucht (idempotent, sonst weiterhin nur
|
||
anlegen-wenn-fehlt).
|
||
- **Lang-Fallback:** die vier Einträge in `core_brands.brands` tragen jetzt `slug` und die drei
|
||
Herkunftsfelder, damit die Sektion auch ohne gepflegte Marke steht – dann ohne Links, wie die
|
||
Kacheln der Kernmarken.
|
||
- **Seeder:** `CmsBrandSeeder` bringt die Herkunft für frische Installationen mit; neu
|
||
`BrandOriginSeeder` trägt sie bei bestehenden Marken nach, nur wenn der Ort leer ist (Muster
|
||
wie `BrandLogoSeeder`). Keine Dubletten möglich, beide arbeiten über den Slug.
|
||
- Ohne Marke mit Ort bleiben Überschrift und Ablauf-Block stehen, Karte und Kacheln entfallen.
|
||
|
||
**Lokal ausgeführt:** `php artisan migrate`, `db:seed --class=BrandOriginSeeder` (4 gesetzt),
|
||
`db:seed --class=OriginSectionCmsSeeder` (`locations` entfernt). Beim Deployment: Abschnitt 8,
|
||
Schritte 9 und 10, die Migration läuft mit `migrate` vorweg.
|
||
|
||
**Offen:** wie Nachtrag 10 (Bestätigung des CABINET-Ablaufs durch Marcel). Der generische
|
||
Inhalte-Editor bleibt für die übrigen Sektionen ohne Schema; wo Listen mit technischen Feldern
|
||
auftauchen, ist derselbe Weg möglich: Daten an ein Modell hängen, Darstellung in den Code.
|
||
|
||
**Tests:** `tests/Feature/OriginSectionTest.php` (15 Fälle), drei neue Fälle in
|
||
`tests/Feature/Admin/Cms/CmsBrandsIndexTest.php` (Herkunft je Sprache speichern, Ort leeren,
|
||
Sidebar-Link).
|
||
|
||
---
|
||
|
||
## Nachtrag 12 · Inhalte-Editor: Seitenbaum und Vorschau (15.09.2026)
|
||
|
||
Kevins Rückmeldung nach der Prüfung des CMS: der Punkt „Inhalte“ zeigt Datenbank-Gruppen
|
||
alphabetisch, ohne Bezug zur Seite, mit JSON-Schlüsseln als Beschriftung – zu abstrakt für
|
||
Marcel. Abgestimmt: Stufe 1 (Seitenbaum, Klartext) und Stufe 2 (Vorschau im Rahmen) umsetzen,
|
||
Stufe 3 (Stift-Markierungen in der Vorschau, die den Editor öffnen) erst nach Marcels Feedback.
|
||
|
||
### Stufe 1 · Seitenbaum statt Gruppen
|
||
|
||
- **Registry `config/cms_pages.php`:** je Seite (Startseite, Marken, Referenzen, Magazin, Über
|
||
uns, Kontakt, FAQ, „Auf jeder Seite“, Immobilien-Welt, Rechtliches) die Sektionen in der
|
||
Reihenfolge, wie sie auf der Website stehen, mit Titel, einem Satz Beschreibung, Pfad und
|
||
Sprungmarke. Dazu ein Wörterbuch `field_labels` (`button_text` → „Button-Beschriftung“,
|
||
`x`/`y` → „Position (Entwickler)“ …), je Sektion überschreibbar über `fields`.
|
||
- **`App\Services\CmsPageTree`** verbindet die Registry mit der Datenbank: welche Sektion
|
||
existiert (`content_id`), welche fehlt, was in der Datenbank liegt, aber auf keiner Seite
|
||
eingetragen ist. Letzteres landet als Sammelpunkt **„Nicht mehr verwendet“** ganz unten
|
||
(Netzwerk-, Partner- und alte Immobilien-Sektionen, `home/synergie_section` & Co.) – nichts
|
||
geht verloren, nichts steht im Weg.
|
||
- **Editor (`admin.cms.content-index`):** linke Spalte zeigt den Seitenbaum, nummeriert von
|
||
oben nach unten. Ein Klick wählt genau eine Sektion (`selectSection`), der Kopf zeigt Titel,
|
||
Beschreibung, Seite und den technischen Schlüssel klein darunter. Felder tragen die
|
||
Klartext-Beschriftung, der Schlüssel steht als `code` daneben; Typ-Badges heißen „Text“,
|
||
„Formatierter Text“, „Bild“, „Liste“. Der Listen-Editor (Overlay) beschriftet seine Felder
|
||
genauso. `selectGroup` bleibt für die Gruppenansicht erhalten.
|
||
- **Fehlende Sektion anlegen:** steht eine Sektion in der Registry, aber nicht in der
|
||
Datenbank (heute z. B. das Terminanfrage-Widget), erscheint sie grau mit „+“. Ein Klick
|
||
legt sie über `CmsContentSeeder` mit den Texten aus `b2in.php` an. Rechtliches und die
|
||
Kontaktdaten (`global/contact`) haben keine Vorlage, dort erscheint ein Hinweis.
|
||
|
||
### Stufe 2 · Vorschau
|
||
|
||
- Rechts neben dem Editor ein **iframe mit der echten Website** (Domain aus
|
||
`config('domains')`, Pfad der Seite, `?cms-preview=<n>` als Cache-Brecher, `#anker`). Beim
|
||
Wechsel der Sektion springt die Vorschau zur Sprungmarke, nach jedem Speichern lädt sie
|
||
neu (`previewVersion`). Buttons: neu laden, in neuem Tab öffnen, Vorschau aus/ein.
|
||
Keine Anmeldung nötig, die Website ist öffentlich; Frame-Header setzt die App keine.
|
||
- **Sprungmarken nachgezogen:** `id` an den Wurzelelementen der lebenden Sektionen (`hero`,
|
||
`gruender`, `wege`, `marken`, `herkunft`, `vision`, `engagement`, `displays`, `immobilien`,
|
||
`cta`, `seitenkopf`, `netzwerk`, `wachstum`, `marken-cta`, `projekte`, `magazin`,
|
||
`geschichte`, `bild`, `werte`, `kontakt`, `faq`, `header`, `footer`). Beim Display-Feed
|
||
sitzt der Anker am Wurzel-`div`, weil die Sektion ohne veröffentlichtes Display leer bleibt.
|
||
- Sektionen ohne Seite (Beitragsseite, Widget, Rechtliches) zeigen die Seite ohne Sprung.
|
||
|
||
### Erkenntnisse beim Kartieren
|
||
|
||
- `/immobilien` rendert `web/dev/immobilien-azizi.blade.php` mit statischen Texten aus
|
||
`immobilien-azizi.json`; die CMS-Sektionen `immobilien/hero`, `warum_dubai`, `kaufprozess`
|
||
usw. gehören zur stillgelegten `web/immobilien.blade.php` und stehen deshalb unter „Nicht
|
||
mehr verwendet“. Gleiches gilt für `about/leadership_team`.
|
||
- `display_feed` liegt in der Gruppe `referenzen`, steht aber zuerst auf der Startseite –
|
||
im Baum unter Startseite mit Hinweis auf /referenzen.
|
||
|
||
**Tests:** `tests/Feature/Cms/CmsPageTreeTest.php` (9 Fälle, darunter: jede Sprungmarke der
|
||
Registry existiert auf der jeweiligen Seite, jede Sektion mit Vorlage ist in `b2in.php`
|
||
auffindbar) und sechs neue Fälle in `tests/Feature/Cms/CmsAdminTest.php` (Seitenbaum,
|
||
Sektion wählen mit Klartext-Labels und Vorschau-Adresse, Sammelpunkt, Anlegen aus Vorlage,
|
||
Anlegen ohne Vorlage, Vorschau ausblenden). Kein Deployment-Schritt nötig: Registry und
|
||
Editor sind Code, die Datenbank bleibt unverändert.
|
||
|
||
**Offen:** Stufe 3 nach Marcels Rückmeldung. Neue Sektionen müssen in `cms_pages.php`
|
||
eingetragen werden, sonst landen sie unter „Nicht mehr verwendet“ – als Erinnerung steht das
|
||
im Kopf der Datei.
|
||
|
||
---
|
||
|
||
## Nachtrag 13 · Referenzen als eigenes Modul, Immobilien-Projekte ausgeblendet (15.09.2026)
|
||
|
||
Kevin nach der Abnahme von Nachtrag 12: „Projekte“ im Portal (die Immobilienprojekte aus
|
||
Dubai) ist nicht freigegeben und kommt raus; an die Stelle gehören die Projekte/Referenzen der
|
||
Interior-Welt. Das ist eine **Korrektur zu AP5**, das die Referenzen bewusst aus den
|
||
Markengalerien zusammengesammelt hatte, um keine zweite Pflegestelle zu schaffen. Ein
|
||
realisiertes Projekt hat aber mehr als ein Bild und oft mehr als eine Marke (CABINET plus
|
||
Tischlerei), darum jetzt ein eigener Eintrag.
|
||
|
||
### Was sich ändert
|
||
|
||
- **Neues Modell `CmsReference`** (Tabelle `cms_references`): Titel und Beschreibung
|
||
übersetzbar, Ort und Jahr als Text, Titelbild, weitere Bilder mit Bildunterschrift,
|
||
beteiligte Marken als Liste von Slugs aus `cms_brands`, Veröffentlicht, Sortierung.
|
||
- **Portal → CMS → „Referenzen“** (`admin.cms.references-index`, Route
|
||
`cms.references.index`): Liste mit Vorschaubild, Marken-Badges und Bildanzahl; Formular
|
||
nach dem Muster des Magazins mit Sprachumschalter, Marken als Checkboxen, Titelbild und
|
||
Galerie über den Media-Picker, Galeriebilder sortierbar. Der Kopf der Seite sagt die Regel:
|
||
nur ausgeführte Aufträge, Entwürfe gehören in die Galerie der Marke.
|
||
- **Sidebar und CMS-Übersicht:** „Referenzen“ ersetzt „Projekte“. Die Route
|
||
`cms.projects.index` bleibt bestehen und ist per Adresse erreichbar, nur nicht mehr
|
||
verlinkt – die Dubai-Daten bleiben unangetastet, falls die Freigabe später kommt.
|
||
- **`/referenzen`** zeigt die veröffentlichten Referenzen: Titelbild, Titel, „Ort · Jahr“,
|
||
Beschreibung, weitere Bilder als kleine Reihe, darunter die beteiligten Marken verlinkt auf
|
||
ihre Markenseiten (unveröffentlichte Marken fallen heraus). Ohne Titelbild dient das erste
|
||
Galeriebild als Titelbild, ohne jedes Bild wird die Referenz übersprungen.
|
||
- **Fallback bleibt:** Solange keine Referenz veröffentlicht ist, greift der Stand aus AP5
|
||
(Bilder der Rubrik „Realisiertes Projekt“ aus den Markengalerien). Der Leerzustand von AP5
|
||
gilt weiter, wenn beides leer ist. So sieht die Preview beim Deployment keinen Unterschied,
|
||
bis Marcel die erste Referenz anlegt.
|
||
- Registry `cms_pages.php`: Beschreibung von „Realisierte Projekte“ verweist auf das neue Modul.
|
||
|
||
**Deployment:** nur `php artisan migrate --force` (Abschnitt 8.2, Schritt 1 deckt die neue
|
||
Tabelle ab). Kein Seeder, keine Daten.
|
||
|
||
**Offen:** Marcel legt die ersten Referenzen selbst an; die bisherigen Galeriebilder der Marken
|
||
bleiben dort, wo sie sind. Ob die Bilder aus den Markengalerien später automatisch als Referenz
|
||
übernommen werden sollen, klärt sich mit den ersten echten Einträgen.
|
||
|
||
**Tests:** `tests/Feature/Admin/Cms/CmsReferencesIndexTest.php` (9 Fälle), vier neue Fälle in
|
||
`tests/Feature/ReferenzenPageTest.php` (Referenzen vor Galerien, Entwurf ausgeblendet und
|
||
Fallback, unveröffentlichte Marke und Referenz ohne Bild, Galeriebild als Titelbild),
|
||
Dashboard-Statistik in `CmsAdminTest` auf Referenzen umgestellt.
|
||
|
||
---
|
||
|
||
## Nachtrag 14 · Bilddauer im b2in-Display mit Nachkommastelle (17.09.2026)
|
||
|
||
Kevins Wunsch: Im Store-Display-Modul „b2in Display“ soll die „Dauer (Sekunden)“ eines Bildes
|
||
auch 1,5 annehmen. Das Feld war ganzzahlig (`int`, Zahlenfeld mit `min=1`).
|
||
|
||
- **Eingabe als Text** mit Dezimal-Tastatur: „10“, „1,5“ und „1.5“ sind gültig, Leerzeichen
|
||
egal, gerundet auf Zehntel. Erlaubt sind 0,5 bis 120 Sekunden; alles andere bringt beim
|
||
Speichern eine Fehlermeldung am Feld und speichert nichts. Bei Videos wird das Feld ignoriert.
|
||
- **Gespeichert wird eine Zahl** (`duration_seconds` = 1.5). Der Player in
|
||
`public/_cabinet/b2in/index.html` rechnet ohnehin `duration_seconds × 1000`, kommt also ohne
|
||
Änderung mit 1500 ms klar. Bestehende Einträge mit ganzen Sekunden bleiben unverändert.
|
||
- Anzeige in der Eintragsliste mit Komma („1,5s“), ganze Zahlen ohne Nachkommastelle.
|
||
- Doku `public/_cabinet/_docs/b2in-displays.md` ergänzt.
|
||
|
||
**Tests:** vier neue Fälle in `tests/Feature/DisplayVersionTest.php` (Komma-Eingabe,
|
||
Parser/Formatierer, Ablehnung unter 0,5 s, Video ignoriert das Feld). Kein Deployment-Schritt.
|
||
|
||
---
|
||
|
||
## Nachtrag 15 · Otterpohl als vierte Marke, Feedback 17.09. eingearbeitet (17.09.2026)
|
||
|
||
Zulieferung 17.09.2026: `dev/2026-08-28/otterpohl_Webseitentext_FINAL.md` (Text der
|
||
Tischlerei-Seite), `dev/2026-08-28/markenlogos/otterpohl.jpg` (Logo) und
|
||
`dev/2026-08-28/feedback-17-09-2026.md` (Marcels Rückmeldung zu CABINET, Febrü und Rotpunkt).
|
||
|
||
### Otterpohl ersetzt den Platzhalter „Tischlerei“
|
||
|
||
- **Marke:** Name „Otterpohl“, Claim „Nicht easy to click & buy. Aber easy to get.“, Kacheltext,
|
||
Text für /marken, drei Merkmale, Einleitung (erster Block des Textes), vier Leistungen, **13
|
||
Abschnitte** mit den Überschriften der Zulieferung 1:1, die pointierten Schlusssätze als
|
||
Schlusszeile je Abschnitt, Abschlussblock „Ihre Idee. Handwerklich umgesetzt.“, Fertigungsort
|
||
Rheda-Wiedenbrück mit Rolle „seit 2014 an unserer Seite“. Slug `tischlerei` bleibt (Links,
|
||
Widget-Thema, Kartenposition).
|
||
- **Logo:** `public/img/assets/marken/otterpohl.png`, aus der JPG-Zulieferung freigestellt und
|
||
knapp beschnitten (Imagick), damit es in der gemeinsamen Logo-Box wie die anderen wirkt.
|
||
Das Logo trägt „25 Jahre“ – so geliefert, so übernommen.
|
||
- **Seeder:** neu `OtterpohlBrandSeeder` (überschreibt bei der bestehenden Marke alle Textfelder,
|
||
lässt Bild, Galerie und Reihenfolge stehen, Logo nur wenn leer); `CmsBrandSeeder` nutzt
|
||
dieselben Daten für frische Installationen; `BrandLogoSeeder` und `BrandOriginSeeder` kennen
|
||
die Marke. Lang-Fallback, Seitentitel von /marken und der Ablauf-Block der Herkunfts-Sektion
|
||
nennen jetzt Otterpohl.
|
||
|
||
### Feedback 17.09. in den Markentexten (`BrandPageTextSeeder`)
|
||
|
||
- **CABINET:** Der Abschnitt „Aufmaß vor Ort statt Schätzung am Telefon“ widersprach Marcels
|
||
Ablauf (erst Foto und grobes Maß, Aufmaß erst nach Angebot). Ersetzt durch „Ein Bild und ein
|
||
grobes Maß reichen für den Anfang“ mit Marcels Fassung wörtlich und der Ablaufzeile
|
||
„So läuft’s: Foto + grobe Maße → … → Bestellung“ als Schlusszeile. Zweiter Absatz von
|
||
„Die Fragen, die wir vorher stellen“ ersetzt (Karnevalskostüme, Sportsachen).
|
||
- **Febrü:** nur die vereinbarten Stellen: „Bei uns gibt es Kunden – keine Schubladen“ (drei
|
||
Absätze), „Aus Herford“ mit „sehr hohe Fertigungstiefe“ statt 95 Prozent, „Wertschätzung ist
|
||
keine Frage der Stückzahl“ (Familienalltag statt Mütter-Passage). Der doppelte Schlusssatz
|
||
„Ob im Kleinen oder im Großen …“ steht nur noch beim ersten Abschnitt. „Nicht drei Marken“,
|
||
„Das Wir und das Ich“ und der mitlaufende CTA unverändert.
|
||
- **Rotpunkt:** „Mehr als Küchen“ mit Marcels drei Absätzen ersetzt.
|
||
- **Handwerk als gemeinsamer Abschluss (Punkt 3b):** Die markeneigenen Abschnitte
|
||
„Schranksystem plus Handwerk“ (CABINET) und „Küchenstudio plus Handwerk“ (Rotpunkt) sind
|
||
entfallen. Stattdessen gibt es **eine** Sektion `brand_craft` („Planung plus Handwerk“, Lang-
|
||
Datei, im Inhalte-Editor unter Marken → „Handwerk-Abschluss auf jeder Markenseite“ anlegbar),
|
||
die `BrandDetail` als letzten Abschnitt auf jeder Markenseite anhängt – außer auf der
|
||
Otterpohl-Seite selbst. Der Link „Mehr zu Otterpohl“ erscheint nur, wenn die Marke
|
||
veröffentlicht ist. Anker `#handwerk`. Einmal gepflegt, überall gleich – genau wie gewünscht.
|
||
|
||
**Lokal ausgeführt:** `OtterpohlBrandSeeder`, `BrandPageTextSeeder`, `BrandLogoSeeder`.
|
||
Beim Deployment: Abschnitt 8.2, Schritt 4 (Feedback) und Schritt 11 (Otterpohl).
|
||
|
||
**Offen:** Stimmungsbild und Galerie für Otterpohl (im Admin nachtragen); Nachtrag 10 bleibt
|
||
offen, ob CABINET selbst Aufbau anbietet. Der Text bestätigt Rheda-Wiedenbrück und die
|
||
Montage-Partnerschaft seit 2014 – die Herkunfts-Sektion passt damit.
|
||
|
||
**Tests:** `tests/Feature/BrandFeedbackTest.php` (10 Fälle: CABINET-Einstieg und Fragen, Febrü-
|
||
Passagen und einmaliger Schlusssatz, Rotpunkt „Mehr als Küchen“, Handwerk-Abschluss auf drei
|
||
Seiten mit Link und Position, nicht auf Otterpohl, ohne Link bei unveröffentlichter Marke,
|
||
CMS-Vorrang, Otterpohl-Seeder behält Logo/Bild/Reihenfolge); `FourthBrandTest`,
|
||
`MarkenPageTest` und `BrandPageSectionsTest` auf die neuen Texte umgestellt.
|
||
|
||
---
|
||
|
||
## Nachtrag 16 · Erste Bilder für CABINET und Rotpunkt (22.09.2026)
|
||
|
||
Zulieferung 22.09.2026 unter `dev/2026-08-28/images/{cabinet,rotpunkt}/`, das Titelbild je
|
||
Marke mit `_title_` markiert. 12 Bilder CABINET, 14 Bilder Rotpunkt, alles Visualisierungen des
|
||
Herstellers (Renderings), 3–6 MB je Datei.
|
||
|
||
- **Optimierung:** alle Bilder als WebP mit maximal 1920 px Kantenlänge, Qualität 82, ohne
|
||
Metadaten (Imagick) nach `public/img/assets/marken/cabinet/` und `…/rotpunkt/`; 55–330 KB je
|
||
Datei statt mehrerer MB. Sprechende Dateinamen aus den Motiven („dachschraegenschrank-filo-
|
||
cashmere.webp“, „kueche-07.webp“). Die Originale bleiben per `.gitignore` außerhalb des
|
||
Repositorys, nur die WebP-Fassungen werden deployt.
|
||
- **Titelbild** (`image`): CABINET „Ankleide Solitär, Eiche Tano“, Rotpunkt „Küche 01“. Es
|
||
erscheint im Seitenkopf der Markenseite, auf der Startseiten-Kachel und im Markenblock auf
|
||
/marken – dort, wo bisher der Platzhalter stand.
|
||
- **Galerie:** die übrigen Bilder als **Visualisierung** mit Bildunterschrift aus dem Motiv.
|
||
Die Rubrik passt: Badge „Visualisierung“, Hinweis „Entwürfe und Visualisierungen“. Unter
|
||
„Referenzen“ erscheinen sie damit bewusst nicht – das sind keine von uns ausgeführten Projekte.
|
||
Marcel kann jedes Bild im Admin umkategorisieren, sobald ein echtes Projekt dahintersteht.
|
||
- **`BrandImageSeeder`:** Titelbild nur, wenn keins gepflegt ist; Galeriebilder nur, wenn die
|
||
Datei noch nicht in der Galerie steht; vorhandene Einträge bleiben samt Kategorie und
|
||
Unterschrift. Mehrfach ausführbar. Febrü und Otterpohl bleiben unberührt (keine Zulieferung).
|
||
|
||
**Lokal ausgeführt:** `php artisan db:seed --class=BrandImageSeeder`. Beim Deployment:
|
||
Abschnitt 8.2, Schritt 12 – die Dateien kommen mit dem Repository.
|
||
|
||
**Ergänzung 23.09.2026:** Febrü nachgeliefert (`dev/2026-08-28/images/februe/`, 16 Bilder,
|
||
Titelbild „Base Thekenlösung“). Gleiche Behandlung, Bildunterschriften nach den Febrü-
|
||
Produktlinien aus den Dateinamen („Active 2.0 mit Bureo“, „Arena Stage“, „Vio“ …). Der Seeder
|
||
und `BrandImageSeederTest` decken jetzt drei Marken ab.
|
||
|
||
**Offen:** Bilder für Otterpohl; Freigabe der Bildunterschriften durch Marcel
|
||
(aus den Dateinamen abgeleitet, z. B. Frontdekore „Filo Cashmere“, „Velluto Fango“, bei Febrü
|
||
die Produktlinien).
|
||
|
||
**Tests:** `tests/Feature/BrandImageSeederTest.php` (4 Fälle: Titelbild und Galerie, jede
|
||
referenzierte Datei existiert als optimierte Datei unter 400 KB und 1920 px, zweiter Lauf
|
||
lässt Gepflegtes stehen, Anzeige auf Startseite, /marken, Markenseite und nicht unter Referenzen).
|
||
|
||
---
|
||
|
||
## Nachtrag 17 · Demobilder raus, Galerie ohne Rubrikwechsel (22.09.2026)
|
||
|
||
Abstimmung 22.09. nach den ersten echten Bildern: die Demobilder aus AP2 müssen weg, der
|
||
Rubrikwechsel „Realisierte Projekte / Inspirationen“ ist ausgesetzt, solange es keine
|
||
realisierten Projekte gibt, und die zwei Zeilen unter der Galerie-Überschrift werden eine.
|
||
|
||
- **`DemoBrandGalleryCleanupSeeder`** entfernt die elf Demobilder (CABINET 4, Rotpunkt 3, Febrü
|
||
4) aus den Galerien. Erkennung am Dateinamen aus `DemoBrandGallerySeeder`, nicht an der
|
||
Unterschrift – den Vermerk „BEISPIEL“ hatte Schritt 5 auf der Vorschau bereits entfernt.
|
||
Alle anderen Bilder bleiben. Idempotent.
|
||
- **Galerie** auf der Markenseite: ein Raster, realisierte Projekte zuerst, jedes Bild trägt
|
||
weiter sein Badge („Realisiertes Projekt“ / „Visualisierung“). Kein Tab-Wechsel, keine
|
||
Gruppenüberschriften, kein separater Hinweistext. Die Kategorie im Admin bleibt bestehen,
|
||
der Wechsel lässt sich wieder einschalten, sobald echte Projekte da sind.
|
||
- **Texte:** Überschrift „Inspirationen und Entwürfe“, eine Zeile darunter: „Visualisierungen,
|
||
die zeigen, was in einem Raum möglich ist – noch bevor das erste Möbel steht.“ (vorher
|
||
„Referenzen und Inspirationen“ plus Hinweis unter der Rubrik).
|
||
|
||
**Lokal ausgeführt:** `php artisan db:seed --class=DemoBrandGalleryCleanupSeeder` (11 entfernt).
|
||
Beim Deployment: Abschnitt 8.2, Schritt 13, nach Schritt 12.
|
||
|
||
**Tests:** `BrandPageTest` umgestellt (ein Raster mit Badges und Projekten zuerst, genau eine
|
||
Zeile unter der Überschrift, Aufräum-Seeder entfernt nur Demobilder und ist idempotent).
|
||
|
||
## Nachtrag 18 · WhatsApp zuerst, Business-Nummer, Farbvariante „Modern“ (23.09.2026)
|
||
|
||
Rückmeldung von Marcel über Kevin am 23.09.: Im Termin-Widget soll WhatsApp oben stehen und das
|
||
Formular darunter; als Nummer gilt die Business-Nummer 0521-98620100 (am 23.09. kam zunächst
|
||
…98610020, Korrektur von Marcel am 24.09.). Außerdem wirkt ihm die
|
||
Farbwelt „zu altbacken“ – die beigen Flächen. Gewünscht ist eine klarere, modernere Variante, die
|
||
farblich am Logo bleibt (Tanne und Ocker unverändert), sowie ein schwimmender Schalter, um beide
|
||
Stände direkt zu vergleichen.
|
||
|
||
### Termin-Widget
|
||
|
||
- **Reihenfolge:** WhatsApp-Block direkt unter der Einleitung, darunter eine Trennzeile „oder per
|
||
Formular“, dann das Formular. Einleitung jetzt „Am schnellsten per WhatsApp – wir bereiten die
|
||
Nachricht mit Ihren Angaben vor.“ Der Hinweis, dass der Besucher selbst abschickt, bleibt.
|
||
Der vorbereitete Text liest weiter Anliegen, Wunschtermin und Name aus dem Formular, auch wenn
|
||
es jetzt unter dem Button steht. Ohne Nummer im CMS erscheint weder Button noch Trennzeile.
|
||
- **Nummer:** `WhatsappNumberSeeder` trägt `+49 521 98620100` in `global.contact.whatsapp` ein
|
||
(de und en), aber nur, wenn das Feld leer ist, noch den Platzhalter „+49 151 00000000“ aus der
|
||
ersten Einrichtung enthält oder die falsche Nummer vom 23.09. (`+49 521 98610020`) – die hatte
|
||
Marcel versehentlich geschickt, auf der Vorschau lief der Button deshalb ins Leere. Eine im
|
||
Admin gepflegte andere Nummer bleibt stehen. Fehlt der Eintrag, wird er angelegt. Idempotent.
|
||
Ergebnis-Link: `https://wa.me/4952198620100`. Auf einer Vorschau ohne Portal reicht
|
||
`php artisan db:seed --class=WhatsappNumberSeeder --force`.
|
||
|
||
### Farbvariante „Modern“
|
||
|
||
Eine zweite Interior-Palette als Override in `theme-b2in.css` (`.palette-modern .world-interior`).
|
||
Sie ändert **nur Flächen**, keine Logofarben:
|
||
|
||
| Token | Bisher (Creme) | Modern |
|
||
|---|---|---|
|
||
| Hintergrund | Creme `#f7f4ef` | fast weiß, leicht warm `#fbfaf8` |
|
||
| Karten | `#fbf9f5` | reinweiß |
|
||
| Sektionswechsel (`bg-accent`) | Sand `#d9cbbf` | helles Grau-Beige `#efece7` |
|
||
| Ruhige Flächen (`bg-muted`) | helles Sand | `#f2f0ed` |
|
||
| Linien / Eingabefelder | Sand-Töne | `#e6e2dc` / weiß |
|
||
| Hero-Bühne | Sand | helles Grau-Beige |
|
||
| Footer | Sand mit Tanne | Tanne mit Creme, Ocker als Akzent |
|
||
| Tanne, Ocker, Clay, dunkle Sektionen, CTA-Band | unverändert | unverändert |
|
||
|
||
Karten liegen jetzt weiß auf fast weiß, deshalb haben `--shadow-card` und `--shadow-elevated` in
|
||
der Variante etwas mehr Tiefe. Weil der Footer dunkel ist, trägt er in „Modern“ das **negative
|
||
Logo** (Rückmeldung Kevin 23.09.): der Footer rendert beide Logos (`footer-logo-light` /
|
||
`footer-logo-dark`), das Stylesheet blendet je Palette das passende ein – die Umschaltung läuft
|
||
im Browser, ohne Server-Roundtrip. Die Immobilien-Welt bleibt bei ihrem einen negativen Logo.
|
||
Zwei Nachbesserungen nach dem ersten Blick (Kevin 23.09.): Abschlussband und Footer sind in
|
||
„Modern“ beide dunkel, deshalb trennt eine helle Haarlinie (`--footer-muted` bei 35 %) den Footer
|
||
oben ab. Und der schwebende Termin-Button war als reine Kontur über Bildern und weißen Karten
|
||
kaum zu sehen – er trägt jetzt in beiden Paletten eine Fläche in Kartenfarbe
|
||
(`.appointment-toggle`), Hover bleibt Tanne.
|
||
|
||
Dritte Nachbesserung (Kevin 23.09.): der **Cookie-Button** unten links kam noch in Blau aus
|
||
`config/cookie-consent.php` – das ist die Immobilien-Welt. `theme-b2in.css` überschreibt die
|
||
Paketvariablen (`--cc-*`) für `.world-interior`: Button in Tanne mit dem Verlauf des
|
||
Akzent-Buttons, Icon, Schalter, Fokusring und Link-Hover in Ocker, „Speichern“ in Tanne,
|
||
„Akzeptieren“ bleibt grün. Gilt in beiden Paletten; `/immobilien` behält das Blau. Der dunkle Footer ist die eine bewusste Abweichung, die über
|
||
„heller“ hinausgeht: er gibt der hellen Seite unten einen klaren Abschluss. Wenn Marcel ihn
|
||
lieber hell hätte, sind es vier Token.
|
||
|
||
### Schalter
|
||
|
||
- `<x-palette-switch />` schwimmt links in der Mitte (unten links sitzt der Cookie-Button, unten
|
||
rechts das Termin-Widget): eine senkrechte Pille „Farbwelt · Bisher / Neu“. Nur auf den
|
||
Interior-Seiten von b2in, nicht auf `/immobilien`.
|
||
- Die Wahl liegt im `localStorage` (`b2in-palette`) und wird schon im `<head>` gesetzt, bevor das
|
||
Stylesheet greift – kein Aufblitzen in Creme. `?palette=modern` bzw. `?palette=classic` an einer
|
||
URL überschreibt die gemerkte Wahl; damit lässt sich Marcel ein Link auf die neue Variante
|
||
schicken: `https://<vorschau>/?palette=modern`.
|
||
- Abschalten, sobald entschieden ist: `B2IN_PALETTE_SWITCH=false` in `.env`
|
||
(`config('app.palette_switch')`). Dann erscheint weder Schalter noch Skript, die Seite läuft in
|
||
der Standard-Palette. Soll „Modern“ dauerhaft werden, werden die Token in `:root` übernommen und
|
||
der Override entfernt – ein Nachtrag, kein Umbau.
|
||
|
||
**Lokal ausgeführt:** `php artisan db:seed --class=WhatsappNumberSeeder` (2 Sprachen gesetzt),
|
||
`npm run build:b2in`. Beim Deployment: Abschnitt 8.2, Schritt 14, dazu `npm run build:web`.
|
||
|
||
**Tests:** `WhatsappNumberSeederTest` (6: anlegen, Platzhalter ersetzen, falsche Nummer vom 23.09.
|
||
korrigieren, gepflegte Nummer behalten, idempotent, Link auf der Seite), `AppointmentWidgetTest` (+2: WhatsApp vor dem Formular, keine
|
||
Trennzeile ohne Nummer), `ColorWorldsTest` (+6: Schalter auf Interior-Seiten, nicht auf
|
||
Immobilien, per Config abschaltbar, Override ohne Logofarben, negatives Logo im Footer der
|
||
Variante, Immobilien-Footer unverändert).
|
||
|
||
**Offen:** Marcel entscheidet zwischen „Bisher“ und „Neu“ – oder benennt, was an „Neu“ noch
|
||
fehlt (Footer hell/dunkel, Grad der Aufhellung). Danach Schalter abschalten.
|
||
|
||
## Nachtrag 19 · Otterpohl: Text v2 und erste Bilder (24.09.2026)
|
||
|
||
Zulieferung vom 24.09.: `dev/2026-08-28/otterpohl_Webseitentext_FINAL_v2.md` löst die lange Fassung
|
||
vom 17.09. komplett ab, dazu 13 Bilder in `dev/2026-08-28/images/otten/` (Titel plus 2–5 vom
|
||
Unternehmen, der Rest Referenzen).
|
||
|
||
### Text v2
|
||
|
||
Deutlich kürzer als v1: eine Einleitung, zwei Abschnitte, acht Leistungen, ein Schlussblock. Die
|
||
Fassung vom 17.09. mit zwölf Abschnitten (u. a. „Seit 2014 an unserer Seite“, „Farbe darf auch
|
||
genau die Farbe sein“) ist damit vollständig ersetzt. Zuordnung auf die Markenseite:
|
||
|
||
| Zulieferung v2 | Feld | Auf der Seite |
|
||
|---|---|---|
|
||
| „Ziemlich nah an der eierlegenden Wollmilchsau“ + 4 Absätze | `sections[0]`, Claim „Genau dort beginnt der individuelle Innenausbau.“ | erster Abschnitt |
|
||
| „Vom einzelnen Möbel bis zum ganzen Raum“ | `sections[1]`, Claim „So können wir Räume ganzheitlicher denken …“ | zweiter Abschnitt |
|
||
| „Planung trifft Handwerk“ | `sections[2]`, Claim „Das Ergebnis kann ein einzelnes Möbel sein. Oder ein kompletter Raum.“ | dritter Abschnitt |
|
||
| „Leistungen und Möglichkeiten“ (8 Punkte) | `services` | Leistungsraster, zwei Reihen à vier |
|
||
| „Das Ganze statt nur das Einzelne“ | `cta_title` / `cta_text` | Abschlussblock hinter Leistungen und Galerie – so bleibt die Reihenfolge der Zulieferung erhalten |
|
||
| „Nicht easy click & buy. Aber dennoch easy to get.“ | `tagline` und Ende des `cta_text` | Claim im Seitenkopf und Schlusssatz |
|
||
|
||
- **Name** jetzt „Otterpohl Möbelservice“ – so nennt die Zulieferung den Partner durchgängig.
|
||
Überall dort, wo der Name aus der Marke kommt (Kacheln, Widget-Anliegen, Herkunfts-Kachel).
|
||
Der Link im Handwerk-Abschnitt der anderen Markenseiten heißt weiter „Mehr zu Otterpohl“.
|
||
- **Kein „seit 2014“ mehr:** v2 erwähnt die gemeinsame Zeit nicht. Der Hinweis ist aus Teaser,
|
||
Fertigungsort (`origin_role`), Lang-Fallback und dem Handwerk-Abschnitt (`brand_craft`)
|
||
entfernt. ⚠️ Falls Marcel die Angabe bewusst behalten wollte, ist sie in drei Sätzen zurück.
|
||
- `description` bleibt leer, damit der Text in der Reihenfolge der Zulieferung steht; `summary`
|
||
(Markenübersicht) fasst die Einleitung zusammen; `highlights` sind drei Stichzeilen aus den
|
||
Leistungen. Englisch: eigene Übersetzung in gleicher Struktur.
|
||
- `widget_label` „Persönliche Beratung zur Maßarbeit vereinbaren“ bleibt.
|
||
|
||
### Bilder
|
||
|
||
13 Dateien, konvertiert wie in Nachtrag 16 (WebP, max. 1920 px, unter
|
||
`public/img/assets/marken/otterpohl/`, zusammen rund 2,4 MB; ein Bild per GD nachverdichtet).
|
||
|
||
- **Titelbild** `werkstatt-titel.webp`: zwei Mitarbeiter in der Werkstatt.
|
||
- **Aus der Werkstatt** (2–5): CNC-Bearbeitungszentrum, Türeinbau vor Ort, Handwerkzeug,
|
||
Anlieferung per Möbellift. Dafür gibt es eine **dritte Galerie-Kategorie** `company`
|
||
(`CmsBrand::GALLERY_COMPANY`, Badge „Aus der Werkstatt“). Im Admin: Button „Werkstatt“ und
|
||
Option „Aus der Werkstatt“ in der Kategorie-Auswahl, Hinweistext ergänzt.
|
||
- **Referenzen** (8, Kategorie `project`, Badge „Realisiertes Projekt“): Treppen, Lamellenwand mit
|
||
Sitzbank, Tür und Kommode, Wandregale, Objektbau-Verkaufsraum, Büro-Sideboard. Unterschriften
|
||
beschreiben das Motiv; die Kundennamen aus den Dateinamen (Lücke, Berkemeier, Neugebauer,
|
||
Dziuballe) stehen bewusst nicht auf der Seite. ⚠️ `Otterpohl_11.jpg` (Sideboard im Büro) ist
|
||
nach Kevins Angabe eine Referenz, nicht Werkstatt – falls es das eigene Büro ist, im Admin auf
|
||
„Aus der Werkstatt“ umstellen.
|
||
- **Reihenfolge in der Galerie:** Projekte, dann Werkstatt, dann Visualisierungen.
|
||
- **Überschrift der Galerie** richtet sich jetzt nach dem Inhalt: nur Visualisierungen →
|
||
„Inspirationen und Entwürfe“ (wie bisher, CABINET/Rotpunkt/Febrü); nur Projekte → „Referenzen“;
|
||
Projekte und Werkstatt → „Referenzen und Einblicke“ (Otterpohl); mit Visualisierungen →
|
||
„Projekte und Entwürfe“. Die Zeile darunter passt jeweils.
|
||
- ⚠️ **Referenzen-Seite:** `/referenzen` zeigt, solange im Modul „Referenzen“ nichts gepflegt ist,
|
||
die Projekte aus den Markengalerien – jetzt also die acht Otterpohl-Referenzen mit Link auf die
|
||
Markenseite. Werkstattbilder erscheinen dort nicht. Wenn Marcel das nicht will: Bilder im Admin
|
||
auf „Aus der Werkstatt“ stellen oder eigene Referenzen anlegen, dann greift der Fallback nicht.
|
||
|
||
**Lokal ausgeführt:** `php artisan db:seed --class=OtterpohlBrandSeeder`, `php artisan db:seed
|
||
--class=BrandImageSeeder`. Beim Deployment: Abschnitt 8.2, Schritte 11 und 12 (Texte
|
||
unverändert, sie decken v2 mit ab).
|
||
|
||
**Tests:** `FourthBrandTest` (v2-Überschriften, acht Leistungen, drei Abschnitte, Schlussblock hinter
|
||
den Leistungen, kein „Seit 2014“), `BrandFeedbackTest` (Seeder setzt Name, acht Leistungen,
|
||
Abschluss), `BrandImageSeederTest` (+3: Otterpohl-Galerie 8 Projekte + 4 Werkstatt ohne
|
||
Kundennamen, Badges und Überschrift „Referenzen und Einblicke“, Referenzen-Fallback zeigt Projekte
|
||
und keine Werkstattbilder), `BrandPageTest` (gemischte Galerie → „Projekte und Entwürfe“, Aufräum-
|
||
Seeder lässt Otterpohl 12).
|
||
|
||
**Offen:** Marcel prüft Unterschriften, die Zuordnung von `Otterpohl_11`, das gestrichene „seit
|
||
2014“ und ob die Otterpohl-Referenzen unter `/referenzen` erscheinen sollen.
|
||
|
||
## Nachtrag 19 · Entwurf der Startseite in der Farbwelt „Greige“ (24.09.2026)
|
||
|
||
Briefing von Marcel (`dev/2026-08-28/farbwelt-kunde-24-09-2026.md`, Visualisierung
|
||
`Farbwelt und Stil.png`): die Creme-Palette wird nicht weiterverfolgt, die Richtung „Neu“ soll
|
||
heller, klarer und hochwertiger werden – heller, leicht kühler Grundton (Greige, kein steriles
|
||
Weiß), deutlich präsenteres Tannengrün, Gold nur als feine Linie. Dazu eine Slideshow im Hero,
|
||
neue Überschrift, keine Aktionsleiste, ein Button im Hero, neuer Projekttext, Logo mit Goldbogen.
|
||
Kevins Auftrag: eine **separate Version der Startseite** zum Vergleich, das Logo als Kopie.
|
||
|
||
### Was gebaut ist
|
||
|
||
- **Entwurfsseite `/entwurf`** (Route `home.draft`, View `web/home-draft.blade.php`): die reguläre
|
||
Startseite mit neuem Hero, ohne Ankündigungsleiste, Body-Klasse `palette-greige`, `noindex`.
|
||
Alle übrigen Sektionen sind unverändert eingebunden und färben sich über die Tokens. Die Seite
|
||
hängt am Farb-Schalter: mit `B2IN_PALETTE_SWITCH=false` liefert sie 404.
|
||
- **Palette „Greige“** als drittes Token-Set in `theme-b2in.css` (`.world-interior.palette-greige`,
|
||
am Body, nicht am `<html>` wie der Browser-Schalter – so überlagern sich beide nicht):
|
||
|
||
| Token | Wert |
|
||
|---|---|
|
||
| Grund | `#f0eeeb` Greige, Off-White (Kopfzeile der Visualisierung) |
|
||
| Karten / Hero-Bühne | `#f8f7f4` |
|
||
| Sektionswechsel (`bg-accent`) | `#e8e6e0` |
|
||
| Tannengrün (`--primary`) | `#14342c`, Buttons, dunkle Sektionen, Footer |
|
||
| Gold (`--secondary`) | `#aa8341` gedeckt; als Text `--secondary-deep` (dunkler) |
|
||
| Text | Tannengrau `hsl(166 25% 13%)` |
|
||
| Footer | Tannengrün mit Greige-Text, Goldlinie oben, negatives Logo |
|
||
|
||
- **Logo-Kopien** `public/img/logos/b2in-interior-logo-gold-{positive,negative}.svg`: Bogen
|
||
`#AA8341` statt Ocker, Wortmarke im neuen Tannengrün `#14342C` (negativ: Schrift `#F0EEEB`).
|
||
Flächig, ohne Verlauf – die Verläufe liefert Marcel nach; die Dateien lassen sich dann 1:1
|
||
ersetzen. Die bisherigen Logos sind unangetastet. `ThemeHelper::getLogoPath()` liefert die
|
||
Gold-Variante, sobald `b2in_palette()` (neuer Helper, Binding `b2in.palette`) „greige“ meldet
|
||
– das setzt nur die Entwurfsroute. Kein PNG erzeugt (kein SVG-Rasterizer im Container).
|
||
- **Hero mit Slideshow** (`HeroSlider`, Sektion `home/hero_slider`, im Seitenbaum unter Startseite
|
||
mit Vorschau auf `/entwurf`): Rahmen mit 1-px-Goldkante und Schatten, tannengrüne Flanken rechts
|
||
(volle Höhe) und links unten wie in der Visualisierung, Eyebrow „B2IN INTERIOR ——“, Überschrift
|
||
„*Räume aus einer Hand.* Mit starken Marken und persönlichen Lösungen.“ (erste Zeile in Gold,
|
||
Serife), Einleitungstext aus der Visualisierung, **ein** Button „Unsere Marken entdecken“ mit
|
||
Goldkante unten und Pfeil. Kein zweiter Button (Briefing Punkt 5), das Termin-Widget bleibt.
|
||
- Bild rechts im festen Seitenverhältnis 4:3 → auf großen Bildschirmen nicht mehr unten
|
||
beschnitten (Briefing Punkt 2).
|
||
- Slides: Liste `slides` der Sektion (je `image`, `label`, `caption`, `active`), solange leer
|
||
die **Titelbilder der veröffentlichten Kernmarken** in ihrer Reihenfolge (aktuell CABINET,
|
||
Rotpunkt, Febrü, Otterpohl sofern Bild). Kleine Marken-Pille unten links im Bild.
|
||
- Ruhig: Überblendung 1,4 s, Wechsel alle 7 s (`interval`, begrenzt auf 3–30 s), Pause bei
|
||
Hover/Fokus, Pfeiltasten, Punkte unter dem Rahmen als Tabs; bei „reduzierter Bewegung“ kein
|
||
Autowechsel. Läuft ohne eigenes JS-Bundle (Alpine im Markup).
|
||
- **Farb-Schalter** hat jetzt drei Einträge: Bisher / Neu (Browser, wie gehabt) / **Entwurf**
|
||
(Link auf `/entwurf`). Auf dem Entwurf ist „Entwurf“ aktiv, „Bisher“/„Neu“ führen mit
|
||
`?palette=…` zurück auf die Startseite.
|
||
- **Projekttext** (Briefing Punkt 7) global: Lang de/en geändert, `AudienceSwitchProjectTextSeeder`
|
||
tauscht den Satz in einem vorhandenen CMS-Eintrag (nur diesen Satz, idempotent). Lokal
|
||
ausgeführt (2 Stellen). Deployment Schritt 15.
|
||
|
||
**Nachbesserung nach Kevins Screenshot (24.09., 17:30):** Die Goldkante war auf Greige nicht zu
|
||
sehen – jetzt ein Verlauf (hell oben links, auslaufend, in der Ecke wieder anziehend) über einen
|
||
maskierten Pseudo-Rand von 1,5 px. Die Flanken sind gerundet (Radius 2,75 rem rechts, 2 rem
|
||
links) und laufen hinter das Bild; ihre Goldlinie folgt der Rundung. Das Bild füllt den Rahmen
|
||
fast ganz (5:4, nur 1,25 rem Luft oben und unten, rechts über der Flanke), die Überschrift ist
|
||
kleiner (max. 3,3 rem statt 4,1 rem) und der Einleitungstext eine Stufe kleiner.
|
||
|
||
**Zweite Nachbesserung (25.09.):** Hinter der Goldkante schien eine helle Linie durch – die
|
||
Masken-Technik ließ die gerundete Kante des Rahmens außerhalb des Rings sichtbar. Jetzt sind
|
||
Rahmen und Bild-Rahmen echte Verlaufs-Borders (transparenter Rand, Fläche auf `padding-box`,
|
||
Goldverlauf auf `border-box`), ohne Pseudo-Element. Der Button trägt den Goldrand rundum, unten
|
||
3 px, der Pfeil ist Gold. Die grünen Flanken sind **Inline-SVGs**
|
||
(`components/web/hero-flank-right|left.blade.php`): grüner Verlauf, Goldlinie entlang der
|
||
Rundung, rechts zusätzlich die kurze Zierlinie aus der Visualisierung. Sie skalieren über die
|
||
Rahmenhöhe (`height: 100 %` bzw. `46 %`, Breite aus dem viewBox-Verhältnis, Strichstärke bleibt
|
||
1,5 px dank `vector-effect`), Farben aus den Tokens. Liefert Marcel eigene SVGs, werden die
|
||
beiden Dateien getauscht – der Platz im Rahmen bleibt.
|
||
|
||
**Abstimmung 25.09. (Kevin):** Für die nächste Runde ist der Farb-Schalter **aus** und die Seite
|
||
steht fest auf „Neu“. Dafür zwei neue Konfigurationswerte in `config/app.php`:
|
||
`B2IN_PALETTE_SWITCH` (Standard jetzt `false`), `B2IN_PALETTE` (Standard `modern`; ohne Schalter
|
||
setzt das Layout die Klasse `palette-modern` serverseitig an `<html>`, mit Schalter ist es die
|
||
Vorbelegung, solange nichts im localStorage liegt) und `B2IN_HOME_DRAFT` (Standard `true`) – der
|
||
Entwurf `/entwurf` hängt nicht mehr am Schalter, sondern an diesem Wert. Der Schalter selbst
|
||
bleibt im Code und lässt sich mit `B2IN_PALETTE_SWITCH=true` wieder einblenden.
|
||
|
||
### Was aus dem Briefing noch offen ist
|
||
|
||
| Punkt | Stand |
|
||
|---|---|
|
||
| 1 Slideshow selbst pflegen (Upload, Reihenfolge, an/aus) | Datenmodell steht (Liste `slides` mit `active`), Pflege bisher nur über den JSON-Editor unter Inhalte. Eigene Oberfläche wie bei den Displays: nächster Schritt nach Freigabe des Entwurfs. |
|
||
| 6 Persönliches Foto | Kein Foto geliefert. Vorschlag: in der Gründer-Leiste („B2in by Marcel Scheibe“), Bildfeld ist dort schon vorhanden (`founder_bar.image`). |
|
||
| 8 Feinabstimmung der Töne | Werte oben sind aus der Visualisierung gesampelt und leicht aufgehellt („noch etwas heller“). Marcel entscheidet am Entwurf. |
|
||
| 9 Logo mit Verläufen | Kommt von Marcel; bis dahin flache Gold-Kopie. |
|
||
| Entwurf → Standard | Wenn freigegeben: Tokens von `.palette-greige` nach `:root`, Gold-Logos umbenennen, `home.blade.php` auf `hero-slider` umstellen, Ankündigungsleiste global aus, Schalter und `/entwurf` abschalten. Ein Nachtrag, kein Umbau. |
|
||
|
||
**Lokal ausgeführt:** `php artisan db:seed --class=AudienceSwitchProjectTextSeeder`, `npm run build:b2in`.
|
||
Beim Deployment: Abschnitt 8.2, Schritt 15, dazu `npm run build:web`; die SVG-Logos liegen im
|
||
Repository. Link für Marcel: `https://<vorschau>/entwurf`.
|
||
|
||
**Tests:** `HomeDraftTest` (16: Palette und Gold-Logos nur auf dem Entwurf, Überschrift/ein
|
||
Button/keine Leiste, Sektionsreihenfolge, 404 ohne Schalter, Slides aus Marken, ohne Bild,
|
||
CMS-Slides mit `active`, Intervall-Grenzen, Schalter hin und zurück, Logo-Dateien, Tokens,
|
||
Projekttext in Lang und per Seeder), `CmsPageTreeTest` (Reihenfolge um `hero_slider` ergänzt).
|
||
Gesamt: 1049 grün.
|
||
|
||
---
|
||
|
||
## Nachtrag 20 · Korrekturen Startseite und Otterpohl (01.10.2026)
|
||
|
||
Farbwelt bleibt vorerst „Modern“ ohne Schalter. Umgesetzt auf der regulären Startseite `/`:
|
||
|
||
- **Hinweisleiste oben** aus über die Flag `B2IN_ANNOUNCEMENT_BAR` (`config('app.announcement_bar')`,
|
||
Standard `false`, gilt für beide Welten). Inhalt und CMS-Pflege bleiben, `=true` blendet sie wieder ein.
|
||
- **Hero-Überschrift** „<span class="text-secondary">Räume aus einer Hand.</span><br>Mit starken Marken
|
||
und persönlichen Lösungen.“ (erste Zeile in `.text-secondary`). Lang de/en und `HomeHeroTextSeeder`
|
||
für den CMS-Eintrag `home/hero` (ersetzt nur die alte Überschrift).
|
||
- **Zweiter Hero-Button** „Termin anfragen“ entfernt: aus Lang und CMS gelöscht; das Blade zeigt ihn nur
|
||
noch, wenn `cta2_text` gepflegt ist. Der feste Termin-Button unten rechts bleibt.
|
||
- **Projekttext**: „… Projektentwicklungen. Koordiniert aus einer Hand …“ (Punkt statt Gedankenstrich),
|
||
Lang de/en und `AudienceSwitchProjectTextSeeder` erweitert.
|
||
- **Otterpohl Titelbild**: `tittle_otter.png` → `marken/otterpohl/titel-treppe.webp` (1920 px, WebP 82).
|
||
Gleiches Motiv wie das Galeriebild `referenz-luecke-01` – daher echter Tausch: die Treppe wird Titelbild,
|
||
das bisherige Werkstattbild nimmt ihren Galerieplatz ein (Aus der Werkstatt). Nur wenn noch das alte
|
||
Titelbild gesetzt ist (`OtterpohlBrandSeeder::swapTitleImage()`).
|
||
- **Otterpohl Abschnitt „Montage“** als vierter Abschnitt. Neu für alle Markenabschnitte: Absätze mit
|
||
„- “ am Anfang werden zur Liste, der Teil vor dem ersten Doppelpunkt fett (`CmsBrand::paragraphBlocks()`)
|
||
– pflegbar im normalen Textfeld im Admin.
|
||
|
||
Lokal ausgeführt: die drei Seeder aus Schritt 16. Tests: `HomeCorrectionsTest` (neu), angepasst
|
||
`AnnouncementBarTest`, `HomePageStructureTest`, `HomeDraftTest`, `BrandImageSeederTest`,
|
||
`FourthBrandTest`, `AppointmentTriggerTest`, `CmsContentSeederTest`. Gesamt 1071 grün
|
||
(mit `B2IN_HOME_DRAFT=true`; die lokale `.env` hat den Entwurf aus, dann schlagen die `/entwurf`-Tests fehl).
|
||
|
||
---
|
||
|
||
## Seeder für das nächste Deployment (Stand 01.10.2026)
|
||
|
||
Alles, was seit dem letzten Commit (`3211569f`, Bilddauer im Display) neu ist: Nachträge 15–20.
|
||
Annahme: Der Stand bis zu diesem Commit ist live. Genau diese Seeder, in dieser Reihenfolge:
|
||
|
||
```bash
|
||
php artisan db:seed --class=CmsBrandSeeder --force # legt Otterpohl („tischlerei“) an, falls die Marke fehlt – überschreibt nichts
|
||
php artisan db:seed --class=BrandPageTextSeeder --force # Feedback 17.09. für CABINET, Rotpunkt, Febrü (überschreibt deren Textfelder)
|
||
php artisan db:seed --class=OtterpohlBrandSeeder --force # Otterpohl-Texte v2, Abschnitt „Montage“, Titelbild-Tausch
|
||
php artisan db:seed --class=BrandImageSeeder --force # Titelbilder und Galerien aller vier Marken
|
||
php artisan db:seed --class=DemoBrandGalleryCleanupSeeder --force # Demobilder raus – nach BrandImageSeeder
|
||
php artisan db:seed --class=WhatsappNumberSeeder --force # WhatsApp-Business-Nummer 0521-98620100
|
||
php artisan db:seed --class=AudienceSwitchProjectTextSeeder --force # Projekttext „… Projektentwicklungen. Koordiniert …“
|
||
php artisan db:seed --class=HomeHeroTextSeeder --force # Hero „Räume aus einer Hand.“, zweiter Button weg; 07.10.: Zeile „B2in Interior“, Untertitel „Wir vereinen …“, erste Slide „B2in Interior“
|
||
php artisan db:seed --class=UnusedCmsContentCleanupSeeder --force # tote CMS-Sektionen (inkl. Entwurfs-Hero home.hero_slider) + ungenutzte Felder (u. a. Markenliste in home.core_brands) löschen (sichert vorher nach storage/app/private/cms-archiv/)
|
||
php artisan db:seed --class=AboutPageTextSeeder --force # /about: „auch dafür geradesteht“ und Textkorrekturen (06.10.)
|
||
php artisan db:seed --class=ProofreadingCorrectionsSeeder --force # Lektorat aller angezeigten Texte (06.10.)
|
||
php artisan db:seed --class=LegalTextUpdateSeeder --force # Rechtstexte: DDG/MStV/TDDDG, GA4, Leistungsbeschreibung (06.10.)
|
||
php artisan db:seed --class=ReferencesPageSwitchSeeder --force # Referenzen ausblenden (Seite + Menüpunkt), nur wenn noch nicht geschaltet
|
||
php artisan db:seed --class=HomeHeroSlidesSeeder --force # Slideshow im Hero der Startseite (9 Bilder), nur wenn noch keine Slides gepflegt
|
||
php artisan db:seed --class=PageHeroEyebrowSeeder --force # Zeile über der Hero-Überschrift auf Marken, Über uns, Kontakt (07.10.); „Über B2in:“ aus der h1 auf /about
|
||
php artisan db:seed --class=HeroTrustItemsSeeder --force # Vertrauenspunkte im Hero: Startseite neu, Marken ergänzt (07.10.)
|
||
php artisan db:seed --class=HomeVisionTitleSeeder --force # „Gebaut auf Expertise und Vertrauen“: Hervorhebung in Ocker (07.10.)
|
||
php artisan db:seed --class=ContentCorrections20261008Seeder --force # Korrekturen 08.10.: Febrü-Slides, Vereine, Ablauf Maßanfertigung, Magazin, FAQ, Otterpohl
|
||
php artisan db:seed --class=CmsSectionFieldsSeeder --force # zuletzt: fehlende Felder aus der Lang-Datei in CMS-Einträgen ergänzen (überschreibt nichts)
|
||
php artisan db:seed --class=AssetMediaImportSeeder --force # ganz zuletzt: verwendete Bilder aus public/img/assets in die Mediathek (braucht php artisan storage:link)
|
||
```
|
||
|
||
Danach:
|
||
|
||
```bash
|
||
php artisan config:cache
|
||
php artisan view:clear
|
||
npm ci && npm run build:web && npm run build:portal
|
||
```
|
||
|
||
- Alle Seeder sind idempotent, ein zweiter Lauf schadet nicht.
|
||
- In der `.env` muss nichts ergänzt werden: Die Hinweisleiste ist standardmäßig aus. `B2IN_PALETTE_SWITCH`,
|
||
`B2IN_PALETTE` und `B2IN_HOME_DRAFT` werden nicht mehr gelesen (Nachtrag 24) und können aus der `.env` raus.
|
||
- Nicht nötig: `BrandLogoSeeder` und `BrandOriginSeeder` – Logo und Fertigungsort von Otterpohl setzt
|
||
bereits der `OtterpohlBrandSeeder`.
|
||
|
||
---
|
||
|
||
## Nachtrag 22 · Tote Inhalte entfernt, Lektorat aller angezeigten Texte (06.10.2026)
|
||
|
||
- **Aufgeräumt:** 48 Sektionen, die keine erreichbare Seite mehr zeigt (Netzwerk, Partner, Ecosystem,
|
||
Interior, alte Immobilien-Seite, Startseiten-Blöcke vor dem Relaunch, Führungsteam), aus Lang-Dateien,
|
||
`cms_section_map`, CMS-Datenbank (`UnusedCmsContentCleanupSeeder`, sichert vorher nach
|
||
`storage/app/private/cms-archiv/`) und Seedern. Dazu 15 alte Views, die Dev-Archivseiten
|
||
`/dev/{immobilien,interior,partner}-v1`, 19 Livewire-Sektionen, `NetzwerkPageCmsSeeder`,
|
||
`config/content.php` und ungenutzte Felder (`stats`, `social_media`, `load_more`, `share_article`) samt
|
||
auskommentiertem Markup. `partner_cta` liegt jetzt in der Gruppe `about`, die Gruppe `netzwerk` gibt es
|
||
nicht mehr. Lang-Sektionen und Section-Map decken sich jetzt 1:1 (Test).
|
||
- **Archiv:** `dev/2026-08-28/archiv-2026-10-06/` (README dort).
|
||
- **Lektorat:** `ProofreadingCorrectionsSeeder` (40 Stellen in CMS, Marken, Magazin, Rechtstexten),
|
||
dieselben Korrekturen in Lang-Dateien und Marken-Seedern, rund 50 Stellen in `immobilien-azizi.json`.
|
||
Offene inhaltliche Punkte: `dev/2026-08-28/lektorat-rueckfragen-06-10-2026.md`.
|
||
- **/about:** Kennzahlen im Abschluss entfernt (wurden nie angezeigt), Alternativtext der Bildpause
|
||
beschreibt jetzt das Bild.
|
||
|
||
Deployment: siehe Seeder-Liste oben (`UnusedCmsContentCleanupSeeder`, `AboutPageTextSeeder`,
|
||
`ProofreadingCorrectionsSeeder`). Tests: 1072 grün (mit `B2IN_HOME_DRAFT=true`).
|
||
|
||
**Nachgang 06.10. (Kevin):** Kachel „Datenstand“ samt `confidence_labels`/`data_confidence` und die
|
||
internen Prüfnotizen auf /immobilien entfernt; „unsere Tischlerei“ → „die Tischlerei Otterpohl“
|
||
(Herkunfts-Sektion, über `ProofreadingCorrectionsSeeder`); Rechtstexte aktualisiert
|
||
(`LegalTextUpdateSeeder` + `resources/lang/de/b2in_legal.php`, Banner-Texte des Cookie-Pakets per
|
||
`resources/lang/vendor/cookie-consent/de/`). Immobilien-Daten bleiben wie sie sind.
|
||
|
||
**Referenzen-Schalter (06.10.):** Im CMS-Modul „Referenzen“ gibt es oben den Schalter „Seite ‚Referenzen‘
|
||
auf der Website anzeigen“ (Einstellung `settings` → `pages.referenzen_enabled`, Helper
|
||
`references_page_enabled()`). Aus: Menüpunkt weg, /referenzen liefert 404, der Button unter dem
|
||
Showroom-Feed entfällt, sofern er auf /referenzen zeigt. Die Referenzen selbst bleiben gepflegt.
|
||
`ReferencesPageSwitchSeeder` schaltet beim Deployment aus (nur ohne bestehenden Eintrag).
|
||
|
||
---
|
||
|
||
## Nachtrag 23 · Slideshow im Hero der Startseite (07.10.2026)
|
||
|
||
Die Slideshow aus dem Entwurf (`/entwurf`) läuft jetzt im Hero der aktiven Startseite („Modern“). Das
|
||
Layout bleibt: Text links, rechts statt des festen Bildes die Slideshow, Infokarte unten links, kleine
|
||
Marken-Pille oben links, Punkte unter dem Bild.
|
||
|
||
- **Bilder:** `dev/2026-08-28/images/slideshow/` (9 JPEGs, 1,7–5,7 MB) → `public/img/assets/b2in/slideshow/*.webp`
|
||
(1920 px, Qualität 82, ohne Metadaten, 86–265 KB). Reihenfolge wie geliefert: Rotpunkt Fenix House,
|
||
CABINET Ankleide, Rotpunkt Küche, CABINET Schlafzimmer, Rotpunkt Küche, CABINET Flur, Rotpunkt Küche,
|
||
CABINET Dachschräge, Rotpunkt Bad.
|
||
- **Pflege im CMS:** Seiten → Startseite → Hero, Liste `slides` (je `image`, `label`, `alt`, `active`), Reihenfolge
|
||
der Liste = Reihenfolge der Slideshow, `interval` in Sekunden (3–30, Standard 7). Ohne aktive Slides
|
||
steht wieder das einzelne Bild `image`.
|
||
- **Verhalten:** Überblendung 1,4 s, Pause bei Hover/Fokus, Pfeiltasten, bei „reduzierter Bewegung“ kein
|
||
Autowechsel; erstes Bild sofort, die übrigen lazy. Festes Seitenverhältnis 4:3, damit nichts unten
|
||
abgeschnitten wird.
|
||
- **Code:** `Hero` (Livewire) mit `activeSlides()`, Blade `sections/hero.blade.php`, Lang de/en
|
||
`hero.slides`/`hero.interval`, `HomeHeroSlidesSeeder` für bestehende Installationen. Tests:
|
||
`HomeHeroSlideshowTest`. `npm run build:b2in` (neue Utility-Klassen).
|
||
|
||
**Nachbesserung 07.10. (nach „Farbwelt und Stil.png“):** Die Slideshow ist jetzt das Hauptelement des
|
||
Rahmens: zweispaltig (Text 5/12, Bild 7/12), das Bild reicht oben, unten und rechts bis auf 16 px an den
|
||
Rand, auf großen Bildschirmen mindestens 560 px hoch (mobil 4:3 unter dem Text). Die Punkte stehen mittig
|
||
unter dem ganzen Block. Die Infokarte über dem Bild bleibt und wechselt mit: Marke (`label`) und Motiv
|
||
(neues Feld `caption`), ohne Angaben die festen `card_title`/`card_text`. Die Marken-Pille oben links
|
||
entfällt. `HomeHeroSlidesSeeder` ergänzt fehlende `caption` bei bereits eingetragenen Slides.
|
||
|
||
**Nachbesserung 07.10. (2):** Rahmenschatten `rgba(0, 0, 0, 0.1) 0px 10px 20px 5px`. Die Infokarte
|
||
saß oben im Bild, weil die Glass-Flow-Regel `[class*="card"]` ihr `position: relative` gab – jetzt
|
||
`absolute!`. Der Kartentext überblendet nicht mehr gleichzeitig: der alte blendet in 0,3 s aus, der neue
|
||
danach in 0,5 s ein.
|
||
|
||
---
|
||
|
||
## Nachtrag 24 · Alte Entwürfe entfernt (07.10.2026)
|
||
|
||
Mit der Slideshow im Hero und der festen Palette „Modern“ sind die Abstimmungsstände erledigt. Entfernt,
|
||
Kopien unter `dev/2026-08-28/archiv-2026-10-07-entwurf/`:
|
||
|
||
- **Entwurf `/entwurf`** (Nachtrag 19): Route, View `home-draft`, Farbwelt „Greige“, Gold-Logos,
|
||
Hero mit Goldkante und Flanken (`hero-flank-*`), CSS `.hero-draft`, CMS-Sektion `home.hero_slider`
|
||
(Seitenbaum, Section-Map, Lang de/en; auf dem Server löscht sie der `UnusedCmsContentCleanupSeeder`).
|
||
- **Farb-Schalter und Palette „Bisher“ (Creme)** (Nachtrag 18): Komponente `palette-switch`, Skript im
|
||
`<head>`, Klasse `palette-modern` am `<html>`, `b2in_palette()`, Config `app.palette_switch`,
|
||
`app.palette`, `app.home_draft`. Die hellen Flächen hängen jetzt fest an `.world-interior`.
|
||
- **HeroSlider** bleibt, weil b2a, Stileigentum und Style2own ihn einbinden – zurück auf den Stand vor
|
||
dem Entwurf. Ohne gepflegte Sektion zeigt er nichts statt eines Fehlers (deren Inhalte lagen in
|
||
`config/content.php`, siehe Archiv vom 06.10.).
|
||
|
||
Tests laufen jetzt ohne `B2IN_HOME_DRAFT=true`.
|
||
|
||
**Nachbesserung 07.10. (3):** Kartentexte überlagerten sich – Alpine ließ die fest gesetzten Klassen
|
||
stehen; der Zustand hängt jetzt an `data-active`. Über der Überschrift steht „B2IN INTERIOR“ mit
|
||
Ockerlinie (neues Feld `eyebrow`), Untertitel „Wir vereinen CABINET, Rotpunkt Küchen, Febrü und ein
|
||
Netzwerk regionaler Experten …“, das erste Bild trägt in der Karte „B2in Interior“. Auf dem Server
|
||
setzt das der `HomeHeroTextSeeder`.
|
||
|
||
**Nachbesserung 07.10. (4):** Gründer-Leiste auf der Startseite auf `bg-accent` (Verlauf Accent/Accent-dark
|
||
50 %). Der Hero-Stil der Startseite gilt jetzt auch für Marken, Über uns und Kontakt: Klasse `hero-frame`
|
||
(Goldverlauf, Hintergrund `linear-gradient(to bottom right, hsl(40, 5.65%, 95.65%), hsl(40, 15.95%, 93.9%))`,
|
||
nur in der Interior-Welt), weißer 1-px-Rand an den Bildern (`border-white!` – die globale Regel
|
||
`* { border-color }` in shared-styles.css schlägt sonst die Utility), Zeile über der Überschrift als
|
||
Komponente `x-web.hero-eyebrow` (Felder `eyebrow`; Kontakt: `hero.eyebrow`), im CMS ergänzt durch
|
||
`PageHeroEyebrowSeeder`.
|
||
|
||
**Nachbesserung 07.10. (5):** Breadcrumb im Seitenkopf entfernt, Heroes oben/unten mit weniger
|
||
Abstand (lg 48 px). Vertrauenspunkte als Komponente `x-web.hero-trust` (Feld `stats`): Startseite
|
||
„Deutsche Manufakturen“, „Planung bis Montage“, „Zwei Showrooms in Bielefeld“; Marken „Maßarbeit vom
|
||
Handwerk“, „Werk und Ausstellung erlebbar“, „Küche, Einbau, Arbeitsplatz“ (`HeroTrustItemsSeeder`).
|
||
|
||
**Nachbesserung 07.10. (6):** Gründer-Leiste auch unter dem Hero von /marken, auf /about und /marken
|
||
wie auf der Startseite mit `bg-accent`.
|
||
|
||
**Nachtrag 25 · Aufräumen (07.10.2026):** Sicherungskopien (`sections_bak/`, `setup-wizard_bak`), doppelte
|
||
`AboutHero`-Klasse, ungenutzte Layouts und Starter-Vorlagen, Bildkopien, macOS-Metadaten, Bild
|
||
„Integriertes Modell“ und die Dubai-Karte nach `dev/2026-08-28/archiv-2026-10-07-aufraeumen/`. Dazu `/welcome` (Demo-Seite) und 118 ungenutzte
|
||
Bilder der ruhenden Domains b2a, Stileigentum und Style2own; die Domains selbst bleiben, `/theme-demo` bleibt.
|
||
|
||
**Nachtrag 26 · Test-Routen nur lokal (07.10.2026):** `routes/test.php` (E-Mail-Vorschauen mit echten Namen
|
||
und Adressen, Login-Tests) lädt nur noch bei `APP_ENV=local`. Live liefern `/test/emails/…`, `/test-login`,
|
||
`/login-simple`, `/debug-login` und `/simple-test` im Portal 404. Auf dem Server `php artisan route:cache` neu bauen,
|
||
falls Routen gecacht sind.
|
||
|
||
**Nachbesserung 07.10. (7):** /marken: Bildpause `marken.image_break` (Section `id="bild"` wie auf /about)
|
||
zwischen Markenblöcken und „Aus der Region gefertigt“, Bild = letztes Slideshow-Bild (Rotpunkt Bad), Zitat
|
||
Marcel Scheibe „Hinter jeder unserer Marken stehe ich persönlich. Ich kenne die Werke und die Menschen, die dort arbeiten.“
|
||
Kein Seeder nötig – ohne CMS-Eintrag gilt die Lang-Datei; im Seitenbaum unter Marken → Bildpause pflegbar.
|
||
|
||
**Nachbesserung 07.10. (8):** Startseite „Gebaut auf Expertise und Vertrauen“: Fläche `bg-secondary`
|
||
(Verlauf Ocker → Ocker dunkel), Inhalt in weißer Box mit Schatten, Porträt klein (4/12, 4:5) – Parameter
|
||
`boxed` an `vision-section`, die anderen Themes bleiben offen. Bildunterschrift mit `absolute!` (Glass-Flow-Regel).
|
||
|
||
**Nachbesserung 07.10. (9):** „Expertise und Vertrauen“ in Ocker (`HomeVisionTitleSeeder`; in der weißen Box
|
||
gilt wieder Ocker statt der Tanne-Regel für Ockerflächen). „Aktuelles aus unserem Showroom“ in weißer Box;
|
||
„Größer ansehen“ öffnet das Display als Overlay über die volle Fensterhöhe (9:16), dort „Vollbild“ per
|
||
Fullscreen-API, wo der Browser es kann (nicht auf dem iPhone). Das große Display lädt erst beim Öffnen.
|
||
|
||
**Nachbesserung 07.10. (10):** Hero-Slideshow: feine Laufzeit-Linie unten im Bild (füllt sich bis zum
|
||
Wechsel, hält bei Hover/Fokus an; Zähler über requestAnimationFrame statt setInterval). Punkte mit
|
||
unsichtbarer Klickfläche (py-4) um den Balken, ohne Glass-Flow-Button-Schatten.
|
||
|
||
**Nachtrag 27 · CMS-Durchsicht (07.10.2026):** Section-Map, Seitenbaum, Datenbank und Lang-Datei decken sich
|
||
(41 Sektionen; Rechtstexte und Kontaktdaten laufen über eigene Helfer). Sections ohne DB-Eintrag (Termin-Widget,
|
||
Marken-Bildpause, Handwerk-Abschluss) lassen sich im Seitenbaum mit „+“ anlegen. Korrigiert: Markenliste
|
||
`brands` in „Kernmarken“ war im CMS ohne Wirkung (Kacheln aus der Markenverwaltung) – entfernt, Fallback liest
|
||
die Lang-Datei direkt. „Zur Marke“ in „Aus der Region gefertigt“ fehlte im CMS-Eintrag – `CmsSectionFieldsSeeder`
|
||
ergänzt fehlende Felder generell. Beschreibungen im Seitenbaum aktualisiert (eyebrow, stats, Bildpause, Vision).
|
||
Marken, Magazin, Projekte und Referenzen: alle Felder im Admin bearbeitbar. Alle 135 Bildpfade vorhanden.
|
||
|
||
**Nachtrag 28 · Admin-Bildvorschauen (07.10.2026):** `media_url()` verwies für Bilder außerhalb der Mediathek
|
||
auf das nicht existierende `assets/images/` (404 in Marken, Magazin, Projekten, Referenzen) – jetzt
|
||
`img/assets/` wie `theme_image_url()`. Ungenutzte `cms_media_url()` entfernt. Alle 80 Bilder der
|
||
Admin-Ansichten lokal geprüft.
|
||
|
||
**Nachtrag 29 · Bilder in der Mediathek (07.10.2026):** `AssetMediaImportSeeder` übernimmt die 82 Bilder, die
|
||
Marken, Magazin und CMS aus `public/img/assets/` verwenden, in die Mediathek (Sammlungen Marken, Magazin,
|
||
Website, mit Vorschaubild). Name = bisheriger Pfad, daher bleiben alle Verweise gültig. Die Website liefert weiter aus
|
||
`public/img/assets/` (WebP-Fassungen), der Admin zeigt die Mediathek-Kopie. Auf dem Server muss `storage:link` bestehen (sonst liefern Mediathek-Bilder 404).
|
||
|
||
**Nachtrag 30 · Beschreibungen im Seitenbaum (07.10.2026):** alle Beschreibungen gegen die Seiten geprüft und
|
||
korrigiert – u. a. Hinweisleiste (über B2IN_ANNOUNCEMENT_BAR aus, Feld „enabled“), Abschluss „Termin anfragen“
|
||
(nur Startseite und /referenzen), Fußbereich (Claim, byline, Links – kein Social Media), Showroom-Display
|
||
(display_id, „Größer ansehen“), Hero (Ersatzkarte/-bild), Geschichte (Zeitleiste), „AGB“ → Nutzungsbedingungen.
|
||
|
||
## Nachtrag 31 · Korrekturen vom 08.10.2026 (`Korrekturen-2026-10-08.md`)
|
||
|
||
- **Slideshow:** Febrü „Active 2.0 Büro“ an Position 4, „Elements Soul Großraum“ an Position 9 (WebP 1920 px).
|
||
- **Regional verbunden:** Arminia, TC Bad Salzuflen, TC Hiddenhausen (Logo war schon da, hieß „TC Hövelhof“),
|
||
TC Blau Weiss Halle – einheitliche Kurztexte, Kachel verlinkt auf die Vereinsseite, wo eine URL gepflegt ist
|
||
(neues Feld `url`, neuer Tab). TC Bad Waldliesborn-Horn raus, alte Logos im Archiv `archiv-2026-10-08/`.
|
||
- **Ablauf Maßanfertigung überall gleich:** Foto / Grundriss + grobe Maße → Beratung → Planung & Angebot →
|
||
Angebotsannahme → Anzahlung → professionelles Aufmaß → Feinplanung / Fertigungsfreigabe → Bestellung / Fertigung.
|
||
Angepasst: CABINET (Ablauf, „Aufmaß vor Ort“), Herkunft (Ablauf am Beispiel CABINET), Marken-Netzwerk
|
||
(„Planung & Aufmaß“), Über uns (Zitat), FAQ (Beratung, Kosten).
|
||
- **Magazin:** Maßanfertigungs-Beitrag neu (Text von Marcel); Beitragsseite kann jetzt Absätze (Leerzeile im Text);
|
||
Abschluss „Weitere Einblicke rund um Einrichtung, Planung und Projekte …“; „Supply-Chain“ und „Local for Local“
|
||
offline; Datum und Lesezeit deutsch („26. August 2026 · 5 Min. Lesezeit“).
|
||
- **FAQ Projektausstattung** nach heutiger Positionierung (ein Vertragspartner, Koordination, Netzwerk) ohne
|
||
Garantie-/Eskalationssprache. **Otterpohl:** „Das erhöht die Planungssicherheit deutlich.“
|
||
- Gemeinsamer Ersetzungs-Baustein `Database\Seeders\Concerns\ReplacesCmsTexts` (auch vom Lektorats-Seeder genutzt).
|
||
|
||
**Nachbesserung 08.10.:** Hero mobil – die Infokarte steht unter dem Bild (Bild 4:3 oben, Karte als weißer
|
||
Streifen darunter), ab lg schwebt sie wie bisher unten links. Karte weiß statt `bg-card`, damit die
|
||
Glass-Flow-Regel `[class*="card"]` nicht greift; `absolute!` entfällt.
|
||
|
||
|
||
---
|
||
|
||
## Nachtrag 32 · Git-Deploy, Monitoring und Ablauf für den Livegang (08.10.2026)
|
||
|
||
- **Git-Deploy per Tag:** `dev/betrieb/deploy.sh` (aus `dev/git-deploy-monitoring/`) liefert nur Tags aus,
|
||
`origin` = forge.adametz.media, `NAS` = Sicherung. `public/build` ist jetzt versioniert. Neu:
|
||
`--seed=<Klasse>` (Seeder im Wartungsmodus) und `--initial` (Vorschau und Live einmalig an Ort und
|
||
Stelle auf Git umstellen, mit Code-Sicherung und Parken der Nur-Server-Dateien).
|
||
`.gitignore`: Das macOS-Muster `Icon` traf `resources/views/flux/icon/`, die vier Icons wären mit
|
||
Git-Deploy auf Live verloren gegangen; das Muster heißt jetzt `Icon[\r]`.
|
||
- **Monitoring:** GlitchTip (Server und Browser, Website und Portal), `/health` mit Token (jede Domain,
|
||
ohne Basic Auth), Scheduler-Herzschlag, Alarme bei fehlgeschlagenen Tasks per Mail und ntfy,
|
||
Version in `php artisan about` und `/health`. Pakete: `sentry/sentry-laravel`, `@sentry/browser`.
|
||
- **Livegang ohne Datenmigration:** Die Live-Datenbank bleibt die Grundlage (Displays, Playlists,
|
||
Mediathek, Benutzer), `InteriorReleaseSeeder` bringt die Website-Inhalte in einem Lauf auf den neuen
|
||
Stand. Er fasst alle Seeder aus 8.2 und „Seeder für das nächste Deployment“ zusammen, ist idempotent
|
||
(Test) und lässt Display-Daten unberührt. Ausnahme: Branding, nur bei Modulen ohne Interior-Logo;
|
||
`DisplayInteriorBrandingSeeder` überschreibt seit heute keinen inzwischen gepflegten Claim mehr.
|
||
Generalprobe: `dev/betrieb/vorschau-auffrischen.sh` kopiert Live-DB und Live-Medien in die Vorschau.
|
||
- **Ablauf:** `dev/betrieb/README.md`. Er ersetzt für den Livegang die Einzelbefehle aus 8.2 und die
|
||
Seeder-Liste oben. Die Prüfliste 8.3 gilt weiter.
|
||
- **Offen:** Datenschutzerklärung um die Fehlerprotokollierung ergänzen, bevor die DSNs auf Live gesetzt
|
||
werden (Textvorschlag in `dev/betrieb/README.md`, Abschnitt 6).
|