# B2in – Projektdokumentation **Stand:** 09.10.2026 · **Version:** v2.0.6 · **Live:** b2in.eu (Website), portal.b2in.eu (Portal) ## Projektübersicht B2in ist eine Laravel-Anwendung für mehrere Domains. Im Zentrum stehen zwei Teile: - **Website b2in.eu** mit zwei Welten. Die Welt **B2in Interior** zeigt hochwertige Einrichtung von CABINET, Rotpunkt Küchen, Febrü und Otterpohl Möbelservice, dazu Showroom, Magazin und Kontakt. Die Welt **Immobilien** betrifft internationale Projekte in Dubai. - **Portal portal.b2in.eu** mit Website-CMS, Store Displays mit Info-Tablet, Partnerverwaltung, Produkten, Regionen und Monitoring. Im Oktober 2026 ging der Interior-Relaunch live (v2.0.0). Seitdem wird per Git-Tag ausgeliefert und der Betrieb überwacht. Die Domains b2a, Stileigentum und Style2own bleiben erreichbar, werden aber nicht weiterentwickelt. --- ## Domains und Welten | Domain | Zweck | Oberfläche | |---|---|---| | `b2in.eu` | Website B2in Interior und Immobilien-Welt | Livewire, Tailwind CSS v4, eigenes Theme `b2in` | | `portal.b2in.eu` | Portal: CMS, Displays, Partner, Admin | Livewire, Volt, Flux UI Pro | | `cabinet.b2in.eu` | Display-Player und Short-Links im Showroom (`public/_cabinet`) | statisches HTML/JS, holt Daten über die Display-API | | b2a, Stileigentum, Style2own | Landingpages (geparkt) | eigene Themes | Die Welt einer Seite ergibt sich aus `b2in_world()` in `app/helpers.php`, das Logo je Welt aus `ThemeHelper::getLogoPath()`. | Welt | Farben | Schriften | |---|---|---| | Interior (Standard) | Tanne, Creme, Sand, Ocker (`#a8741f` als Akzent) | Inter, EB Garamond | | Immobilien | Anthrazit, Dynamic Blue | Inter, IBM Plex Sans | Lokal laufen die Domains unter `*.test` (siehe `CLAUDE.md`). --- ## Technik | Bereich | Einsatz | |---|---| | Framework | Laravel 12, PHP 8.4 | | Oberfläche | Livewire 4, Volt, Flux UI Pro 2, Alpine.js, Tailwind CSS v4 | | Anmeldung | Laravel Fortify, Sanctum, Rollen über Spatie Laravel-Permission | | Mehrsprachigkeit | Deutsch/Englisch: Lang-Dateien und Spatie Laravel-Translatable | | CMS | eigenes Paket `packages/flux-cms` (Inhalte, Mediathek) und App-Module (Marken, Magazin, Referenzen) | | Build | Vite, je Theme ein Build unter `public/build/`, Portal unter `public/build/portal` | | Fehler und Betrieb | GlitchTip (Sentry-SDK), `/health`, Uptime Kuma, ntfy | | Tests | Pest 3, SQLite im Arbeitsspeicher | | Entwicklung | Dev Container: `php`, `composer`, `npm` direkt, ohne Sail | --- ## Website B2in Interior ### Seiten | Pfad | Inhalt | |---|---| | `/` | Hero mit Bilder-Slideshow und Infokarte, Gründerleiste (Marcel Scheibe), Weiche Privat/Projekt, Kernmarken, „Aus der Region gefertigt“, „Gebaut auf Expertise und Vertrauen“, Vereine (Sponsoring), Live-Ansicht des Showroom-Displays, Immobilien-Teaser, Kontakt-CTA | | `/marken` | Hero, Gründerleiste, die vier Kernmarken, Bildpause mit Zitat, Herkunft, Netzwerk, Wachstum, CTA | | `/marken/{slug}` | Markenseite: Einleitung, Abschnitte mit aufklappbaren Vertiefungen, Leistungen, Galerie (Realisiertes Projekt / Aus der Werkstatt / Inspiration), Handwerk-Abschluss, weitere Marken | | `/about` | Mission, Gründerleiste, Geschichte, Werte, Partner-CTA | | `/magazin`, `/magazin/{slug}` | Magazin der Interior-Welt; alte Adressen `/magazin/1` … `/5` leiten per 301 weiter | | `/faq` | allgemeine Fragen und Bereiche „Für Ihr Zuhause“ und „Für Projekte und Objekte“ | | `/contact` | Kontaktformular | | `/referenzen` | Referenzen-Modul; zurzeit ausgeblendet (Schalter im CMS) | | `/impressum`, `/privacy`, `/terms`, `/cookie-policy` | Rechtstexte (Stand 06.10.2026: DDG, MStV, TDDDG) | | `/embed/display/{display}` | schreibgeschützte Einbettung eines Displays (nur veröffentlichte Playlists) | Stillgelegte Seiten leiten dauerhaft um: `/netzwerk`, `/interior`, `/partner` und `/service` auf `/marken`, `/ecosystem` auf `/partner`, `/portfolio` auf `/immobilien`. ### Bausteine - **Hero-Slideshow:** elf Bilder, im CMS pflegbar. Je Bild Marke und Motiv in der Infokarte. Überblendung alle 7 Sekunden (einstellbar 3–30), Pause bei Hover und Fokus, Steuerung per Pfeiltasten. Eine Fortschrittslinie im Bild zeigt die verbleibende Zeit. Auf dem Handy steht die Karte unter dem Bild. - **Gemeinsamer Hero-Stil** auf Start, Marken, Über uns und Kontakt: Goldverlauf als Rahmen, Zeile über der Überschrift, Vertrauenspunkte. - **Termin-Widget:** WhatsApp zuerst (0521-98620100), darunter das Formular. - **Live-Display:** Die Startseite zeigt, was im Showroom läuft, vergrößerbar und im Vollbild. - **Sprache:** Deutsch und Englisch, Umschaltung über die Sitzung (`SetLocale`). ### Inhalte: CMS vor Lang-Datei Jede Sektion liest zuerst das CMS (`cms_theme_section()` über `config/cms_section_map.php`). Fehlt der Eintrag, gilt die Lang-Datei `resources/lang/{de,en}/b2in.php`. Bilder kommen bevorzugt aus `public/img/assets` (WebP-Fassungen) und sonst aus der Mediathek (`theme_image_url()`, `media_url()`). --- ## Immobilien-Welt - Seiten unter `/immobilien`: Übersicht, Projekt (`/immobilien/{slug}`), Magazin, Über B2in, FAQ, Kontakt. Eigene Navigation, eigenes Logo, blaues Farbschema. - Projekte als `CmsProject` mit Preis in AED und Umrechnung in EUR/USD (`PriceHelper`). Die Projekte sind zurzeit nicht freigegeben und im Portal nicht verlinkt. - Magazin der Immobilien-Welt: drei Beiträge (Escrow, Al Jaddaf, Turnkey). --- ## Magazin Beiträge als `CmsArticle` (Titel, Untertitel und Inhalt je Sprache, Welt `interior` oder `immobilien`, Autor, Lesezeit, Veröffentlichung). | Welt | Veröffentlicht | |---|---| | Interior | „Nach Maß statt von der Stange“, „Küche planen“ | | Immobilien | Escrow, Al Jaddaf, Turnkey | | offline | Supply-Chain, Local for Local (seit 08.10.2026) | Absätze im Inhalt trennt eine Leerzeile. Datum und Lesezeit stehen im deutschen Format. --- ## CMS im Portal Unter **CMS ▸ Website-Inhalte**: | Bereich | Funktion | |---|---| | Übersicht | Einstieg mit Kennzahlen | | Inhalte | **Seitenbaum** (`config/cms_pages.php`): je Seite die Sektionen mit Beschreibung. Felder je Sprache (DE/EN), Listen als Wiederholfelder, Bilder über die Mediathek. **Vorschau** der Seite daneben im Rahmen. Eine fehlende Sektion lässt sich aus der Lang-Datei anlegen. | | Marken | die vier Kernmarken: Texte, Logo, Titelbild, Merkmale, Leistungen, Abschnitte, Galerie mit Rubriken, Fertigungsort, CTA. **Alle Textfelder je Sprache**, Bilder und Rubriken gelten für beide Sprachen. | | Magazin | Beiträge beider Welten | | Referenzen | Modul vorhanden, Seite und Menüpunkt zurzeit ausgeblendet | | Medien | Mediathek mit Sammlungen (Marken, Magazin, Website), Alternativtexten je Sprache und Bildgrößen. Alle auf der Website verwendeten Bilder sind übernommen. | Hinweise zur Pflege: - **FAQ:** Jede Frage hat das Feld `category`. Leer heißt allgemeine Frage oben, sonst steht dort der Bereich. Überschrift und Symbol der Bereiche stehen in `categories`. - **Vorschau im Portal:** Die Website erlaubt das Einbetten nur durch sich selbst und das Portal (`frame-ancestors`, `AllowPortalFraming`). - **Übersetzungen prüfen:** `php artisan cms:untranslated` listet alles, was auf der englischen Seite fehlt oder noch deutsch ist. --- ## Store Displays und Info-Tablet Unter **Cabinet ▸ Store Displays**: | Bereich | Funktion | |---|---| | Übersicht | Kennzahlen, Status des Info-Tablets | | Mediathek | Bilder und Videos der Displays (Uploads oder externe URLs) | | Module | Inhalte nach Typ: `video-display` (Video-Playlist), `b2in` (Marken-Slides mit Interior-Logo, Bilddauer mit Nachkommastelle), `offers` (Angebote). Vorschau je Modul und je Folie. | | Displays | physische Geräte mit **Playlists** (Entwurf und veröffentlicht), Test-Displays, Vorschau-Links mit Token | | Info-Tablet | Öffnungszeiten (7 Tage), Tagesausnahmen mit Rücksetzung um Mitternacht, Status (offen, Hinweis, geschlossen, Warnung), Kontakt; Schnellschalter unter `/info/status` | **API:** Die Displays fragen die API zyklisch ab, ein Neustart ist nach Änderungen nicht nötig. Medien-URLs sind relativ gespeichert und funktionieren dadurch auf jedem Host. | Endpunkt | Zweck | |---|---| | `/api/display/{display}/config`, `/check` | Konfiguration und Änderungsprüfung je Gerät | | `/api/display/overview` | Übersicht aller Geräte | | `/api/display/preview/{token}` | Entwurf über Vorschau-Token | | `/api/display/module/{module}/preview` | Vorschau eines Moduls | | `/api/cabinet-tablet/status`, `/check` | Info-Tablet | **Short-Links:** `cabinet.b2in.eu/go.php?z=CODE` mit Klickzählung in `public/_cabinet/clicks.log`. Die Datei schreibt der Player im Betrieb, deshalb ist sie nicht versioniert. --- ## Partner, Produkte, Regionen Diese Bereiche haben eine Grundarchitektur. Seit dem Frühjahr kamen keine neuen Funktionen hinzu. | Bereich | Funktionen | |---|---| | Rollen | Super-Admin, Admin, Retailer, Manufacturer, Broker, Customer | | Partner | Einladung per Mail mit Token, Setup-Wizard, Registrierungscodes mit QR (`/reg/{role}`), Impersonation, Anonymisieren statt Löschen | | Produkte | Produkte, Varianten, Kategorien, Marken, Kuration (`curate_products`) | | Regionen | Hubs mit PLZ-Gebieten (Import einzeln, Bereich oder CSV) | --- ## Betrieb Die vollständige Anleitung steht in **`dev/betrieb/README.md`**. ### Auslieferung per Git-Tag - Remotes: `origin` = forge.adametz.media (Quelle für den Deploy, auf dem Server über den Alias `forge-b2in`), `NAS` = Sicherung. - Ausgeliefert wird nur ein Tag `vX.Y.Z`, auf dem Server mit `bash dev/betrieb/deploy.sh vX.Y.Z [--migrations] [--seed=…]`. - Das Skript bricht ab, bevor es etwas verändert, wenn im Verzeichnis von Hand geändert wurde, der Tag fehlt, ein Build-Manifest fehlt oder Migrationen ohne `--migrations` kommen. Rollback: dasselbe Skript mit dem vorigen Tag. - `public/build` ist versioniert, weil der Server kein Node hat. Vor dem Tag lokal `npm run build:web && npm run build:portal` ausführen. - Inhaltsänderungen laufen über idempotente Seeder. `InteriorReleaseSeeder` fasst alle Schritte des Relaunchs zusammen. Spätere Seeder nennt die jeweilige Tag-Notiz. ### Überwachung | Was | Wo | |---|---| | Fehler in PHP und im Browser | GlitchTip `errors.adametz.media`, Projekte `server-b2in` und `browser-b2in`. Ohne Personenbezug: nur User-ID, keine Formularinhalte, E-Mails ausgeblendet. | | Tiefer Health-Check | `/health` mit Bearer-Token (`MONITORING_HEALTH_TOKEN`): Datenbank, Cache, Queue, Scheduler-Herzschlag, Plattenplatz | | Externer Monitor | Uptime Kuma auf `/health` und `/up`, Alarme per ntfy (Topic `b2in-ops`) und Mail | | Geplante Aufgaben | Cron `schedule:run` jede Minute: Herzschlag, `cabinet:reset-overrides` (0 Uhr), Aufräumen alter Jobs; bei Fehlschlag ein Alarm | | **Admin ▸ Monitoring** | Prüfungen, Version und Deploy-Zeit, geplante Aufgaben, letzte Fehler und Alarme, fehlgeschlagene Jobs, Test-Alarm | Eine Queue braucht B2in nicht, Mails gehen sofort raus. --- ## Datenbank (Auszug) | Bereich | Tabellen | |---|---| | Benutzer und Rollen | `users`, `roles`, `permissions`, `model_has_roles`, `personal_access_tokens` | | Partner | `partners`, `partner_invitations`, `registration_codes`, `hubs`, `hub_locations` | | Produkte | `products`, `product_variants`, `brands`, `categories`, `attributes`, `tags`, `collections` … | | Website-CMS | `flux_cms_contents` (Sektionen je Gruppe/Schlüssel, Werte je Sprache), `flux_cms_media`, `cms_brands` (mit `field_translations`), `cms_articles` (mit `world`), `cms_projects`, `cms_references` | | Displays | `displays`, `display_versions` (Module), `display_version_items`, `display_playlists`, `display_playlist_items`, `display_media`, `cabinet_tablet_settings` | | Altbestand Displays | `display_videos`, `display_footer_contents` | | System | `cache`, `jobs`, `failed_jobs`, `sessions` | --- ## Tests 1197 Tests (Pest), alle grün (Stand 09.10.2026). Sie laufen auf SQLite im Arbeitsspeicher, die MySQL-Datenbank bleibt unberührt. ```bash php artisan test --compact # alle php artisan test --compact tests/Feature/FooTest.php ``` Wächtertests sichern bekannte Stolpersteine ab: - Klassenpfad und Namespace in gleicher Schreibweise, sonst Ausfall auf Linux - Lang-Sektionen und Section-Map decken sich - die Testsuite meldet nie an das echte GlitchTip --- ## Wichtige Dateien und Dokumente | Datei | Inhalt | |---|---| | `CLAUDE.md` | Projektkontext für Entwicklung mit KI | | `dev/betrieb/README.md` | Deploy, Livegang, Monitoring (Runbook) | | `dev/2026-08-28/entwicklungsplan.md` | Verlauf des Interior-Relaunchs mit allen Nachträgen | | `dev/git-deploy-monitoring/` | Baukasten Git-Deploy und Monitoring (projektübergreifend) | | `config/cms_pages.php` | Seitenbaum und Beschreibungen im CMS | | `config/cms_section_map.php` | Zuordnung Website-Sektion ↔ CMS-Eintrag | | `resources/lang/{de,en}/b2in.php` | Standardtexte der Website | | `resources/lang/{de,en}/b2in_legal.php` | Rechtstexte | | `database/seeders/data/brand-translations-en.json` | englische Markentexte | | `dev/DISPLAY_CMS_README.md`, `dev/DISPLAY_SETUP_LIVE.md` | Display-System | | `DOMAINS-CONFIG.md` | Domain-Konfiguration | Archive alter Entwürfe und stillgelegter Seiten liegen unter `dev/2026-08-28/archiv-*`, jeweils mit README. --- ## Offene Punkte - **Datenschutzerklärung:** Der Absatz zur Fehlerprotokollierung (GlitchTip) fehlt noch. Ein Textvorschlag steht in `dev/betrieb/README.md`, Abschnitt 6. - **OG-Bild** `img/assets/b2in-og-default.jpg` fehlt. Geteilte Links zeigen deshalb kein Vorschaubild. - **Freigaben:** - Herstellerfreigabe der Texte von Rotpunkt und Febrü, mit Blick auf die EmpCo-Regeln - CABINET-Seitentext von Marcel - Waldflächen-Aussage bei Rotpunkt - **Englische Markentexte** einmal muttersprachlich gegenlesen lassen. - **Logo TC Bad Salzuflen** liegt nur in geringer Auflösung vor (72 × 80 px). - **Mailzustellung:** Im Frühjahr wurden Systemmails bei Gmail abgewiesen („sender is unauthenticated“). SPF, DKIM und DMARC der Absenderdomain prüfen. - **Display-Feed:** Festlegen, welches Display auf der Website läuft (`referenzen.display_feed.display_id`). Ohne Eintrag läuft das erste aktive Display mit veröffentlichter Playlist. --- *Diese Dokumentation wird mit jedem Release aktualisiert. Letzte Aktualisierung: 09.10.2026 (v2.0.6).*