Appearance
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 --recursive2. 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
| Service | URL | Login |
|---|---|---|
| Filament Admin | https://admin.matev.ddev.site/admin | admin@matev.eu / admin |
| Filament Editor (Demo) | https://admin.matev.ddev.site/admin | editor@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-Tab | DB: 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 storybookWas 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-VariantenCMS / 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/panelURLs:
| URL | Inhalt |
|---|---|
https://cms.matev.ddev.site/ | Startseite mit Page-Builder (Server-Rendering) |
https://cms.matev.ddev.site/panel | Editor-UI (Blueprints) |
https://cms.matev.ddev.site/api/query | KQL-Endpoint (POST) |
https://cms.matev.ddev.site/produkte | Produkt-Übersicht |
https://cms.matev.ddev.site/produkte/kompaktkehrmaschine-mt500 | Beispiel-Produktseite |
https://cms.matev.ddev.site/haendler | Händler-Hub |
https://cms.matev.ddev.site/kontakt | Kontakt |
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.sitestaging/ 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.sh8. Häufige Fehler
| Symptom | Ursache & Lösung |
|---|---|
getaddrinfo for db failed | DDEV nicht gestartet — ddev start |
Access denied for user 'db'@'localhost' auf pimcore-Connection | matev_pimcore_source DB nicht angelegt — ddev restart (post-start-Hook legt sie an) |
tags-Tabelle fehlt beim Import | Erwartet — composer require spatie/laravel-tags einspielen, dann ddev exec "php artisan migrate" |
settings-Tabelle fehlt | Analog: composer require spatie/laravel-settings |
| Storybook lädt YAML nicht | bun install im storybook/ muss @modyfi/vite-plugin-yaml mitgezogen haben |
| Filament zeigt nur 401 | Default-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/indexesOpenSearch (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/healthVier 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/tagsContainer 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 restartDer 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-Mediadocumentschunked + 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\HasMediaAsset-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.ymlvorbereitet, wartet auf erreichbaresgit.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.