Interior-Farbwelt, Welten-Trennung, Tischlerei und Herkunfts-Sektion

Arbeitsplan 14.09.2026, Punkte 1.1 bis 1.4 (Nachträge 6 bis 10 im Entwicklungsplan):

- Farbwelt Interior (Tanne, Creme, Sand, Ocker, Clay) als Standard, Immobilien-Welt
  behält das bisherige Blau über body.world-immobilien; Logo je Welt, Favicons neu,
  Welten-Wechsler in Kopf- und Fußzeile.
- Saubere Trennung der Welten: eigene Navigation, Ankündigungsleiste, Magazinliste,
  Über-uns-Seite, FAQ, Kontaktseite und Abschluss-CTA für Immobilien; Beiträge tragen
  eine Welt (Migration + Admin-Feld). Abschluss-CTA Ton in Ton statt Grün-zu-Ocker.
- Kontakt: Betreffe in Gruppen Interior / Immobilien / B2in, Marken darin.
  Terminanfrage-Buttons öffnen das Widget mit vorgewähltem Anliegen; Select-Felder
  einheitlich gestaltet.
- Tischlerei als vierte Kernmarke (Platzhalter), Kachelraster 2×2.
- Herkunfts-Sektion „Aus der Region gefertigt“ mit schematischer Standortkarte und
  Ablauf CABINET (Beratung Bielefeld, Fertigung Köln, Aufbau mit Tischlerei).

Deployment: migrate, WorldSplitCmsSeeder, CmsBrandSeeder, OriginSectionCmsSeeder
(Abschnitt 8 im Entwicklungsplan).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-15 12:46:41 +00:00
parent 1242d4bce8
commit 7953a8c9a1
137 changed files with 3840 additions and 589 deletions

View file

@ -23,6 +23,7 @@ class CmsArticleFactory extends Factory
'subtitle' => fake()->sentence(12),
'image' => 'b2in/magazin-'.fake()->numberBetween(1, 5).'.jpg',
'category' => fake()->randomElement(['Dubai Investment', 'Rendite & Einrichtung', 'B2B & Partner', 'Einrichtung & Netzwerk']),
'world' => CmsArticle::WORLD_INTERIOR,
'date_label' => fake()->date('F j, Y'),
'read_time' => fake()->numberBetween(3, 10).' min read',
'author' => [

View file

@ -0,0 +1,34 @@
<?php
use App\Models\CmsArticle;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Magazinbeiträge gehören zu einer Farbwelt (Interior oder Immobilien).
*
* Die drei Dubai-Beiträge aus dem Bestand werden direkt der Immobilien-Welt zugeordnet,
* damit sie nach der Trennung nicht in der Interior-Liste stehen.
*/
public function up(): void
{
Schema::table('cms_articles', function (Blueprint $table) {
$table->string('world', 20)->default(CmsArticle::WORLD_INTERIOR)->index()->after('category');
});
CmsArticle::query()
->whereIn('slug', CmsArticle::LEGACY_IMMOBILIEN_SLUGS)
->update(['world' => CmsArticle::WORLD_IMMOBILIEN]);
}
public function down(): void
{
Schema::table('cms_articles', function (Blueprint $table) {
$table->dropIndex(['world']);
$table->dropColumn('world');
});
}
};

View file

@ -70,6 +70,7 @@ class CmsArticleSeeder extends Seeder
],
'image' => (string) ($rowDe['image'] ?? ''),
'category' => (string) ($rowDe['category'] ?? ''),
'world' => (string) ($rowDe['world'] ?? CmsArticle::WORLD_INTERIOR),
'date_label' => (string) ($rowDe['date'] ?? ''),
'read_time' => (string) ($rowDe['readTime'] ?? ''),
'author' => is_array($rowDe['author'] ?? null) ? $rowDe['author'] : [],

View file

@ -6,7 +6,13 @@ use App\Models\CmsBrand;
use Illuminate\Database\Seeder;
/**
* Legt die drei Kernmarken an. Texte aus dev/2026-08-28/umsetzung-inhalte.md §5.
* 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.
*
* Bestehende Marken werden nicht überschrieben – Marcel pflegt sie im Admin. Für bereits
* angelegte Marken setzt {@see BrandLogoSeeder} die Logos nach.
@ -139,6 +145,86 @@ Consultation and planning in our kitchen studio.',
'showroom' => '',
'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' => '',
'is_published' => true,
],
];
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
/**
* Herkunfts-Sektion „Aus der Region gefertigt“ ins CMS legen (Arbeitsplan 14.09.2026, Punkt 1.3).
*
* Legt die Sektion nur an, wenn sie fehlt. Ein bestehender Eintrag bleibt unangetastet,
* damit Korrekturen aus dem Admin (Entfernungen, Ablauf CABINET) nicht verloren gehen.
*
* php artisan db:seed --class=OriginSectionCmsSeeder
*/
class OriginSectionCmsSeeder extends Seeder
{
/** @var array<int, string> */
private const SECTIONS = ['origin_section'];
public function run(): void
{
$seeder = new CmsContentSeeder;
$seeder->setCommand($this->command);
$seeder->onlySections = self::SECTIONS;
$seeder->run();
$this->command?->info('Herkunfts-Sektion: angelegt, falls sie fehlte.');
}
}

View file

@ -0,0 +1,63 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
/**
* Trennung der Welten Interior und Immobilien im CMS (Arbeitsplan 14.09.2026, Folge von 1.1).
*
* Zwei Schritte:
*
* 1. **Neue Sektionen anlegen**, falls sie fehlen: Navigation, Ankündigungsleiste, Magazinliste,
* Über-uns-Seite und FAQ der Immobilien-Welt. Bestehende Einträge bleiben unangetastet.
* 2. **Sektionen überschreiben**: die Hauptnavigation (ohne „Immobilien“ – der Welten-Wechsler
* übernimmt), die Einleitung der Magazinliste (ohne Dubai-Bezug) und das Kontaktformular
* beider Welten (Betreffe in Gruppen).
*
* ⚠️ Schritt 2 setzt genau diese beiden Sektionen auf den Stand der Lang-Dateien zurück.
* Vorher ein DB-Backup ziehen, falls die Navigation im Admin geändert wurde.
*
* php artisan db:seed --class=WorldSplitCmsSeeder
*/
class WorldSplitCmsSeeder extends Seeder
{
/** @var array<int, string> */
private const NEW_SECTIONS = [
'header_immobilien',
'announcement_bar_immobilien',
'magazin_list_immobilien',
'faq_immobilien',
'contact_form_immobilien',
'cta_section_immobilien',
'immobilien_about_hero',
'immobilien_our_story',
'immobilien_about_image_break',
'immobilien_our_values',
];
/** @var array<int, string> */
private const OVERWRITE_SECTIONS = [
'header',
'magazin_list',
// Betreffe in Gruppen (Interior / Immobilien / B2in) statt flacher Liste, 15.09.
'contact_form',
'contact_form_immobilien',
];
public function run(): void
{
$create = new CmsContentSeeder;
$create->setCommand($this->command);
$create->onlySections = self::NEW_SECTIONS;
$create->run();
$overwrite = new CmsContentSeeder;
$overwrite->setCommand($this->command);
$overwrite->onlySections = self::OVERWRITE_SECTIONS;
$overwrite->overwriteExisting = true;
$overwrite->run();
$this->command?->info('Welten-Trennung: '.count(self::NEW_SECTIONS).' Sektionen angelegt (falls fehlend), '.count(self::OVERWRITE_SECTIONS).' Interior-Sektionen aktualisiert.');
}
}