Startseite ruhiger, Otterpohl mit Montage, Marken-Bilder und Farbwelt-Entwurf

- Hinweisleiste per B2IN_ANNOUNCEMENT_BAR ausgeblendet (Standard aus)
- Hero: „Räume aus einer Hand.“ als neue Überschrift, zweiter Button entfernt
- Projekttext mit zentralem deutschen Vertragspartner (Punkt statt Gedankenstrich)
- Otterpohl als vierte Kernmarke: Text v2, Abschnitt „Montage“, Titelbild getauscht
- Markenabschnitte: Absätze mit „- “ als Liste mit fetter Einleitung
- Titelbilder und Galerien für CABINET, Rotpunkt, Febrü und Otterpohl (WebP)
- Feedback 17.09. in den Markentexten, Demobilder entfernt, WhatsApp-Nummer
- Palette „Modern“ fest ohne Schalter, Entwurf /entwurf mit Hero-Slideshow
- Seeder-Liste fürs Deployment im Entwicklungsplan

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-10-01 10:34:21 +00:00
parent 3211569fee
commit 4b07bbdcae
124 changed files with 3618 additions and 496 deletions

View file

@ -0,0 +1,84 @@
<?php
namespace Database\Seeders;
use FluxCms\Core\Models\CmsContent;
use FluxCms\Core\Services\CmsContentService;
use Illuminate\Database\Seeder;
/**
* Projekttext auf der Startseite (Briefing Marcel 24.09.2026, Punkt 7; Nachtrag 19).
*
* In der Karte „Ausstattung für Ihr Projekt“ (home/audience_switch) wird „Mit deutscher
* Vertragssicherheit …“ durch „Mit einem zentralen deutschen Vertragspartner …“ ersetzt.
* Abstimmung 01.10.2026: Nach „Projektentwicklungen“ steht ein Punkt statt des Gedankenstrichs.
* Der Seeder tauscht nur genau diesen Satz, egal wo er im Sektions-JSON steht; alles andere
* bleibt. Steht der Satz nicht mehr drin, passiert nichts. Mehrfaches Ausführen ist unbedenklich.
*
* php artisan db:seed --class=AudienceSwitchProjectTextSeeder
*/
class AudienceSwitchProjectTextSeeder extends Seeder
{
/** @var array<string, string> alter Satz → neuer Satz */
public const REPLACEMENTS = [
'Mit deutscher Vertragssicherheit und einem eingespielten Herstellernetzwerk.' => 'Mit einem zentralen deutschen Vertragspartner und einem eingespielten Herstellernetzwerk.',
'With German contractual reliability and an established manufacturer network.' => 'With a single German contract partner and an established manufacturer network.',
'Projektentwicklungen – koordiniert aus einer Hand' => 'Projektentwicklungen. Koordiniert aus einer Hand',
'developments – coordinated from a single source' => 'developments. Coordinated from a single source',
];
public function run(): void
{
$row = CmsContent::query()->where('group', 'home')->where('key', 'audience_switch')->first();
if (! $row) {
$this->command?->info('Projekttext: Sektion home/audience_switch nicht im CMS – die Lang-Datei gilt.');
return;
}
$value = $row->getTranslations('value');
$count = 0;
$value = $this->replaceDeep($value, $count);
if ($count === 0) {
$this->command?->info('Projekttext: bereits aktuell, nichts geändert.');
return;
}
$row->value = $value;
$row->save();
app(CmsContentService::class)->clearCache('home');
$this->command?->info("Projekttext ersetzt ({$count} Stelle(n)).");
}
/**
* @param array<mixed> $data
* @return array<mixed>
*/
private function replaceDeep(array $data, int &$count): array
{
foreach ($data as $key => $item) {
if (is_array($item)) {
$data[$key] = $this->replaceDeep($item, $count);
continue;
}
if (! is_string($item)) {
continue;
}
$replaced = strtr($item, self::REPLACEMENTS);
if ($replaced !== $item) {
$data[$key] = $replaced;
$count++;
}
}
return $data;
}
}

View file

@ -0,0 +1,162 @@
<?php
namespace Database\Seeders;
use App\Models\CmsBrand;
use Illuminate\Database\Seeder;
/**
* Trägt Titelbild und Galerie für CABINET, Rotpunkt, Febrü (Nachtrag 16) und Otterpohl (Nachtrag 19) nach.
*
* Grundlage: dev/2026-08-28/images/ (Zulieferungen vom 22.–24.09.2026). Die Originale sind 1–8 MB
* große JPEGs; unter public/img/assets/marken/{cabinet,rotpunkt,februe,otterpohl}/ liegen sie als
* WebP mit maximal 1920 px Kantenlänge (Imagick, Qualität 82, ohne Metadaten). Die mit `_title_`
* markierte Datei ist das Titelbild (Seitenkopf der Markenseite, Kachel auf der Startseite,
* Markenblock auf /marken). Die Galeriebilder der drei Hersteller stehen als **Visualisierung**:
* es sind Herstellerdarstellungen, keine von uns ausgeführten Projekte – unter „Referenzen“
* erscheinen sie damit nicht. Bei Otterpohl sind die Bilder 2–5 Einblicke in Werkstatt und
* Montage (**Aus der Werkstatt**, dazu das frühere Titelbild), alle übrigen ausgeführte Aufträge (**Realisiertes Projekt**);
* letztere erscheinen unter „Referenzen“, solange dort keine eigenen Einträge gepflegt sind.
*
* Verhalten: Das Titelbild wird nur gesetzt, wenn keins gepflegt ist. Galeriebilder werden
* nur ergänzt, wenn die Datei noch nicht in der Galerie steht; vorhandene Einträge bleiben
* samt Kategorie und Bildunterschrift, wie Marcel sie gepflegt hat. Mehrfaches Ausführen ist
* unbedenklich.
*
* php artisan db:seed --class=BrandImageSeeder
*/
class BrandImageSeeder extends Seeder
{
/**
* Galerie: Dateiname → Bildunterschrift (Kategorie Visualisierung) oder
* Dateiname → ['caption' => …, 'category' => …] für eine andere Kategorie.
*
* @var array<string, array{image: string, gallery: array<string, string|array{caption: string, category: string}>}>
*/
private const IMAGES = [
'cabinet' => [
'image' => 'marken/cabinet/ankleide-solitaer-eiche-tano.webp',
'gallery' => [
'marken/cabinet/dachschraegenschrank-filo-cashmere.webp' => 'Dachschrägenschrank in Filo Cashmere',
'marken/cabinet/schrank-gegen-schraege-marmor.webp' => 'Schrank gegen die Schräge in Marmoroptik',
'marken/cabinet/schlafzimmer-eiche-tano.webp' => 'Schlafzimmerschrank in Eiche Tano',
'marken/cabinet/schlafzimmer-velluto-fango.webp' => 'Schlafzimmerschrank in Velluto Fango',
'marken/cabinet/schlafzimmer-wandschrank-filo-cashmere.webp' => 'Wandschrank im Schlafzimmer in Filo Cashmere',
'marken/cabinet/garderobe-seite-offen.webp' => 'Garderobe mit offener Seite',
'marken/cabinet/garderobe-sitznische-filo-cashmere.webp' => 'Garderobe mit Sitznische in Filo Cashmere',
'marken/cabinet/drehtuerenschrank-marmor.webp' => 'Drehtürenschrank in Marmoroptik',
'marken/cabinet/flur-schrank-eiche-tano.webp' => 'Flurschrank in Eiche Tano',
'marken/cabinet/dachschraege-velluto-fango.webp' => 'Schrank unter der Dachschräge in Velluto Fango',
'marken/cabinet/ankleide-solitaer-eiche-tano-seite.webp' => 'Ankleide Solitär in Eiche Tano, Seitenansicht',
],
],
'rotpunkt' => [
'image' => 'marken/rotpunkt/kueche-01.webp',
'gallery' => [
'marken/rotpunkt/kueche-01-b.webp' => 'Küche 01, zweite Ansicht',
'marken/rotpunkt/kueche-02.webp' => 'Küche 02',
'marken/rotpunkt/kueche-03.webp' => 'Küche 03',
'marken/rotpunkt/kueche-04.webp' => 'Küche 04',
'marken/rotpunkt/kueche-05.webp' => 'Küche 05',
'marken/rotpunkt/kueche-06.webp' => 'Küche 06',
'marken/rotpunkt/kueche-06-b.webp' => 'Küche 06, zweite Ansicht',
'marken/rotpunkt/kueche-07.webp' => 'Küche 07',
'marken/rotpunkt/kueche-08.webp' => 'Küche 08',
'marken/rotpunkt/kueche-09.webp' => 'Küche 09',
'marken/rotpunkt/kueche-10.webp' => 'Küche 10',
'marken/rotpunkt/kueche-11.webp' => 'Küche 11',
'marken/rotpunkt/kueche-12.webp' => 'Küche 12',
],
],
// Bildunterschriften nach den Febrü-Produktlinien aus den Dateinamen.
'februe' => [
'image' => 'marken/februe/base-thekenloesung.webp',
'gallery' => [
'marken/februe/active-2-0-bureo.webp' => 'Active 2.0 mit Bureo',
'marken/februe/active-2-0-soul-grossraum.webp' => 'Großraum mit Active 2.0 und Soul',
'marken/februe/adesso.webp' => 'Adesso',
'marken/februe/arena-stage.webp' => 'Arena Stage',
'marken/februe/base.webp' => 'Base',
'marken/februe/base-sideboard.webp' => 'Base Sideboard',
'marken/februe/bobb-bionics-coworker-container-cube.webp' => 'Bobb, Bionics, CoWorker, Container und Cube',
'marken/februe/bobb.webp' => 'Bobb',
'marken/februe/brandon.webp' => 'Brandon',
'marken/februe/coworker.webp' => 'CoWorker',
'marken/februe/corporate.webp' => 'Corporate',
'marken/februe/curved-ben-basic.webp' => 'Curved, Ben und Basic',
'marken/februe/eline-one-silent-garderobenpaneel.webp' => 'E-Line, One, Silent und Garderobenpaneel',
'marken/februe/elements-soul-grossraum.webp' => 'Großraum mit Elements und Soul',
'marken/februe/vio.webp' => 'Vio',
],
],
// Otterpohl (Zulieferung 24.09.): Werkstattbilder und Referenzen. Seit 01.10. ist die Treppe mit
// Lamellenwand (tittle_otter.png) das Titelbild, das frühere Werkstatt-Titelbild steht in der
// Galerie – {@see OtterpohlBrandSeeder::swapTitleImage()} tauscht bestehende Installationen.
// Unterschriften ohne Kundennamen – die stehen nur in den Dateinamen der Zulieferung.
'tischlerei' => [
'image' => OtterpohlBrandSeeder::TITLE_IMAGE,
'gallery' => [
'marken/otterpohl/referenz-dziuballe-treppe.webp' => ['caption' => 'Treppe mit Holzstufen, Stufenbeleuchtung und Eichenhandlauf', 'category' => CmsBrand::GALLERY_PROJECT],
'marken/otterpohl/referenz-luecke-12.webp' => ['caption' => 'Tür und Kommode vor Lamellenwand', 'category' => CmsBrand::GALLERY_PROJECT],
'marken/otterpohl/referenz-neugebauer.webp' => ['caption' => 'Gewendelte Treppe mit Eichenstufen', 'category' => CmsBrand::GALLERY_PROJECT],
'marken/otterpohl/referenz-luecke-15.webp' => ['caption' => 'Beleuchtete Wandregale über Eck', 'category' => CmsBrand::GALLERY_PROJECT],
'marken/otterpohl/referenz-berkemeier-treppe.webp' => ['caption' => 'Treppe mit umlaufender Sockelleiste und Lichtdetail', 'category' => CmsBrand::GALLERY_PROJECT],
'marken/otterpohl/referenz-objektbau-luecke-technik.webp' => ['caption' => 'Objektbau: Verkaufsraum mit Theke und Regalwand', 'category' => CmsBrand::GALLERY_PROJECT],
'marken/otterpohl/referenz-otterpohl-11.webp' => ['caption' => 'Sideboard mit Eichenplatte im Büro', 'category' => CmsBrand::GALLERY_PROJECT],
OtterpohlBrandSeeder::FORMER_TITLE_IMAGE => ['caption' => OtterpohlBrandSeeder::FORMER_TITLE_CAPTION, 'category' => CmsBrand::GALLERY_COMPANY],
'marken/otterpohl/werkstatt-02.webp' => ['caption' => 'CNC-Bearbeitungszentrum in der Fertigung', 'category' => CmsBrand::GALLERY_COMPANY],
'marken/otterpohl/werkstatt-03.webp' => ['caption' => 'Einbau einer Tür vor Ort', 'category' => CmsBrand::GALLERY_COMPANY],
'marken/otterpohl/werkstatt-04.webp' => ['caption' => 'Handwerkzeug in der Werkstatt', 'category' => CmsBrand::GALLERY_COMPANY],
'marken/otterpohl/werkstatt-05-lift.webp' => ['caption' => 'Anlieferung per Möbellift – Montage inklusive', 'category' => CmsBrand::GALLERY_COMPANY],
],
],
];
public function run(): void
{
foreach (self::IMAGES as $slug => $data) {
$brand = CmsBrand::query()->where('slug', $slug)->first();
if (! $brand) {
$this->command?->warn("Marke „{$slug}“ nicht gefunden – übersprungen.");
continue;
}
$titleSet = false;
if (trim((string) $brand->image) === '') {
$brand->image = $data['image'];
$titleSet = true;
}
$gallery = CmsBrand::normalizeGallery($brand->gallery);
$known = array_column($gallery, 'image');
$added = 0;
foreach ($data['gallery'] as $image => $entry) {
if (in_array($image, $known, true)) {
continue;
}
$gallery[] = [
'image' => $image,
'category' => is_array($entry) ? $entry['category'] : CmsBrand::GALLERY_INSPIRATION,
'caption' => is_array($entry) ? $entry['caption'] : $entry,
];
$added++;
}
$brand->gallery = $gallery;
$brand->save();
$this->command?->info(sprintf(
'Marke „%s“: Titelbild %s, %d Galeriebilder ergänzt, %d vorhanden.',
$slug,
$titleSet ? 'gesetzt' : 'behalten',
$added,
count($gallery) - $added,
));
}
}
}

View file

@ -15,6 +15,7 @@ use Illuminate\Database\Seeder;
* Rotpunkt Zeichenflaeche = Inhalt → fuellt die Box, gilt als Bezugsgroesse
* CABINET Zeichenflaeche rechts +18 % → rendert 15 % kleiner als Rotpunkt
* Februe Zeichenflaeche oben/unten +20 % → rendert wie vor der Abstimmung
* Otterpohl knapp beschnitten, weiss freigestellt (Zulieferung 17.09.2026, Nachtrag 15)
*
* Alle drei waren in der Zulieferung sehr unterschiedlich stark umrandet (CABINET nutzte nur
* 29 Prozent der Hoehe) und wirkten dadurch ungleich gross. Die Abstimmung steckt bewusst in den
@ -38,6 +39,7 @@ class BrandLogoSeeder extends Seeder
'cabinet' => 'marken/cabinet.svg',
'rotpunkt' => 'marken/rotpunkt.svg',
'februe' => 'marken/februe.png',
'tischlerei' => 'marken/otterpohl.png',
];
public function run(): void

View file

@ -51,8 +51,8 @@ class BrandOriginSeeder extends Seeder
'origin_city' => ['de' => 'Rheda-Wiedenbrück', 'en' => 'Rheda-Wiedenbrück'],
'origin_distance' => ['de' => 'rund 35 km', 'en' => 'about 35 km'],
'origin_role' => [
'de' => 'Unsere Werkstatt für Aufbau, Sonderlösungen und Veredelung.',
'en' => 'Our workshop for assembly, custom solutions and finishing.',
'de' => 'Tischlerei und Innenausbau aus Rheda-Wiedenbrück – vom einzelnen Möbel bis zum ganzen Raum, inklusive Montage.',
'en' => 'Joinery and interior fit-out from Rheda-Wiedenbrück – from a single piece to the whole room, installation included.',
],
],
];

View file

@ -22,6 +22,12 @@ use Illuminate\Database\Seeder;
* keine Zahlen, Zertifizierungen oder Herstelleraussagen, die niemand belegen kann. Er braucht
* die Freigabe durch Marcel Scheibe, bevor er live geht.
*
* Feedback 17.09.2026 (dev/2026-08-28/feedback-17-09-2026.md) eingearbeitet: CABINET Einstieg
* „Bild und grobes Maß“ und die Fragen vorab; Febrü „Kunden – keine Schubladen“, „Aus Herford“
* und „Wertschätzung“, doppelter Schlusssatz entfernt; Rotpunkt „Mehr als Küchen“. Die
* markeneigenen Handwerk-Abschnitte sind entfallen: das Thema steht als gemeinsamer Abschluss
* auf jeder Markenseite (Lang-Sektion `brand_craft`, siehe BrandDetail).
*
* ⚠️ Überschreibt bei bestehenden Marken **nur** die Felder aus {@see FIELDS}. Bilder, Galerie,
* Leistungen und Reihenfolge bleiben unangetastet, damit gepflegte Inhalte erhalten bleiben.
*
@ -95,11 +101,14 @@ class BrandPageTextSeeder extends Seeder
],
],
[
'title' => 'Aufmaß vor Ort statt Schätzung am Telefon',
'title' => 'Ein Bild und ein grobes Maß reichen für den Anfang',
'paragraphs' => [
'Jede Planung beginnt bei uns mit dem Aufmaß in Ihren Räumen. Das klingt selbstverständlich, ist es aber nicht: Wände sind selten exakt im Lot, Böden selten vollkommen eben, und alte Häuser halten regelmäßig Überraschungen bereit.',
'Wir messen deshalb vor Ort und planen mit den tatsächlichen Maßen. Das kostet zu Beginn etwas mehr Zeit und erspart am Montagetag die unangenehme Sorte Überraschung.',
'Für den Anfang reicht uns ein Bild und ein grobes Maß völlig aus.',
'Sie müssen also nicht erst alles millimetergenau ausmessen. Ein paar Fotos von der Raumsituation und die ungefähren Maße reichen, damit wir schon eine gute Planung machen und Ihnen ein konkretes Angebot erstellen können.',
'Danach gehen wir gemeinsam ins Detail: Aufteilung, Ausstattung, Materialien, Farben und natürlich der Preis.',
'Wenn alles grundsätzlich passt, kommen wir zum professionellen Aufmaß bei Ihnen vor Ort. Danach machen wir die Feinplanung fertig und geben den Schrank zur Bestellung frei.',
],
'claim' => 'So läuft’s: Foto + grobe Maße → Beratung → Planung & Angebot → Aufmaß vor Ort → Feinplanung → Bestellung',
],
[
'title' => 'Innen entscheidet sich, ob ein Schrank funktioniert',
@ -111,7 +120,7 @@ class BrandPageTextSeeder extends Seeder
'title' => 'Die Fragen, die wir vorher stellen',
'paragraphs' => [
'Wie viel Hängefläche wird wirklich gebraucht und wie viel Fachboden? Wo sollen Schuhe, Koffer, Bettwäsche, Sportsachen oder Weihnachtsdeko hin? Wer nutzt den Schrank – und wie groß ist diese Person?',
'Auch der weniger repräsentative Teil gehört dazu: Wäschekörbe, Bügelbrett, Staubsauger und die Kiste mit den Kabeln, die man aus Prinzip nicht wegwirft. Wird das vorher besprochen, muss es hinterher nicht improvisiert werden.',
'Auch die Dinge, die man nicht jeden Tag braucht, gehören in die Planung: Wäschekörbe, Bügelbrett, Staubsauger, Karnevalskostüme oder besondere Sportsachen. Wenn wir vorher wissen, was untergebracht werden soll, können wir den Platz direkt sinnvoll dafür einplanen.',
],
],
],
@ -153,15 +162,6 @@ class BrandPageTextSeeder extends Seeder
'Sie müssen sich also nicht allein auf unser Verkaufsgespräch verlassen, sondern entscheiden auf Grundlage dessen, was Sie tatsächlich gesehen und angefasst haben.',
],
],
[
'title' => 'Schranksystem plus Handwerk',
'paragraphs' => [
'CABINET deckt bereits eine große planerische Bandbreite ab. Es geht deshalb ausdrücklich nicht um Sonderanfertigungen um jeden Preis.',
'Natürlich gibt es trotzdem diesen einen Fall, bei dem selbst ein hervorragendes Maßsystem an seine Grenze kommt. Dann greift unsere dauerhaft verankerte Schnittstelle zu angeschlossenen Tischlereien – für den Übergang zur Architektur, die besondere Verkleidung oder den letzten Millimeter.',
'Wir wägen gestalterischen Mehrwert, technische Notwendigkeit und wirtschaftliche Sinnhaftigkeit ehrlich miteinander ab. Am Ende entscheiden aber Ihre Wünsche – nicht unser Drang, Ihnen noch eine Sonderlösung zu verkaufen.',
],
'claim' => 'Die Möglichkeiten eines Maßsystems. Die Flexibilität des Handwerks.',
],
],
],
'rotpunkt' => [
@ -235,9 +235,9 @@ class BrandPageTextSeeder extends Seeder
[
'title' => 'Mehr als Küchen',
'paragraphs' => [
'Die Möglichkeiten von Rotpunkt enden nicht bei der klassischen Küche. Das Möbel- und Planungssystem lässt sich auch für Hauswirtschaftsräume, Ankleiden, Badezimmer und weitere Wohnbereiche einsetzen.',
'Materialien, Farben und Gestaltungselemente können über mehrere Räume hinweg aufgegriffen werden. So entsteht nicht in jedem Zimmer eine neue Idee, sondern ein zusammenhängendes Interior-Konzept mit einer gemeinsamen gestalterischen Sprache.',
'Zusammen mit CABINET, Febrü und weiteren ausgewählten Partnern betrachten wir bei Bedarf den gesamten Innenraum – von Möbeln und Beleuchtung bis zu Tapeten, Fußböden und, wenn es sein soll, der letzten Blume.',
'Die Möglichkeiten von Rotpunkt enden nicht bei der klassischen Küche. Das Möbel- und Planungssystem lässt sich auch für Hauswirtschaftsräume, Badezimmer, Sideboards, Wohnmöbel und weitere Bereiche rund um das Wohnen einsetzen.',
'Materialien, Farben und Gestaltungselemente können dabei über mehrere Räume hinweg aufgegriffen werden. So entsteht ein stimmiges Gesamtbild, statt in jedem Raum wieder ganz von vorne anzufangen.',
'Bei Bedarf denken wir den Innenraum deshalb auch über die Küche hinaus – von Möbeln und Beleuchtung bis zu Tapeten, Fußböden und, wenn es sein soll, der letzten Blume.',
],
],
[
@ -257,22 +257,6 @@ class BrandPageTextSeeder extends Seeder
'Wir begleiten Sie dabei, ordnen die unterschiedlichen Möglichkeiten ein und führen Ihre Entscheidungen zu einem stimmigen Gesamtkonzept zusammen.',
],
],
[
'title' => 'Küchenstudio plus Handwerk',
'paragraphs' => [
'Rotpunkt deckt bereits eine enorme planerische und gestalterische Bandbreite ab. Es geht deshalb ausdrücklich nicht um Sonderanfertigungen um jeden Preis.',
'Natürlich gibt es trotzdem immer diesen einen planerischen Sonderfall, bei dem selbst hervorragende Standardsysteme an ihre Grenzen kommen. Dann greift unsere dauerhaft verankerte Schnittstelle zu angeschlossenen Tischlereien.',
'Wir wägen gestalterischen Mehrwert, technische Notwendigkeit und wirtschaftliche Sinnhaftigkeit ehrlich miteinander ab. Am Ende entscheiden aber Ihre Wünsche – nicht unser Drang, Ihnen unbedingt noch eine Sonderlösung zu verkaufen.',
],
'detail' => [
'title' => 'Wenn das Handwerk den letzten Millimeter übernimmt',
'paragraphs' => [
'Möglich sind beispielsweise passgenaue Nischenlösungen, besondere Verkleidungen, raumhohe Einbauten, Übergänge zu angrenzenden Möbeln oder individuelle Anpassungen an die vorhandene Architektur.',
'Bei Bedarf endet das Konzept nicht an der Arbeitsplatte. Auch Tapeten, Fußböden, Wandgestaltung, Beleuchtung und weitere Details können einbezogen werden.',
],
],
'claim' => 'Die Möglichkeiten eines modernen Küchenstudios. Die Flexibilität des Handwerks.',
],
],
],
'februe' => [
@ -299,9 +283,8 @@ class BrandPageTextSeeder extends Seeder
'detail' => [
'title' => 'Bei uns gibt es Kunden – keine Schubladen',
'paragraphs' => [
'B2B und B2C sind Begriffe aus Präsentationen und Vertriebsschulungen. Früher hieß es Privatkunde oder Firmenkunde. Oder, noch schlimmer: A-, B- oder C-Kunde. Bei diesem Schubladendenken machen wir nicht mit.',
'Natürlich beeinflusst die Menge den Preis. Wer fünfzig Arbeitsplätze einrichtet, erhält eine andere Kalkulation als jemand, der einen einzelnen Schreibtisch für sein Homeoffice sucht. Alles andere wäre weder ehrlich noch kaufmännisch sinnvoll.',
'Die Menge verändert aber weder die Qualität des Produktes noch die Sorgfalt der Planung, die persönliche Beratung oder den Service. Ein einzelner Arbeitsplatz im privaten Zuhause verdient dieselbe Aufmerksamkeit wie eine vollständige Büroetage.',
'Ob Privatkunde oder Unternehmen: Für uns gibt es zunächst einmal Kunden mit unterschiedlichen Räumen, Anforderungen und Stückzahlen.',
'Natürlich beeinflusst die Menge den Preis. Fünfzig Arbeitsplätze werden anders kalkuliert als ein einzelner Schreibtisch fürs Homeoffice. Der Anspruch an Produkt, Beratung und Service bleibt trotzdem derselbe.',
'Febrü bleibt Febrü. B2in bleibt B2in. Und jeder Kunde erhält eine Lösung, die zu seinem tatsächlichen Bedarf passt.',
],
],
@ -310,7 +293,7 @@ class BrandPageTextSeeder extends Seeder
[
'title' => 'Aus Herford. Für moderne Arbeitswelten.',
'paragraphs' => [
'Febrü entwickelt und produziert hochwertige Büromöbel direkt im ostwestfälischen Herford – nur wenige Kilometer von Bielefeld entfernt. Eine Fertigungstiefe von 95 Prozent ermöglicht kurze Wege, verlässliche Qualität und hohe Flexibilität bei Materialien, Farben und individuellen Anforderungen.',
'Febrü entwickelt und produziert hochwertige Büromöbel direkt im ostwestfälischen Herford – nur wenige Kilometer von Bielefeld entfernt. Eine sehr hohe Fertigungstiefe ermöglicht kurze Wege, verlässliche Qualität und hohe Flexibilität bei Materialien, Farben und individuellen Anforderungen.',
],
'detail' => [
'title' => 'Von einem Schreibtisch bis zum vollständigen Bürotrakt',
@ -348,7 +331,7 @@ class BrandPageTextSeeder extends Seeder
'title' => 'Wertschätzung ist keine Frage der Stückzahl',
'paragraphs' => [
'Gerade in Zeiten des Fachkräftemangels können Unternehmen es sich nicht leisten, Arbeitsbedingungen als Nebensache zu behandeln. Wer Top-Leistung erwartet, muss die passenden Voraussetzungen schaffen. Ein Obstkorb und kostenloses Wasser sind freundlich – ersetzen aber keinen guten Arbeitsplatz.',
'Besonders deutlich wird das bei teilzeitbeschäftigten Müttern – selbstverständlich genauso bei Vätern und allen anderen Menschen mit familiärer Sorgeverantwortung. Teilzeit bedeutet nicht halbe Leistung. Oft wird in einem kürzeren Zeitfenster hoch konzentriert gearbeitet, während neben dem nächsten Onlinemeeting gleichzeitig Schule, Termine, Betreuung und damit unsere wichtigste gemeinsame Ressource organisiert werden: unser Nachwuchs.',
'Besonders deutlich wird das bei Menschen, die Beruf und Familie miteinander organisieren. Teilzeit bedeutet nicht halbe Leistung. Oft wird in einem kürzeren Zeitfenster hoch konzentriert gearbeitet, während gleichzeitig Schule, Termine, Betreuung und der ganz normale Familienalltag organisiert werden müssen.',
'Gerade hier darf der Arbeitsplatz kein Provisorium aus Küchentisch, Beistelltisch oder Schlafzimmerecke sein. Er muss sofort funktionieren, Bewegung ermöglichen, technisch durchdacht sein und sich trotzdem vernünftig in das Zuhause einfügen. Für den Menschen, der ihn täglich nutzt, ist ein einzelner Arbeitsplatz keine kleine Lösung. Er ist seine vollständige Arbeitswelt.',
],
],
@ -447,7 +430,6 @@ class BrandPageTextSeeder extends Seeder
'Durch die Nähe zwischen Bielefeld und Herford können Febrü-Produkte nach Abstimmung persönlich erlebt werden. Wir organisieren und begleiten den Besuch der Ausstellung – für einen Schreibtisch genauso wie für einen vollständigen Unternehmensstandort.',
'Dort lassen sich Materialien anfassen, Stühle und Tische ausprobieren, Akustiklösungen erleben und unterschiedliche Arbeitswelten vergleichen. Sie müssen sich nicht allein auf ein Verkaufsgespräch verlassen.',
],
'claim' => 'Ob im Kleinen oder im Großen – die Detailtreue entscheidet.',
],
],
],

View file

@ -8,11 +8,9 @@ use Illuminate\Database\Seeder;
/**
* Legt die Kernmarken an. Texte aus dev/2026-08-28/umsetzung-inhalte.md §5.
*
* Die vierte Marke „Tischlerei“ (Arbeitsplan 14.09.2026, Punkt 1.2) ist ein **Platzhalter**:
* Name, Logo, Basisinfos und Bilder liegen noch nicht vor. Die Texte folgen der inhaltlichen
* Ausrichtung aus dem Plan (Aufbau, Sonderlösungen, Veredelung, Maßarbeit – ergänzt CABINET
* und Rotpunkt, steht nicht daneben) und sollen als Denkanstoß dienen. Der Name des
* Partnerbetriebs gehört laut Plan auf die Detailseite, nicht in die Marke.
* Die vierte Marke ist Otterpohl aus Rheda-Wiedenbrück (Arbeitsplan 14.09.2026, Punkt 1.2;
* Zulieferung 17.09.2026). Ihre Texte liegen in {@see OtterpohlBrandSeeder}, der sie bei
* bestehenden Installationen auch nachträgt. Der Slug „tischlerei“ bleibt stabil.
*
* Bestehende Marken werden nicht überschrieben – Marcel pflegt sie im Admin. Für bereits
* angelegte Marken setzt {@see BrandLogoSeeder} die Logos nach und {@see BrandOriginSeeder}
@ -164,92 +162,11 @@ Consultation and planning in our kitchen studio.',
],
'is_published' => true,
],
[
// ⚠️ Platzhalter – siehe Klassenkommentar. Slug bleibt stabil, auch wenn der Name kommt.
'slug' => 'tischlerei',
'logo' => '',
'name' => ['de' => 'Tischlerei', 'en' => 'Joinery'],
'tagline' => ['de' => 'Maßarbeit, die den Raum vollendet.', 'en' => 'Craftsmanship that completes the room.'],
'teaser' => [
'de' => 'Aufbau, Sonderlösungen und Veredelung aus einer Tischlerei in Ostwestfalen – dort, wo Serienmöbel aufhören und Ihr Raum anfängt.',
'en' => 'Assembly, bespoke solutions and finishing from a joinery in East Westphalia – where series furniture ends and your room begins.',
],
'summary' => [
'de' => 'Manche Stellen im Raum passen in keinen Katalog: die Nische neben dem Kamin, der Übergang von der Küche zum Sideboard, das Regal unter der Treppe. Unsere Tischlerei baut, was dort fehlt – und veredelt, was schon da ist.
Sie ergänzt CABINET und Rotpunkt dort, wo Fertigung nach Zeichnung gefragt ist: Aufbau vor Ort, Sonderlösungen nach Aufmaß, Oberflächen und Anpassungen aus einer Hand.',
'en' => 'Some spots in a room fit no catalogue: the alcove next to the fireplace, the transition from kitchen to sideboard, the shelf under the stairs. Our joinery builds what is missing there – and refines what is already in place.
It complements CABINET and Rotpunkt wherever making to drawing is required: assembly on site, bespoke solutions to measure, surfaces and adaptations from a single source.',
],
'highlights' => [
'Sonderlösungen nach Aufmaß und Zeichnung',
'Veredelung und Anpassung bestehender Möbel',
'Aufbau und Montage aus einer Hand',
],
'description' => [
'de' => '<p>Eine Küche endet nicht an der letzten Front, ein Einbauschrank nicht an der Wand. Dazwischen liegen die Details, die einen Raum fertig machen: eine Blende, die den Übergang schließt, ein Regal, das genau in die Nische passt, eine Oberfläche, die zum Boden passt. Unsere Tischlerei fertigt diese Details in Ostwestfalen – nach Zeichnung, nach Aufmaß, in Abstimmung mit den Marken, die den Raum tragen.</p>',
'en' => '<p>A kitchen does not end at the last front, a fitted wardrobe not at the wall. In between lie the details that finish a room. Our joinery makes these details in East Westphalia – to drawing, to measure, in tune with the brands that carry the room.</p>',
],
'services' => [
['title' => 'Aufbau und Montage', 'description' => 'Fachgerechter Aufbau vor Ort – auch von Möbeln, die nicht von uns stammen.'],
['title' => 'Sonderlösungen', 'description' => 'Nischen, Schrägen, Übergänge: gefertigt nach Aufmaß, wo Standard nicht passt.'],
['title' => 'Veredelung', 'description' => 'Oberflächen, Fronten und Griffe – bestehende Möbel aufwerten statt ersetzen.'],
['title' => 'Maßarbeit', 'description' => 'Einzelstücke nach Zeichnung: Regale, Sideboards, Garderoben, Tische.'],
],
'widget_label' => ['de' => 'Persönliche Beratung zur Maßarbeit vereinbaren', 'en' => 'Arrange a personal consultation on bespoke work'],
'cta_title' => ['de' => 'Ihr Raum. Bis ins Detail gefertigt.', 'en' => 'Your room. Made down to the detail.'],
'cta_text' => [
'de' => 'Ob ein einzelnes Regal in der Nische oder die Anpassung einer ganzen Einrichtung: Wir schauen uns Ihren Raum an und sagen Ihnen, was sich fertigen lässt – und was sich lohnt. Persönlich, vor Ort und mit einer Werkstatt, die wir kennen.',
'en' => 'Whether a single shelf in an alcove or the adaptation of an entire interior: we look at your room and tell you what can be made – and what is worth it.',
],
'sections' => [
[
'title' => 'Wo Serienmöbel aufhören.',
'paragraphs' => [
'Die meisten Räume sind nicht rechtwinklig, nicht genormt und nicht leer. Sie haben Heizkörper, Fensterbänke, Schrägen und Möbel, die bleiben sollen. Genau dort beginnt die Arbeit der Tischlerei: mit einem Aufmaß, einer Zeichnung und der Frage, was der Raum wirklich braucht.',
'Das kann ein einzelnes Möbelstück sein, eine Anpassung an ein bestehendes oder ein Detail, das zwei Marken miteinander verbindet.',
],
'detail' => [
'title' => 'Beispiele aus dem Alltag',
'paragraphs' => [
'Ein Sideboard, das die Flucht der Rotpunkt-Küche aufnimmt und im Wohnzimmer weiterführt. Eine Blende, die den Spalt zwischen CABINET-Schrank und Dachschräge schließt. Ein Regal unter der Treppe, das die Tiefe der Stufen nutzt. Eine Bank am Fenster mit Stauraum darunter.',
'Nichts davon steht in einem Katalog. Alles davon lässt sich fertigen.',
],
],
'claim' => 'Gefertigt nach Raum, nicht nach Norm.',
],
[
'title' => 'Ergänzung, nicht Konkurrenz.',
'paragraphs' => [
'CABINET plant Einbauschränke bis auf den Millimeter, Rotpunkt baut Küchen, Febrü richtet Arbeitsplätze ein. Die Tischlerei steht nicht daneben, sondern dazwischen: Sie fertigt die Übergänge, die Sonderteile und die Einzelstücke, mit denen aus drei Marken ein durchgängiger Raum wird.',
],
'detail' => [
'title' => 'Aus der Region gefertigt',
'paragraphs' => [
'Die Werkstatt liegt in Ostwestfalen, wenige Kilometer von Bielefeld. Kurze Wege bedeuten kurze Abstimmungen: Aufmaß, Muster und Montage kommen aus einer Hand, und wenn etwas nicht passt, ist die Werkstatt erreichbar – nicht ein Callcenter.',
],
],
'claim' => 'Vier Marken. Ein Raum. Ein Ansprechpartner.',
],
[
'title' => 'Veredeln statt ersetzen.',
'paragraphs' => [
'Nicht jedes Möbel muss neu sein. Ein guter Korpus mit neuen Fronten, eine geölte statt lackierte Oberfläche, neue Griffe und eine passende Innenaufteilung – oft ist das die nachhaltigere und die schönere Lösung.',
'Wir sagen Ihnen ehrlich, wann sich eine Veredelung lohnt und wann nicht.',
],
'claim' => 'Was gut ist, darf bleiben – und besser werden.',
],
],
'showroom' => '',
'origin_city' => ['de' => 'Rheda-Wiedenbrück', 'en' => 'Rheda-Wiedenbrück'],
'origin_distance' => ['de' => 'rund 35 km', 'en' => 'about 35 km'],
'origin_role' => [
'de' => 'Unsere Werkstatt für Aufbau, Sonderlösungen und Veredelung.',
'en' => 'Our workshop for assembly, custom solutions and finishing.',
],
'is_published' => true,
],
// Vierte Kernmarke Otterpohl (Nachtrag 15). Slug bleibt „tischlerei“, Texte aus OtterpohlBrandSeeder.
array_merge(OtterpohlBrandSeeder::data(), [
'slug' => OtterpohlBrandSeeder::SLUG,
'logo' => OtterpohlBrandSeeder::LOGO,
]),
];
}
}

View file

@ -0,0 +1,52 @@
<?php
namespace Database\Seeders;
use App\Models\CmsBrand;
use Illuminate\Database\Seeder;
/**
* Entfernt die Demobilder aus den Markengalerien (Nachtrag 17).
*
* {@see DemoBrandGallerySeeder} hatte Stockmotive und KI-Renderings der alten Dubai-Seite als
* Beispiele in die Galerien von CABINET, Rotpunkt und Febrü gelegt. Seit den echten Bildern
* (Nachtrag 16) sollen sie weg. Erkannt werden sie am Dateinamen aus dem Demo-Seeder – nicht an
* der Bildunterschrift, denn den Vermerk „BEISPIEL“ hat {@see BrandGalleryCaptionNormalizerSeeder}
* auf der Vorschau bereits entfernt. Alle anderen Galeriebilder bleiben samt Kategorie,
* Unterschrift und Reihenfolge. Mehrfaches Ausführen ist unbedenklich.
*
* php artisan db:seed --class=DemoBrandGalleryCleanupSeeder
*/
class DemoBrandGalleryCleanupSeeder extends Seeder
{
public function run(): void
{
$demoImages = [];
foreach (DemoBrandGallerySeeder::GALLERIES as $items) {
foreach ($items as $item) {
$demoImages[] = $item[0];
}
}
$removed = 0;
foreach (CmsBrand::query()->whereNotNull('gallery')->get() as $brand) {
$gallery = CmsBrand::normalizeGallery($brand->gallery);
$kept = array_values(array_filter(
$gallery,
fn (array $item) => ! in_array($item['image'], $demoImages, true),
));
if (count($kept) === count($gallery)) {
continue;
}
$removed += count($gallery) - count($kept);
$brand->gallery = $kept;
$brand->save();
}
$this->command?->info("Demobilder aus den Galerien entfernt: {$removed}.");
}
}

View file

@ -17,8 +17,8 @@ use Illuminate\Database\Seeder;
* bzw. „Visualisierung“) – die Motive der Kategorie `project` muessen deshalb vor dem Livegang
* durch echte Referenzen ersetzt werden. Steht als Punkt in der Deployment-Checkliste.
*
* Wieder entfernen:
* php artisan tinker --execute="App\Models\CmsBrand::query()->update(['gallery' => null]);"
* Wieder entfernen – nur die Demobilder, gepflegte Bilder bleiben:
* php artisan db:seed --class=DemoBrandGalleryCleanupSeeder
*/
class DemoBrandGallerySeeder extends Seeder
{
@ -27,7 +27,7 @@ class DemoBrandGallerySeeder extends Seeder
*
* @var array<string, list<array{0: string, 1: string, 2: string}>>
*/
private const GALLERIES = [
public const GALLERIES = [
'cabinet' => [
['b2a.webp', CmsBrand::GALLERY_PROJECT, 'Wohnwand mit Einbauregal, Bielefeld'],
['hero-room.webp', CmsBrand::GALLERY_PROJECT, 'Wohnbereich mit Raumteiler'],

View file

@ -0,0 +1,79 @@
<?php
namespace Database\Seeders;
use FluxCms\Core\Models\CmsContent;
use FluxCms\Core\Services\CmsContentService;
use Illuminate\Database\Seeder;
/**
* Hero der Startseite (Abstimmung 01.10.2026, Briefing Marcel 24.09.2026 Punkte 3 und 5).
*
* Setzt im CMS-Eintrag home/hero die neue Überschrift „Räume aus einer Hand. Mit starken Marken
* und persönlichen Lösungen.“ und entfernt den zweiten Button „Termin anfragen“ (der feste
* Termin-Button unten rechts bleibt). Die Überschrift wird nur ersetzt, solange noch die alte
* „B2in Interior – Premium-Einrichtung …“ drinsteht – eine eigene Formulierung im CMS bleibt.
* Mehrfaches Ausführen ist unbedenklich.
*
* php artisan db:seed --class=HomeHeroTextSeeder
*/
class HomeHeroTextSeeder extends Seeder
{
/** @var array<string, array{old: string, new: string}> */
public const TITLES = [
'de' => [
'old' => 'Premium-Einrichtung von starken Marken',
'new' => '<span class="text-secondary">Räume aus einer Hand.</span><br>Mit starken Marken und persönlichen Lösungen.',
],
'en' => [
'old' => 'Premium furnishing from strong brands',
'new' => '<span class="text-secondary">Spaces from a single source.</span><br>With strong brands and personal solutions.',
],
];
public function run(): void
{
$row = CmsContent::query()->where('group', 'home')->where('key', 'hero')->first();
if (! $row) {
$this->command?->info('Hero: Sektion home/hero nicht im CMS – die Lang-Datei gilt.');
return;
}
$value = $row->getTranslations('value');
$changed = false;
foreach ($value as $locale => $content) {
if (! is_array($content)) {
continue;
}
$title = self::TITLES[$locale] ?? null;
if ($title && str_contains((string) ($content['title'] ?? ''), $title['old'])) {
$content['title'] = $title['new'];
$changed = true;
}
if (array_key_exists('cta2_text', $content) || array_key_exists('cta2_link', $content)) {
unset($content['cta2_text'], $content['cta2_link']);
$changed = true;
}
$value[$locale] = $content;
}
if (! $changed) {
$this->command?->info('Hero: bereits aktuell, nichts geändert.');
return;
}
$row->value = $value;
$row->save();
app(CmsContentService::class)->clearCache('home');
$this->command?->info('Hero: Überschrift gesetzt, zweiter Button entfernt.');
}
}

View file

@ -0,0 +1,193 @@
<?php
namespace Database\Seeders;
use App\Models\CmsBrand;
use Illuminate\Database\Seeder;
/**
* Otterpohl Möbelservice, Rheda-Wiedenbrück – die vierte Kernmarke (Nachtrag 15, Text v2 in Nachtrag 19).
*
* Ersetzt den Platzhalter „Tischlerei“ aus Nachtrag 9 durch die Zulieferung:
* dev/2026-08-28/otterpohl_Webseitentext_FINAL_v2.md (Text vom 24.09.2026, Überschriften 1:1 übernommen;
* löst die lange Fassung vom 17.09. ab)
* dev/2026-08-28/markenlogos/otterpohl.jpg (Logo, freigestellt nach public/img/assets/marken/)
*
* Der Slug `tischlerei` bleibt stabil (Links, Widget-Thema, Kartenposition der Herkunfts-Sektion).
* Überschrieben werden Name, Claim, Texte, Leistungen, Abschnitte, Abschlussblock und
* Fertigungsort. Bild, Galerie und Reihenfolge bleiben, das Logo wird nur gesetzt, wenn es leer ist.
* Ausnahme seit 01.10.2026: Steht noch das alte Werkstatt-Titelbild drin, tauscht es mit der
* Treppe aus der Galerie ({@see swapTitleImage()}). Dazu kam der Abschnitt „Montage“.
* {@see CmsBrandSeeder} nutzt dieselben Daten für frische Installationen.
*
* php artisan db:seed --class=OtterpohlBrandSeeder
*/
class OtterpohlBrandSeeder extends Seeder
{
public const SLUG = 'tischlerei';
public const LOGO = 'marken/otterpohl.png';
/** Titelbild seit 01.10.2026: dev/2026-08-28/images/otten/tittle_otter.png als WebP. */
public const TITLE_IMAGE = 'marken/otterpohl/titel-treppe.webp';
/** Titelbild bis 01.10.2026 – rückt in die Galerie. */
public const FORMER_TITLE_IMAGE = 'marken/otterpohl/werkstatt-titel.webp';
public const FORMER_TITLE_CAPTION = 'Fertigung in der Werkstatt in Rheda-Wiedenbrück';
/** Galeriebild mit demselben Motiv wie das neue Titelbild – fällt beim Tausch heraus. */
public const TITLE_IMAGE_IN_GALLERY = 'marken/otterpohl/referenz-luecke-01.webp';
public function run(): void
{
$brand = CmsBrand::query()->where('slug', self::SLUG)->first();
if (! $brand) {
$this->command?->warn('Marke „'.self::SLUG.'“ nicht gefunden – erst CmsBrandSeeder ausführen.');
return;
}
$brand->fill(self::data());
if (trim((string) $brand->logo) === '') {
$brand->logo = self::LOGO;
}
$swapped = self::swapTitleImage($brand);
$brand->save();
$this->command?->info('Otterpohl: Marke „'.self::SLUG.'“ mit den Texten vom 24.09.2026 (v2) und dem Abschnitt „Montage“ aktualisiert'
.($swapped ? ', Titelbild getauscht.' : '.'));
}
/**
* Tauscht Titelbild und Produktbild (Abstimmung 01.10.2026): Die Treppe mit Lamellenwand wird
* Titelbild, das bisherige Werkstattbild nimmt ihren Platz in der Galerie ein (Aus der Werkstatt).
*
* Nur solange noch das alte Titelbild gesetzt ist – ein im Backend gewähltes Bild bleibt.
*/
public static function swapTitleImage(CmsBrand $brand): bool
{
if ($brand->image !== self::FORMER_TITLE_IMAGE) {
return false;
}
$brand->image = self::TITLE_IMAGE;
$gallery = CmsBrand::normalizeGallery($brand->gallery);
$former = ['image' => self::FORMER_TITLE_IMAGE, 'category' => CmsBrand::GALLERY_COMPANY, 'caption' => self::FORMER_TITLE_CAPTION];
$position = array_search(self::TITLE_IMAGE_IN_GALLERY, array_column($gallery, 'image'), true);
if ($position !== false) {
$gallery[$position] = $former;
} elseif (! in_array(self::FORMER_TITLE_IMAGE, array_column($gallery, 'image'), true)) {
$gallery[] = $former;
}
$brand->gallery = array_values($gallery);
return true;
}
/**
* Alle Textfelder der Marke. Ohne slug, logo, image, gallery, order.
*
* Reihenfolge wie in der Zulieferung v2: Einleitung „Wollmilchsau“, zwei Abschnitte, die acht
* Leistungen, zum Schluss „Das Ganze statt nur das Einzelne“ – der steht als Abschlussblock
* (cta_title/cta_text), damit er auf der Seite hinter Leistungen und Galerie bleibt.
*
* @return array<string, mixed>
*/
public static function data(): array
{
return [
'name' => ['de' => 'Otterpohl Möbelservice', 'en' => 'Otterpohl Möbelservice'],
'tagline' => ['de' => 'Nicht easy click & buy. Aber dennoch easy to get.', 'en' => 'Not easy click & buy. But still easy to get.'],
'teaser' => [
'de' => 'Individuelle Möbel, Türen, Treppen, Küchen, Wandverkleidungen und Objektbau – bis hin zum kompletten Innenausbau. Tischlerhandwerk aus Rheda-Wiedenbrück.',
'en' => 'Bespoke furniture, doors, stairs, kitchens, wall cladding and contract work – up to complete interior fit-outs. Joinery from Rheda-Wiedenbrück.',
],
'summary' => [
'de' => 'Individuelle Möbel. Türen. Treppen. Küchen. Wandverkleidungen. Objektbau. Sonderanfertigungen. Lackierungen und Echtholzfurniere. Bis hin zum kompletten Innenausbau. Mit Otterpohl Möbelservice haben wir einen Partner an unserer Seite, bei dem die Möglichkeiten nicht am einzelnen Möbelstück aufhören.
Denn manchmal braucht ein Raum mehr als einen Schrank oder ein Sideboard. Vielleicht soll eine Treppe Teil des Gestaltungskonzepts werden. Eine Wand erhält eine individuelle Holzverkleidung. Oder Möbel, Materialien und bauliche Elemente müssen so zusammenspielen, dass am Ende alles wie aus einem Guss wirkt. Genau dort beginnt der individuelle Innenausbau.',
'en' => 'Bespoke furniture. Doors. Stairs. Kitchens. Wall cladding. Contract work. Special constructions. Lacquer and real-wood veneer. Up to complete interior fit-outs. With Otterpohl Möbelservice we have a partner whose possibilities do not end at the single piece of furniture.
Sometimes a room needs more than a wardrobe or a sideboard. A staircase becomes part of the design. A wall gets individual wood cladding. Or furniture, materials and built elements have to work together so that everything looks as if cast from one mould. That is where individual interior fit-out begins.',
],
'highlights' => [
'Individuelle Möbel, Türen, Treppen und Küchen',
'Innenausbau, Objektbau, Lack und Echtholzfurnier',
'Planung und Handwerk aus einer Hand – inklusive Montage',
],
'description' => ['de' => '', 'en' => ''],
'services' => [
['title' => 'Individuelle Möbel & Sonderanfertigungen', 'description' => 'Möbel nach Maß, besondere Konstruktionen und individuelle Lösungen – nach Planung, Idee, Skizze oder konkreter Anforderung.'],
['title' => 'Innenausbau', 'description' => 'Von einzelnen Ausbauarbeiten bis zum ganzheitlichen Raumkonzept – inklusive individueller Verkleidungen und maßgefertigter Einbauten.'],
['title' => 'Türen & Treppen', 'description' => 'Individuelle Türen, Treppen und konstruktive Lösungen, die sich in Architektur und Einrichtung einfügen.'],
['title' => 'Küchen', 'description' => 'Individuelle Küchenlösungen und handwerkliche Ergänzungen auch dort, wo klassische Küchenprogramme an ihre Grenzen kommen.'],
['title' => 'Wandverkleidungen & besondere Details', 'description' => 'Holzverkleidungen, Lamellen, Paneele und individuelle Gestaltungselemente, die Architektur und Einrichtung miteinander verbinden.'],
['title' => 'Objektbau', 'description' => 'Individuelle Lösungen für Büros, Verkaufsräume und gewerblich genutzte Flächen – vom Einzelmöbel bis zum kompletten Ausbau.'],
['title' => 'Lack & Echtholzfurnier', 'description' => 'Individuelle Lackierungen und Furniere für Lösungen, bei denen Farbe, Material und Oberfläche exakt aufeinander abgestimmt werden sollen.'],
['title' => 'Montage', 'description' => 'Die Umsetzung endet nicht bei der Fertigung. Entscheidend ist, dass Möbel, Ausbau und Raum am Ende auch vor Ort sauber zusammenkommen.'],
],
'sections' => [
[
'title' => 'Ziemlich nah an der eierlegenden Wollmilchsau',
'paragraphs' => [
'Der Begriff ist vielleicht nicht besonders elegant. Aber ganz falsch ist er nicht.',
'Individuelle Möbel. Türen. Treppen. Küchen. Wandverkleidungen. Objektbau. Sonderanfertigungen. Lackierungen und Echtholzfurniere. Bis hin zum kompletten Innenausbau.',
'Mit Otterpohl Möbelservice haben wir einen Partner an unserer Seite, bei dem die Möglichkeiten nicht am einzelnen Möbelstück aufhören.',
'Denn manchmal braucht ein Raum mehr als einen Schrank oder ein Sideboard. Vielleicht soll eine Treppe Teil des Gestaltungskonzepts werden. Eine Wand erhält eine individuelle Holzverkleidung. Eine Tür soll sich selbstverständlich in den Raum einfügen. Oder Möbel, Materialien und bauliche Elemente müssen so zusammenspielen, dass am Ende alles wie aus einem Guss wirkt.',
],
'claim' => 'Genau dort beginnt der individuelle Innenausbau.',
],
[
'title' => 'Vom einzelnen Möbel bis zum ganzen Raum',
'paragraphs' => [
'Wir arbeiten mit Herstellern, die schon sehr viele individuelle Möglichkeiten bieten. CABINET, Rotpunkt und Febrü geben uns dafür eine starke Basis. Aber es gibt Projekte, bei denen die Lösung darüber hinausgeht.',
'Mit Otterpohl Möbelservice können wir deshalb nicht nur individuelle Möbel und Sonderanfertigungen realisieren, sondern auch Türen, Treppen, Küchen, Wand- und Deckenverkleidungen sowie komplette Innenausbauten und Lösungen für den Objektbereich einbeziehen.',
],
'claim' => 'So können wir Räume ganzheitlicher denken – und Details nicht isoliert betrachten.',
],
[
'title' => 'Planung trifft Handwerk',
'paragraphs' => [
'Manchmal entsteht die beste Lösung aus einem Möbelprogramm. Manchmal braucht es eine individuelle Ergänzung. Und manchmal muss etwas komplett neu gedacht und gebaut werden. Genau diese Kombination macht für uns den Unterschied.',
'Wir planen den Raum und verbinden bei Bedarf unterschiedliche Hersteller, Materialien und handwerkliche Lösungen miteinander. Otterpohl Möbelservice ergänzt diese Planung um die Möglichkeiten einer klassischen Tischlerei und eines erfahrenen Innenausbauers.',
],
'claim' => 'Das Ergebnis kann ein einzelnes Möbel sein. Oder ein kompletter Raum.',
],
// Ergänzung vom 01.10.2026. Absätze mit „- “ erscheinen als Liste, der Teil vor dem
// ersten Doppelpunkt fett ({@see CmsBrand::paragraphBlocks()}).
[
'title' => 'Montage',
'paragraphs' => [
'Eine perfekte Montage ist keine Glückssache, sondern das Ergebnis starker Logistik. Wir sorgen dafür, dass alles Hand in Hand geht:',
'- Sichere Prüfung & Terminierung: Wir vereinbaren Ihren Montagetermin erst, wenn Ihre Lieferung vollständig und unversehrt bei uns geprüft wurde. Das garantiert Ihnen absolute Planungssicherheit.',
'- Perfekt vorbereitete Lieferung: Wir prüfen vorab die Anliefersituation bei Ihnen vor Ort. Die Lieferung erfolgt mit unserem modernen Fuhrpark, optimal geschützt durch Spezialfolien und Decken.',
'- Flexibler Renovierungsschutz: Ihr Bauprojekt verzögert sich? Kein Problem. Wir lagern Ihre Möbel fachgerecht und sicher ein.',
'- Erweiterter Komfort: Auf Wunsch liefern wir Umzugskartons, lagern Möbel zwischen oder passen vorhandene Möbelstücke direkt an.',
],
],
],
'widget_label' => ['de' => 'Persönliche Beratung zur Maßarbeit vereinbaren', 'en' => 'Arrange a personal consultation on bespoke work'],
'cta_title' => ['de' => 'Das Ganze statt nur das Einzelne', 'en' => 'The whole, not just the single piece'],
'cta_text' => [
'de' => 'Genau deshalb passt Otterpohl Möbelservice zu unserem Ansatz: Wir möchten Räume nicht in einzelne Gewerke zerlegen, sondern Lösungen schaffen, bei denen Möbel, Materialien, Architektur und handwerkliche Details zusammenpassen. Mal braucht es dafür einen Hersteller. Mal einen Tischler. Und manchmal beides. Nicht easy click & buy. Aber dennoch easy to get.',
'en' => 'That is why Otterpohl Möbelservice fits our approach: we do not want to split rooms into single trades, but create solutions where furniture, materials, architecture and craft details belong together. Sometimes that takes a manufacturer. Sometimes a joiner. And sometimes both. Not easy click & buy. But still easy to get.',
],
'origin_city' => ['de' => 'Rheda-Wiedenbrück', 'en' => 'Rheda-Wiedenbrück'],
'origin_distance' => ['de' => 'rund 35 km', 'en' => 'about 35 km'],
'origin_role' => [
'de' => 'Tischlerei und Innenausbau aus Rheda-Wiedenbrück – vom einzelnen Möbel bis zum ganzen Raum, inklusive Montage.',
'en' => 'Joinery and interior fit-out from Rheda-Wiedenbrück – from a single piece to the whole room, installation included.',
],
'showroom' => '',
'is_published' => true,
];
}
}

View file

@ -0,0 +1,83 @@
<?php
namespace Database\Seeders;
use FluxCms\Core\Models\CmsContent;
use FluxCms\Core\Services\CmsContentService;
use Illuminate\Database\Seeder;
/**
* Hinterlegt die WhatsApp-Business-Nummer des Stores (Abstimmung 23.09.2026, Nachtrag 18).
*
* Der WhatsApp-Button im Terminanfrage-Widget liest `global.contact.whatsapp`. Auf der Vorschau
* stand dort der Platzhalter „+49 151 00000000“ aus der ersten Einrichtung, danach kurz die
* falsche Nummer vom 23.09. Der Seeder trägt die echte Nummer ein, wenn das Feld leer ist oder
* einen dieser beiden Werte enthält; eine im Admin gepflegte andere Nummer bleibt stehen. Fehlt der Eintrag `global.contact` ganz, wird er
* angelegt. Mehrfaches Ausführen ist unbedenklich.
*
* php artisan db:seed --class=WhatsappNumberSeeder
*/
class WhatsappNumberSeeder extends Seeder
{
/** Business-Nummer laut Marcel (0521-98620100, korrigiert am 24.09.), international geschrieben. */
public const NUMBER = '+49 521 98620100';
/**
* Werte, die der Seeder ersetzt: der Platzhalter aus der ersten Einrichtung und die am 23.09.
* versehentlich eingetragene falsche Nummer (Zahlendreher in der Zulieferung).
*
* @var array<int, string>
*/
private const PLACEHOLDERS = ['+49 151 00000000', '+49 521 98610020'];
/** @var array<int, string> */
private const LOCALES = ['de', 'en'];
public function run(): void
{
$row = CmsContent::query()->where('group', 'global')->where('key', 'contact')->first();
if (! $row) {
CmsContent::create([
'group' => 'global',
'key' => 'contact',
'type' => 'json',
'value' => array_fill_keys(self::LOCALES, ['whatsapp' => self::NUMBER]),
'order' => 0,
]);
app(CmsContentService::class)->clearCache('global');
$this->command?->info('WhatsApp-Nummer: Eintrag global.contact angelegt.');
return;
}
$value = $row->getTranslations('value');
$changed = 0;
foreach (self::LOCALES as $locale) {
$section = is_array($value[$locale] ?? null) ? $value[$locale] : [];
$current = trim((string) ($section['whatsapp'] ?? ''));
if ($current !== '' && ! in_array($current, self::PLACEHOLDERS, true)) {
continue;
}
$section['whatsapp'] = self::NUMBER;
$value[$locale] = $section;
$changed++;
}
if ($changed === 0) {
$this->command?->info('WhatsApp-Nummer: bereits gepflegt, nichts geändert.');
return;
}
$row->value = $value;
$row->save();
app(CmsContentService::class)->clearCache('global');
$this->command?->info("WhatsApp-Nummer gesetzt ({$changed} Sprache(n)).");
}
}