Skip to content

Lokales Setup — MATEV 2026 ​

Schritt-für-Schritt-Anleitung: vom frischen Clone bis lauffähig in DDEV mit Demo-Daten.

Voraussetzungen ​

  • macOS mit Homebrew oder Linux
  • DDEV ≥ v1.24
  • Bun ≥ 1.2 (statt npm)
  • mkcert (DDEV richtet das automatisch ein)
  • Git

1. Repos & Submodules ​

bash
cd /Users/bjorn.engelhardt/SynologyDrive/Bengel.digital/01_KUNDEN/10_MATEV/01_WEBSITES/matev_2026

# Submodules: admin/ (Filament), shared/ (Schemas + Components).
# cms/ (Kirby), staging/ (Nuxt), b2b/ (Livewire) werden derzeit noch direkt
# im Hauptbaum gepflegt und wandern in eigene Submodules sobald Forgejo stabil ist.
git submodule update --init --recursive

2. Admin (Filament + Laravel) ​

bash
cd admin

# DDEV starten — legt MariaDB, PHP-FPM, Mailpit, Adminer auf
ddev start

# .env aus Vorlage erzeugen (DDEV-spezifische Werte sind in .env.example bereits gesetzt)
cp .env.example .env
ddev exec "php artisan key:generate"

# Migrations laufen automatisch durch den post-start-Hook.
# Demo-User seeden:
ddev exec "php artisan db:seed"

URLs ​

ServiceURLLogin
Filament Adminhttps://admin.matev.ddev.site/adminadmin@matev.eu / admin
Filament Editor (Demo)https://admin.matev.ddev.site/admineditor@matev.eu / editor
API (REST)https://admin.matev.ddev.site/api/v1/Sanctum-Token (siehe unten)
Mailpit (Mail-Catcher)ddev mailpit öffnet Browser-Tab—
Adminer (DB-Browser)ddev adminer öffnet Browser-TabDB: db (User+Pass: db)

Sanctum-API-Token erzeugen ​

bash
ddev exec "php artisan tinker"
>>> $u = \App\Models\User::where('email','admin@matev.eu')->first();
>>> $u->createToken('local-dev')->plainTextToken;
# Kopiere das Token, nutze es als Header: Authorization: Bearer <token>

3. Pimcore-Daten importieren (PIM) ​

Erst wenn ein SQL-Dump aus Pimcore vorliegt:

bash
# Dump in matev_pimcore_source-DB laden (DDEV-Custom-Command)
cd admin
ddev load-pimcore-dump ../migration/exports/pimcore-2026-04-27.sql.gz

# Asset-Pfad mounten (optional, wenn Assets mit kopiert werden sollen)
# In .ddev/config.yaml unter "web_extra_daemons" oder via mutagen:
#   mounts: [{type: bind, source: /pfad/zu/pimcore/var/assets, target: /mnt/pimcore_assets}]

# Trockenlauf
ddev exec "php artisan import:pimcore --dry-run"

# Voller Import (Phase-für-Phase)
ddev exec "php artisan import:pimcore --phase=1"   # Stammdaten
ddev exec "php artisan import:pimcore --phase=2"   # Tractor + Dealer
ddev exec "php artisan import:pimcore --phase=3"   # Katalog (5.255 Articles!)
ddev exec "php artisan import:pimcore --phase=4"   # Offers + Orders
ddev exec "php artisan import:pimcore --phase=5"   # Konfiguration

# Nur einen Importer testen
ddev exec "php artisan import:pimcore --only=MakerImporter --limit=5"

# Mapping zurücksetzen (Vorsicht!)
ddev exec "php artisan import:pimcore --reset-mapping"

Brick-Schemas aus Pimcore generieren ​

Nach Phase 1+3 (oder direkt aus information_schema):

bash
# Aus Pimcore-Connection (alle 41 Bricks):
ddev exec "php artisan blueprints:generate"

# Aus den durch MainArticleBrickSchemaImporter befüllten Backend-Tabellen:
ddev exec "php artisan blueprints:generate --source=attributes"

# Nur einer:
ddev exec "php artisan blueprints:generate --brick=hydraulicDrive"

# Bestehende Stub-YAMLs überschreiben:
ddev exec "php artisan blueprints:generate --force"

Output landet in ../shared/schemas/spec-bricks/*.yml.

4. Storybook (CMS-Demo für den Kunden) ​

bash
cd ../storybook
bun install
bun run storybook

URL: http://localhost:6006

Was zu sehen ist:

  • CMS / Spec Bricks / SpecBrickRenderer — schema-driven Renderer für die 41 Pimcore-Bricks (Beispiele: Hydraulic Drive, Lighting, Main Article MOW)
  • CMS / Area Bricks / Text — Areablock-Sub-Brick mit Background/Width/Margin-Varianten
  • CMS / Snippets / CTA — Call-to-Action Snippet (4 Varianten)
  • CMS / Page Layouts / Default — Hero + Areablock-Renderer (Classic / Minimal / Full-Bleed)

Alle Beispiele lesen die YAML-Schemas aus shared/schemas/ direkt — so sieht der Kunde, wie die CMS-Felder am Ende im Filament aussehen werden.

5. Kirby-CMS (Page-Builder + KQL) ​

Marketing-Content (Startseite, Über uns, Produkte, Händler, Kontakt) plus Page-Builder-Sektionen für Produkte/Händler. 10 Block-Typen, 5 Page-Templates, 5+1 Beispielseiten — alle 1:1 aus shared/schemas/area-bricks/ abgeleitet.

bash
cd ../cms

# Kirby + KQL holen (legt ./kirby/ + ./vendor/ an)
ddev composer install
ddev start

# Beim ersten Aufruf — Admin-Account anlegen über Setup-Wizard:
open https://cms.matev.ddev.site/panel

URLs:

URLInhalt
https://cms.matev.ddev.site/Startseite mit Page-Builder (Server-Rendering)
https://cms.matev.ddev.site/panelEditor-UI (Blueprints)
https://cms.matev.ddev.site/api/queryKQL-Endpoint (POST)
https://cms.matev.ddev.site/produkteProdukt-Übersicht
https://cms.matev.ddev.site/produkte/kompaktkehrmaschine-mt500Beispiel-Produktseite
https://cms.matev.ddev.site/haendlerHändler-Hub
https://cms.matev.ddev.site/kontaktKontakt

KQL-Test:

bash
curl -X POST https://cms.matev.ddev.site/api/query \
  -H "Content-Type: application/json" \
  -d '{"query":"site","select":{"title":true,"brandName":true}}'

Ausführlich siehe cms/README.md.

6. Staging-Frontend / B2B-Portal (optional) ​

bash
# Nuxt-Staging-Frontend (Marketing, Bun)
cd ../staging && bun install && bun run dev
# → http://localhost:3000  — zieht KQL aus cms.matev.ddev.site
#                          + REST aus admin.matev.ddev.site

# B2B-Händlerportal (Laravel + Livewire, lokal über DDEV)
cd ../b2b && ddev start
# → https://b2b.matev.ddev.site

staging/ und b2b/ ersetzen die früheren frontend/ (Nuxt-Marketing) bzw. portal/ (Nuxt-SPA-Portal). Das B2B-Portal nutzt Livewire/Blade statt Nuxt — das passte besser zur PIM-Kopplung.

6. Hilfsbefehle ​

bash
# Logs streamen
ddev exec "php artisan pail --timeout=0"

# Pint (Code-Style)
ddev exec composer lint

# Phpstan
ddev exec composer analyse

# Pest-Tests
ddev exec composer test

# Migrate fresh + reseed (Datenverlust!)
ddev exec "php artisan migrate:fresh --seed --force"

# Cache komplett leeren
ddev exec "php artisan optimize:clear"

7. Hosts-Datei (falls DNS-Probleme) ​

DDEV trägt automatisch ein. Falls nicht:

bash
sudo ./setup-hosts.sh

8. Häufige Fehler ​

SymptomUrsache & Lösung
getaddrinfo for db failedDDEV nicht gestartet — ddev start
Access denied for user 'db'@'localhost' auf pimcore-Connectionmatev_pimcore_source DB nicht angelegt — ddev restart (post-start-Hook legt sie an)
tags-Tabelle fehlt beim ImportErwartet — composer require spatie/laravel-tags einspielen, dann ddev exec "php artisan migrate"
settings-Tabelle fehltAnalog: composer require spatie/laravel-settings
Storybook lädt YAML nichtbun install im storybook/ muss @modyfi/vite-plugin-yaml mitgezogen haben
Filament zeigt nur 401Default-Provider unter app/Providers/Filament/AdminPanelProvider.php checken — Login-Page sollte unter /admin/login erreichbar sein

9. Search-Stack (Meilisearch + OpenSearch + Ollama) ​

Meilisearch und OpenSearch laufen als DDEV-Container (.ddev/docker-compose.search.yaml), Ollama in .ddev/docker-compose.ollama.yaml. Sie starten automatisch mit ddev start.

Meilisearch (Schicht B — Frontend-Suche) ​

bash
ddev exec "php artisan search:reindex --scout"
# Stack-Reindex: catalog_index (Schicht A) + Meilisearch via Scout

# Status (Meilisearch ist auf Port 7701 nur via HTTPS routet, Port 7700 via HTTP):
curl -k -H "Authorization: Bearer matev_local_master_key" https://matev.ddev.site:7701/indexes
# oder HTTP:
curl    -H "Authorization: Bearer matev_local_master_key" http://matev.ddev.site:7700/indexes

OpenSearch (Schicht C — Geo, Konfigurator, RAG, Embeddings) ​

bash
# Indizes anlegen (post-start macht das schon — manuell:):
ddev exec "php artisan opensearch:setup"

# Reset & neu:
ddev exec "php artisan opensearch:setup --reset"

# Cluster-Health:
curl http://matev.ddev.site:9200/_cluster/health

Vier Indizes: catalog_advanced (k-NN-Embeddings), locations (geo_point), configurator_compat, content_rag.

Ollama (lokales LLM: Text, Embeddings, Bildanalyse) ​

bash
# Verbindung + Modellstand prüfen (zieht nichts):
ddev exec "php artisan ollama:setup --skip-pull"

# fehlende Modelle ziehen:
ddev exec "php artisan ollama:setup"
# konfiguriert sind: qwen2.5:14b-instruct (Text), bge-m3 (Embeddings, 1024-dim),
# qwen3-vl:8b (Bildanalyse, ~6 GB)

# Bildanalyse in der UI: /admin/media → Zeilenaktion „Mit KI analysieren"
# (nur bei Bildern). Läuft als Queue-Job, Ergebnis steht in
# custom_properties.ai_analysis und im Metadaten-Formular des Assets.

# Direkter HTTP-Check (vom Host):
curl http://matev.ddev.site:11435/api/tags

Container oder nativ? ​

Der Container (.ddev/docker-compose.ollama.yaml) rechnet auf der CPU — Docker reicht unter macOS kein Metal durch. Gemessen mit qwen2.5:14b: 0,2 Token/s, ein Vision-JSON läuft damit weit über den Job-Timeout von 600 s.

Nativ auf dem Mac ist derselbe Code um Größenordnungen schneller:

bash
brew install ollama && ollama serve          # hört auf 127.0.0.1:11434

# admin/.env:
OLLAMA_HOST=http://host.docker.internal:11434

# Modelle nicht neu laden, sondern aus dem Container übernehmen:
docker cp ddev-matev-ollama:/root/.ollama/models/. ~/.ollama/models/

# optional ~9 GB RAM freigeben:
mv admin/.ddev/docker-compose.ollama.yaml admin/.ddev/docker-compose.ollama.yaml.disabled
ddev restart

Der Container liegt deshalb auf Host-Port 11435 — 11434 bleibt für den nativen Dienst frei, beide können parallel laufen.

10. Rollen & Berechtigungen (Spatie-Permission + Filament-Shield) ​

bash
# Roles + Permissions seeden (Demo: admin@matev.eu = super_admin, editor@matev.eu = editor)
ddev exec "php artisan db:seed --class=RolesAndPermissionsSeeder"

# Shield-UI ist im Admin-Panel unter "Shield" automatisch verfügbar
# (Plugin in AdminPanelProvider registriert)

# Pro Resource Policies generieren:
ddev exec "php artisan shield:generate --resource=MainArticleResource"

Acht Mitarbeiter-Rollen + sechs Tenant-Rollen (Architektur § 16.2):

  • Admin-Panel: super_admin, admin, editor, crm, support, marketing
  • Portal (Tenant): dealer_owner/dealer_manager/dealer_staff, customer_owner/customer_manager/customer_staff

Spezielle Permissions: blueprint.{manage,use}, agentic.{manage,run,approve}, mcp.tools.{invoke,audit}, ai.{use,configure}.

11. OpenSearch Indexer (4 Jobs) ​

bash
# Alle Indizes neu befüllen (synchron, dauert mit ollama-Embedding ein paar Min):
ddev exec "php artisan search:index-all --sync"

# Über Queue (empfohlen, braucht laufenden queue:work):
ddev exec "php artisan search:index-all"
ddev exec "php artisan queue:work --queue=default"

# Nur einzelne Jobs:
ddev exec "php artisan search:index-all --only=locations --only=configurator --sync"

Jobs:

  • GeocodeLocationJob → locations-Index (geo_point pro Dealer)
  • EmbedCatalogItemsJob → catalog_advanced-Index (Ollama bge-m3 → 1024-dim)
  • IndexRagSourcesJob → content_rag-Index (Spatie-Media documents chunked + embedded)
  • RebuildConfiguratorIndexJob → configurator_compat-Index (Article ↔ Tractor Pivots)

12. Spatie-Media-Library Pro ​

Die media-Tabelle ist bereits angelegt, der InteractsWithMatevMedia-Trait und die Standard-Collections (logos, cad_images, documents, previews, heroes, lifestyle, icons, images, gallery) sind in den Models vorbereitet.

Sobald die Pro-Lizenz hinterlegt ist:

bash
composer config --global http-basic.satis.spatie.be <USER> <LICENSE-KEY>
ddev exec composer require "spatie/laravel-medialibrary-pro:^4"

# Im Trait app/Models/Concerns/InteractsWithMatevMedia.php die kommentierten
# `addMediaCollection()` + `addMediaConversion()`-Aufrufe einkommentieren.
# Im Model das HasMedia-Interface ergänzen:
#   class MainArticle extends Model implements \Spatie\MediaLibrary\HasMedia

Asset-Browser steht dann automatisch im Filament unter /admin/media zur Verfügung.

13. Was funktioniert jetzt lokal ​

  • [x] Filament 5 + Laravel 13.6 — Login admin@matev.eu / admin (super_admin) bzw. editor@matev.eu / editor
  • [x] Filament-Shield + Spatie-Permission, 14 Rollen + 9 spezielle Permissions geseedet
  • [x] Spatie-Tags + Spatie-Settings (Migrations + Importer-Stubs aktiv)
  • [x] Sanctum (API-Token-Auth) + REST-API v1
  • [x] Pimcore-Importer (22 Klassen, 5 Phasen) — wartet auf Pimcore-SQL-Dump
  • [x] blueprints:generate (41 Spec-Bricks aus Pimcore-Schema)
  • [x] Meilisearch + Laravel Scout + catalog_index + search:reindex
  • [x] OpenSearch (4 Indizes) + opensearch:setup + 4 Indexer-Jobs + search:index-all
  • [x] Ollama-Provider + ollama:setup
  • [x] Spatie-Media-Library Pro vorbereitet (Migration + Trait, Lizenz-Install nachträglich)
  • [x] Storybook mit 8 Komponenten-Story-Files
  • [x] 60+ Vue-Komponenten (Generic-Spec-Renderer + 10 Area-Bricks + 5 Snippets + 5 Page-Layouts)

14. Was noch nicht lokal funktioniert ​

  • [ ] Filament-Resource-Policies (shield:generate --all) — folgt nach Demo, brauchen Modell-Vollständigkeit
  • [ ] CI auf Forgejo — .woodpecker.yml vorbereitet, wartet auf erreichbares git.matev.eu

Alle anderen Bausteine aus migration/docs/filament-architecture-prompt.md Phase 8–22 sind verkabelt — Detail-Logik (z.B. PDF-Text-Extraktion in IndexRagSourcesJob) ist als TODO markiert und kann inkrementell ergänzt werden.