b2in/dev/entwicklung.md
Kevin Adametz 17acb35231 Projektdokumentation im Admin auf den Stand v2.0.6 gebracht
dev/entwicklung.md neu: Welten Interior/Immobilien, Seiten und Bausteine der Website, CMS
im Portal, Store Displays mit Playlists, Betrieb (Git-Deploy, Monitoring), Datenbank, Tests,
offene Punkte. Die Doku-Seite stellt Tabellen jetzt lesbar dar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:43:12 +00:00

261 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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/<theme>`, 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).*