10-04-2026
This commit is contained in:
parent
4d6b4930b2
commit
4bb89aad8c
836 changed files with 52961 additions and 5950 deletions
|
|
@ -1,9 +1,9 @@
|
|||
# Entwicklungsplan: B2In / Local for Local Marktplatz-Ökosystem
|
||||
# Entwicklungsplan: B2in / Local for Local Marktplatz-Ökosystem
|
||||
|
||||
**Erstellt:** 12.02.2026
|
||||
**Letzte Aktualisierung:** 12.02.2026
|
||||
**Basis:** konzeption.md (Version 1.1)
|
||||
**Status:** Phase 1 ✅, Phase 2 ✅, Phase 2.5 Produkt-Bearbeitung ✅, Phase 2.6 Refactoring & UX ✅, Phase 2.7 Admin-Produktverwaltung & Freigabe ✅, Phase 3 Kern ✅
|
||||
**Status:** Phase 1 ✅, Phase 2 ✅, Phase 2.5 Produkt-Bearbeitung ✅, Phase 2.6 Refactoring & UX ✅, Phase 2.7 Admin-Produktverwaltung & Freigabe ✅, Phase 3 Kern ✅, Phase 2.8 Partner-Präsentation ✅
|
||||
**Docker** Projekt läuft in Docker, root /var/www/html nutze php artisan ... nicht vendor/bin/sail artisan ...
|
||||
---
|
||||
|
||||
|
|
@ -581,6 +581,31 @@ Alle Preistypen erlaubt; Standard-Varianten mit Festpreis möglich.
|
|||
- [ ] Notification an Händler/Hersteller bei Freigabe/Ablehnung – ausstehend
|
||||
- [ ] Admin kann `product_type` bei Bedarf nachträglich ändern – ausstehend
|
||||
|
||||
#### 2.4a Nachbesserungen Phase 2 – ✅ Abgeschlossen (27.02.2026)
|
||||
|
||||
**Fix: `curate products` Permission fehlte in der Datenbank**
|
||||
- Die Permission war im `RoleSeeder` definiert, aber nie in die Produktions-DB eingespielt
|
||||
- `Attempt to read property "id" on null` beim Öffnen von `/admin/products`
|
||||
- Lösung: Migration `2026_02_27_154145_add_curate_products_permission.php`
|
||||
- `Permission::firstOrCreate(['name' => 'curate products', 'guard_name' => 'web'])`
|
||||
- Admin-Rolle bekommt Permission via `Role::where('name', 'Admin')->first()` (kein `findByName` = würde Exception werfen wenn Rolle fehlt)
|
||||
- Tests (`ProductCurationTest`, `ProductPolicyTest`, `PartnerPolicyTest`): `Permission::create()` → `Permission::firstOrCreate()` (verhindert Fehler wenn Migration die Permission bereits angelegt hat)
|
||||
|
||||
**Fix: Admin kann Produkte anlegen (Partner-Selector)**
|
||||
- Admin hat keine eigene `partner_id` → `$user->partner` war `null` → Crash beim Speichern
|
||||
- Lösung in `form-teaser.blade.php` und `form-standard.blade.php`:
|
||||
- Neues Property `$selectedPartnerId` + `resolvePartner()` Methode
|
||||
- Für Admins: Partner-Auswahl-Karte erscheint vor dem Formular (nur bei Neuanlage)
|
||||
- `updatedSelectedPartnerId()` aktualisiert Produktnummer automatisch nach Partnerwahl
|
||||
- Validierung: `selectedPartnerId` Pflichtfeld für Admins bei Neuanlage
|
||||
- Alle bestehenden 158 Produkt-Tests weiterhin grün ✅
|
||||
|
||||
**Fix: Portal Textarea Dark-Mode Kontrast**
|
||||
- Korrektur-Textfeld in der Kuration zeigte weißen Text auf weißem Hintergrund
|
||||
- Ursache: `@apply dark:text-zinc-500` innerhalb von `::placeholder` Pseudo-Elementen kompiliert in Tailwind v4 zu ungültigem `:is():where(.dark,.dark *)` Selektor
|
||||
- Lösung in `resources/css/portal.css`: Explizites CSS mit `:where(.dark,.dark *)` als Vorfahren-Selektor statt `@apply dark:`
|
||||
- Portal-Build (`npm run build:portal`) aktualisiert
|
||||
|
||||
#### 2.5 Tests Phase 2 – ✅ Kern abgeschlossen
|
||||
- [x] Feature-Tests: `PartnerPolicyTest` (10 Tests) – viewAny, view, update, curateProducts
|
||||
- [x] Feature-Tests: `ProductPolicyTest` (14 Tests) – alle Policy-Methoden
|
||||
|
|
@ -596,6 +621,59 @@ Alle Preistypen erlaubt; Standard-Varianten mit Festpreis möglich.
|
|||
|
||||
---
|
||||
|
||||
### Phase 2.8: Partner-Präsentation & Selbst-Service-Profil – ✅ ABGESCHLOSSEN (27.02.2026)
|
||||
**Geschätzter Aufwand:** 2-3 Tage | **Tatsächlich:** 1 Sitzung
|
||||
|
||||
#### 2.8.1 Händler-Profil (Retailer) – Präsentation
|
||||
- [x] `my-data.blade.php` erweitert um:
|
||||
- [x] **Story-Text** – Freitext max. 2000 Zeichen mit Live-Zeichenzähler, Feld: `story_text`
|
||||
- [x] **Öffnungszeiten** – 7-Tage-Eingabe (Mo–So), `open`/`close`-Felder + "Geschlossen"-Checkbox, Feld: `opening_hours` (JSON)
|
||||
- [x] **Spezialisierungen** – kommagetrennte Eingabe → gespeichert als JSON-Array, Feld: `specialties`
|
||||
- [x] **Gründungsjahr** – Zahlfeld mit Validierung (1800–heute), Feld: `founded_year`
|
||||
- [x] **Team-Fotos** – Mehrfach-Upload via `WithFileUploads`, gespeichert als `Media.type = 'team_photo'`
|
||||
- [x] **Showroom-Galerie** – Mehrfach-Upload, `Media.type = 'showroom'`
|
||||
- [x] Foto-Löschen per Klick (mit `wire:confirm`)
|
||||
- [x] Formular in 4 separate `flux:card`-Abschnitte gegliedert: Stammdaten, Präsentation & Story, Öffnungszeiten, Fotos
|
||||
|
||||
#### 2.8.2 Hersteller-Profil (Manufacturer) – Firma & Marke
|
||||
- [x] `my-data.blade.php` erweitert um:
|
||||
- [x] **Story-Text** – Unternehmensgeschichte, Feld: `story_text`
|
||||
- [x] **Gründungsjahr** – Feld: `founded_year`
|
||||
- [x] **Spezialisierungen** – Feld: `specialties`
|
||||
- [x] **Marken-Bilder** – Mehrfach-Upload, `Media.type = 'brand_image'`
|
||||
- [x] Abschnitte: Stammdaten, Über das Unternehmen, Marke (mit Markenname, Beschreibung, Bilder)
|
||||
|
||||
#### 2.8.3 Öffentliches Partnerprofil (`livewire/partner/profile.blade.php`)
|
||||
- [x] Story-Text anzeigen wenn vorhanden (bereits vorhanden)
|
||||
- [x] Öffnungszeiten anzeigen (bereits vorhanden)
|
||||
- [x] Spezialisierungen + Gründungsjahr anzeigen (bereits vorhanden)
|
||||
- [x] **Showroom-Galerie** – 3-spaltige Bild-Galerie unterhalb der Story
|
||||
- [x] **Marken-Bilder** (Hersteller) – 3-spaltige Galerie unter der Story
|
||||
- [x] **Team-Fotos** – 2-spaltige Galerie in der rechten Sidebar
|
||||
|
||||
#### 2.8.4 Datenbank
|
||||
- [x] Alle Felder vorhanden: `story_text`, `opening_hours`, `specialties`, `founded_year` (Migration `2026_02_12_000003_add_profile_fields_to_partners_table`)
|
||||
- [x] Media-System: Custom `Media` Model mit `type`-Feld (kein Spatie) – `Partner::media()` morph-Relation bereits vorhanden
|
||||
|
||||
#### 2.8.5 Tests Phase 2.8
|
||||
- [x] `PartnerSelfServiceProfileTest` (15 Tests) – alle bestanden ✅
|
||||
- Händler kann Story, Öffnungszeiten, Spezialisierungen, Gründungsjahr speichern
|
||||
- Händler kann Team-Fotos und Showroom-Fotos hochladen
|
||||
- Händler kann Foto löschen
|
||||
- Hersteller kann Story, Markendaten, Gründungsjahr speichern
|
||||
- Hersteller kann Marken-Bilder hochladen
|
||||
- Öffentliches Profil zeigt Story und Spezialisierungen an
|
||||
- Validierung: Story-Text max. 2000 Zeichen, Gründungsjahr-Grenzen
|
||||
|
||||
**Erstellte/geänderte Dateien (2):**
|
||||
|
||||
| Datei | Änderungen |
|
||||
|-------|-----------|
|
||||
| `resources/views/livewire/partner/my-data.blade.php` | Komplett überarbeitet: 4 Karten-Abschnitte, neue Profil-Felder, Foto-Upload mit `WithFileUploads` |
|
||||
| `resources/views/livewire/partner/profile.blade.php` | Showroom-Galerie, Marken-Bilder, Team-Fotos hinzugefügt; `media` eager-loaded |
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Kunden-Frontend & Local Feed – ✅ KERN ABGESCHLOSSEN (12.02.2026)
|
||||
**Geschätzter Aufwand:** 4-5 Tage | **Tatsächlich:** 1 Tag (12.02.2026)
|
||||
**Priorität:** HOCH – Kunden-Facing Funktionalität
|
||||
|
|
@ -721,7 +799,7 @@ Enum: App\Enums\TransactionStatus
|
|||
- [ ] `PendingMerchant` – Beleg hochgeladen, Händler muss bestätigen
|
||||
- [ ] `Confirmed` – Händler hat bestätigt → Rechnung an Händler generieren
|
||||
- [ ] `Invoiced` – Rechnung erstellt → Zahlung ausstehend
|
||||
- [ ] `Paid` – Händler hat Provision an B2In überwiesen
|
||||
- [ ] `Paid` – Händler hat Provision an B2in überwiesen
|
||||
- [ ] `Distributed` – Provisionen an Makler/Kunde ausgeschüttet
|
||||
- [ ] `Rejected` – Händler hat abgelehnt
|
||||
- [ ] `Disputed` – Streitfall
|
||||
|
|
@ -778,7 +856,7 @@ Migration: create_ledger_entries_table
|
|||
#### 6.2 Provisions-Berechnung
|
||||
- [ ] Service: `App\Services\CommissionService`
|
||||
- `calculateSplit(Transaction $transaction): CommissionSplit`
|
||||
- Berechnet: Makler-Anteil, Kunden-Cashback, B2In-Marge
|
||||
- Berechnet: Makler-Anteil, Kunden-Cashback, B2in-Marge
|
||||
- Nutzt `partner.provision_rate_percentage` und `partner.provision_fixed_amount`
|
||||
- [ ] Event Listener für `TransactionPaid`:
|
||||
- Erstellt Ledger-Einträge
|
||||
|
|
@ -856,7 +934,7 @@ Migration: create_ledger_entries_table
|
|||
> **Entscheidung:** Individuell pro Partner. Admin-Settings-Seite mit Feldern für:
|
||||
> - Makler-Provision (%)
|
||||
> - Kunden-Cashback (%)
|
||||
> - B2In-Marge (Rest)
|
||||
> - B2in-Marge (Rest)
|
||||
> Felder werden pro Partner im Admin-Backend konfiguriert.
|
||||
|
||||
**Frage 8: Ticket-Gültigkeit** ✅
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ Konzept-Update: "Local for Local" Marktplatz
|
|||
1. Strategische Neuausrichtung: Die Domains
|
||||
Die Trennung wird schärfer.
|
||||
|
||||
B2In (Backend/B2B): Bleibt das "Maschinenraum"-Portal für Händler, Hersteller und Makler. Hier wird verwaltet.
|
||||
B2in (Backend/B2B): Bleibt das "Maschinenraum"-Portal für Händler, Hersteller und Makler. Hier wird verwaltet.
|
||||
|
||||
Local for Local (Customer Frontend): Das wird das Gesicht zum Kunden. Der Kunde fühlt sich nicht auf einer abstrakten "B2In"-Seite, sondern in seinem regionalen Hub (z.B. "Local for Local OWL").
|
||||
Local for Local (Customer Frontend): Das wird das Gesicht zum Kunden. Der Kunde fühlt sich nicht auf einer abstrakten "B2in"-Seite, sondern in seinem regionalen Hub (z.B. "Local for Local OWL").
|
||||
|
||||
To-Do: Wir benötigen ggf. die Domain localforlocal.de (o.ä.) und routen diese auf die Endkunden-Ansicht.
|
||||
|
||||
|
|
@ -83,11 +83,11 @@ Anstatt eines klassischen "Warenkorbs" bauen wir für Typ A Produkte einen "Tick
|
|||
Das ist technisch einfacher als ein Checkout mit Payment-Provider! Wir generieren ein PDF/QR-Code und senden eine Mail.
|
||||
|
||||
|
||||
Konzeptpapier: B2In / Local for Local Marktplatz-Ökosystem
|
||||
Konzeptpapier: B2in / Local for Local Marktplatz-Ökosystem
|
||||
Status: Final | Version: 1.1 (Update: Marken-Hierarchie)
|
||||
|
||||
1. Executive Summary
|
||||
Das B2In-Ökosystem ist ein hybrider Marktplatz, der den Immobilienkauf ("Moment of Need") mit der Einrichtung verbindet. Es agiert als "Closed Shop" (Zugang nur über Makler). B2In ist die zentrale B2B-Plattform und Technologie. Local for Local ist das verbindende Prinzip innerhalb des Marktplatzes, das die Endkunden-Marken (style2own, stileigentum) mit den regionalen Händlern verknüpft.
|
||||
Das B2in-Ökosystem ist ein hybrider Marktplatz, der den Immobilienkauf ("Moment of Need") mit der Einrichtung verbindet. Es agiert als "Closed Shop" (Zugang nur über Makler). B2in ist die zentrale B2B-Plattform und Technologie. Local for Local ist das verbindende Prinzip innerhalb des Marktplatzes, das die Endkunden-Marken (style2own, stileigentum) mit den regionalen Händlern verknüpft.
|
||||
|
||||
Der USP liegt in der Transparenz lokaler Verfügbarkeit (Säule A: Local Express) und exklusiven Insider-Konditionen (Säule B: Smart Club), abgesichert durch ein Cashback-System.
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ Der USP liegt in der Transparenz lokaler Verfügbarkeit (Säule A: Local Express
|
|||
Wir unterscheiden strikt zwischen dem B2B-Zugang (Partner) und den B2C-Einstiegen (Endkunden).
|
||||
|
||||
A. Der B2B-Kanal (Die Dachmarke)
|
||||
Marke: B2In
|
||||
Marke: B2in
|
||||
|
||||
Zielgruppe: Immobilienmakler, Händler, Hersteller.
|
||||
|
||||
|
|
@ -163,9 +163,9 @@ Ticket: Kunde zieht im Portal einen QR-Code für Händler X.
|
|||
|
||||
Kauf: Kunde kauft vor Ort, verhandelt Preise individuell.
|
||||
|
||||
Upload (Der Trigger): Kunde lädt Kaufbeleg im B2In-Portal hoch, um sein Cashback anzufordern.
|
||||
Upload (Der Trigger): Kunde lädt Kaufbeleg im B2in-Portal hoch, um sein Cashback anzufordern.
|
||||
|
||||
Clearing: Händler bestätigt Umsatz im Backend -> Händler zahlt Gesamt-Provision an B2In.
|
||||
Clearing: Händler bestätigt Umsatz im Backend -> Händler zahlt Gesamt-Provision an B2in.
|
||||
|
||||
Ausschüttung: Sobald Geld eingeht, verteilt das System automatisch:
|
||||
|
||||
|
|
@ -173,7 +173,7 @@ Provision an Makler (Lead-Vergütung).
|
|||
|
||||
Cashback an Kunden (Motivation & Datentreue).
|
||||
|
||||
Marge an B2In.
|
||||
Marge an B2in.
|
||||
|
||||
|
||||
|
||||
|
|
@ -240,7 +240,7 @@ pending_merchant: Händler muss bestätigen ("Ja, Kunde war da und hat für 3.00
|
|||
|
||||
confirmed: Händler hat bestätigt -> Rechnung an Händler wird generiert.
|
||||
|
||||
paid: Händler hat Provision an B2In überwiesen.
|
||||
paid: Händler hat Provision an B2in überwiesen.
|
||||
|
||||
distributed: Provision wurde an Makler/Kunde ausgeschüttet.
|
||||
|
||||
|
|
@ -264,7 +264,7 @@ Händler Setup-Buchung:
|
|||
|
||||
Ein kleiner "Service-Store" im Händler-Backend.
|
||||
|
||||
Button: "Setup-Paket buchen (399€)". Löst eine interne Notification an das B2In-Team aus (Ticket für Fotografen).
|
||||
Button: "Setup-Paket buchen (399€)". Löst eine interne Notification an das B2in-Team aus (Ticket für Fotografen).
|
||||
|
||||
5. Frontend-Modul: Die Weichenstellung
|
||||
Wie die Landingpages mit dem System reden.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue