Dokumentation
Technische Dokumentation der Pammys-Produktsuche: Architektur, n8n-Aufbau, Matching-Logik, Daten-Contract, Dashboard und Abgabe. Dieselbe Doku liegt als README.md im Repository.
Überblick
Die Anwendung nimmt freie Texteingaben entgegen (z. B. snowboots nightfall 38, auch mit Tippfehlern) und erkennt entweder genau eine Produktvariante oder stellt eine gezielte Rückfrage nach Größe, Farbe oder Modell. Die Antwort formuliert anschließend eine KI in vier Sprachen.
Sie besteht aus einem n8n-Workflow für Verarbeitung und Produkterkennung (im Code, ohne KI) und einem React-Dashboard (Next.js) für Eingabe, Ergebnisanzeige mit Bildern und Verlauf.
Besonderheit: Modell, Farbe und Größe stehen gemeinsam in einem Titelfeld, z. B. Snowboots 2.0 - Nightfall - 38, und müssen erst daraus gelöst und robust abgeglichen werden.
Architektur & Datenfluss
Das Dashboard spricht n8n nie direkt an, sondern über zwei serverseitige Next.js-Proxy-Routes (/api/ask, /api/history). Das hält die Webhook-URLs auf dem Server und vermeidet CORS.
POST /api/askGET /api/historyGET /pammys-historyEine Anfrage durchläuft folgende Schritte:
- Der Nutzer gibt im Dashboard einen freien Text ein.
- Das Dashboard ruft
/api/askauf, die Route reicht{ query, locale }an den n8n-Webhook weiter. Get productslädt die Data Table,Match(Code Node) zerlegt die Titel und entscheidet genau einen von vier Fällen.- Der
AI Agentformuliert daraus die Antwort in vier Sprachen. Respondschickt die HTTP-Antwort und schreibt parallel eine Zeile nach Google Sheets.- Der Verlauf wird über einen zweiten Workflow (
/api/history) ausgelesen.
Tech-Stack
- Dashboard: Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS v4, shadcn/ui, next-intl, motion.
- Automation: n8n (self-hosted), Data Table, Code Node, AI Agent mit Anthropic
claude-haiku-4-5, Google Sheets. - Bindeglied: zwei n8n-Webhooks (POST für die Suche, GET für den Verlauf) über Next.js-Routes.
Lokales Setup
Voraussetzungen: Node.js 22+, pnpm (npm/yarn gehen auch), Zugriff auf die aktive n8n-Instanz.
pnpm install # .env.local anlegen, Variablen siehe unten pnpm dev # http://localhost:3000 pnpm build && pnpm start # Produktions-Build pnpm lint # ESLint
Ohne gesetzte Webhook-Variablen liefern die Proxy-Routes kontrollierte Fehlerzustände statt eines Absturzes.
Environment-Variablen
In .env.local (nicht eingecheckt). Beide Variablen werden ausschließlich serverseitig gelesen.
N8N_WEBHOOK_URL(POST): Hauptworkflow für die Produktsuche, erhält{ query, locale }.N8N_HISTORY_URL(GET): Verlaufs-Workflow, liefert alle Sheet-Zeilen als JSON-Array.
Datenmodell
Grundlage ist die CSV data/Pammys Products.csv mit 890 Zeilen und den Spalten status, product_title, image_url. Diese werden in die Data Table pammys_products übernommen; die Erkennung läuft auf deren Basis.
Die automatische id (1 bis 890) dient als Produkt-ID. Modell, Farbe und Größe entstehen zur Laufzeit durch Splitten des Titels am Trenner - :
"Snowboots 2.0 - Nightfall - 38"
-> model = "Snowboots 2.0"
color = "Nightfall"
size = "38"Größen können auch Bereiche sein (z. B. 40/41).
Matching-Logik
Die komplette Logik (Matching, Entscheidung, Optionen) passiert im Code, nicht in der KI. Das macht sie deterministisch und testbar. Kernbausteine:
- Normalisierung: Kleinschreibung, Akzente entfernt,
ßzuss, Sonderzeichen raus. - Tippfehler-Toleranz: Levenshtein, Treffer ab Ähnlichkeit 0.8 (
snowbotstrifftSnowboots). - N-Gramme: benachbarte Tokens werden zusammengezogen, sodass
snow bootsaufSnowbootsmatcht. - Farb-Synonyme: Deutsch und Englisch werden vereinheitlicht (
schwarz=black). - Größen-Bereiche: eine Eingabe
40trifft auch die Range40/41.
Je Modell wird ein Score gebildet. Ein Modell gilt als eindeutig, wenn sein Score hoch genug ist und klar über dem zweitbesten liegt; sonst folgt eine Modell-Rückfrage. Danach wird analog über Farbe und Größe entschieden. Zusätzlich liefert der Node immer bis zu vier Produkte mit image_url in results, damit das Dashboard immer Bilder zeigen kann.
Entscheidungslogik & Contract
Request an den Webhook: POST mit Body { query, locale }. Die Antwort ist genau einer von vier Fällen, jeweils ergänzt um results (bis zu vier Produkte mit Bild) und message mit den vier Sprachen.
A) Eindeutiger Match
Genau eine Variante wurde eindeutig identifiziert.
{
"type": "match",
"product": { "id": 524, "title": "Snowboots 2.0 - Nightfall - 38", "image_url": "..." },
"context": { "model": "Snowboots 2.0", "color": "Nightfall", "size": "38" },
"results": [ { "id": 524, "title": "...", "model": "...", "color": "...", "size": "38", "image_url": "..." } ],
"message": { "de": "...", "en": "...", "es": "...", "fr": "..." }
}B) Größe fehlt (missing_size)
Modell und Farbe sind klar, es existieren aber mehrere Größen.
{
"type": "question",
"question_key": "missing_size",
"options": ["36", "37", "38", "39", "40", "41", "42", "43"],
"context": {
"model": "Snowboots 2.0",
"color": "Nightfall",
"matched_candidates": [ { "id": 522, "title": "Snowboots 2.0 - Nightfall - 36", "image_url": "..." } ]
},
"results": [ ... ],
"message": { "de": "...", "en": "...", "es": "...", "fr": "..." }
}C) Farbe fehlt (missing_color)
Das Modell ist klar, es existieren aber mehrere Farben.
{
"type": "question",
"question_key": "missing_color",
"options": ["Beige", "Hellblau", "Rosa", "Schwarz", "Weiss"],
"context": {
"model": "Belt 2025",
"matched_candidates": [ { "color": "Beige", "image_url": "..." } ]
},
"results": [ ... ],
"message": { "de": "...", "en": "...", "es": "...", "fr": "..." }
}D) Modell unklar (ambiguous_model)
Kein Modell eindeutig, oder mehrere passen ähnlich gut.
{
"type": "question",
"question_key": "ambiguous_model",
"options": [ { "model": "Snowboots 2.0", "score": 0.82 } ],
"context": { "top_candidates": [ { "id": 1, "title": "...", "image_url": "..." } ] },
"results": [ ... ],
"message": { "de": "...", "en": "...", "es": "...", "fr": "..." }
}Sonderfall „nichts erkannt“
Bei einer vagen Eingabe wie asdf qwer kommt ambiguous_model mit leeren options, ohne context.model und mit leeren top_candidates. Der Agent benennt kein Produkt, das Dashboard zeigt einen neutralen Zustand statt erfundener Treffer.
AI-Agent
Der Agent ist ausschließlich für die Sprache zuständig, nicht für die Logik. Er erhält eine reduzierte Projektion (type, question_key, options, product, context) und gibt eine Antwort als { de, en, es, fr } zurück. Die Liste results sieht er bewusst nicht, damit er bei nicht erkannter Eingabe keine Produktnamen zur Hand hat.
Verbindliche Formulierungsregeln pro Fall:
- match: kurze Bestätigung mit dem vollständigen
product.title. - missing_size: Frage nach der Größe, nennt Modell und Farbe, listet die Optionen.
- missing_color: Frage nach der Farbe, nennt das Modell, listet die Optionen.
- ambiguous_model: Frage nach dem Modell, nennt die Modelle aus
options.
Außerdem: nichts erfinden, nur Werte aus dem JSON verwenden, keine neuen Optionen, Namen unverändert lassen, kurzer freundlicher Ton, keine Gedankenstriche.
Logging & Verlauf
Jede Anfrage wird als Zeile in die Google-Sheets-Tabelle „Pammys Produktsuche - Verlauf“ geschrieben (Service-Account). Spalten:
timestamp, query, type, question_key, status, reply, product_id, product_title, model, color, size, results_json, raw_json
results_json und raw_json enthalten die vollständigen Strukturen als JSON-String, sodass die Detailansicht Kandidaten samt Bildern rekonstruieren kann.
Ein zweiter Workflow „Pammys History“ liefert den Verlauf: Webhook (GET /pammys-history) ▸ Google Sheets (Read) ▸ Respond.
Dashboard
1. Produkteingabe
- Eingabefeld für eine freie Produktbeschreibung, schrittweiser Ablauf.
- Anzeige des erkannten Produkts bzw. der Rückfrage des Agenten in der gewählten Sprache.
2. Produktanzeige mit Bildern
- Produktbilder aus
image_urlin allen Fällen, auch wenn nur das Modell oder mehrere Kandidaten erkannt wurden. - Mehrere Kandidaten erscheinen übersichtlich als Grid neben- und untereinander.
- Beim eindeutigen Treffer zusätzlich Produkttitel, Modell, Farbe und Größe.
- Rückfragen verfeinern die Suche: Die Auswahl wird an die Query angehängt und neu gefragt.
3. Chat- / Eingabeverlauf
- Liste aller Anfragen unter
/historie, neueste zuerst, je Eintrag mit Datum, Uhrzeit, Preview und Status. - Einträge sind anklickbar.
- Die Detailseite
/historie/[id]zeigt das vollständige Ergebnis: gefundenes Produkt bzw. Kandidaten, jeweils mit Bild.
Mehrsprachigkeit
Das Dashboard unterstützt Deutsch, Englisch, Spanisch und Französisch über next-intl. Die UI-Texte liegen in messages/, diese Doku in src/lib/doc-content.ts, die Sprache wird im Header umgeschaltet. Auch die Antwort des Agenten folgt der UI-Sprache, da er alle vier Sprachen liefert und das Frontend die passende auswählt.
Tests
Die Matching-Logik des Code Nodes ist 1:1 als lokaler Harness gegen die echte CSV ausführbar, ohne laufendes n8n:
node scripts/match-harness.mjs
Abgedeckt sind die vier Fälle, Tippfehler (snowbots nightfal 38), getrennt geschriebene Modellnamen (snow boots nightfall 38) sowie der „nichts erkannt“-Fall.
Projektstruktur
src/app/page.tsx Einstieg -> SearchFlow src/app/api/ask/route.ts POST-Proxy auf N8N_WEBHOOK_URL src/app/api/history/route.ts GET-Proxy auf N8N_HISTORY_URL src/app/historie/page.tsx Verlaufsliste src/app/historie/[id]/page.tsx Verlaufs-Detailansicht src/app/dokumentation/page.tsx Diese Dokumentationsseite src/components/search-flow.tsx Zustandsmaschine der vier Faelle src/components/match-result.tsx Anzeige des eindeutigen Treffers src/components/product-grid.tsx Kandidaten-Grid mit Bildern src/lib/history.ts Mapping der Sheet-Zeilen auf Verlaufseintraege src/lib/doc-content.ts Inhalt dieser Seite (DE/EN/ES/FR) src/i18n/, messages/ Mehrsprachigkeit DE/EN/ES/FR data/Pammys Products.csv Quelle der Data Table (890 Zeilen) scripts/match-harness.mjs Lokaler Test der Match-Logik gegen die CSV n8n/ Workflow-JSON-Exporte (Haupt + History)
Abgabe
- Privates GitHub-Repository mit Leserecht für
lp@dieseo.de. - n8n-Workflows als JSON-Export im Ordner
n8n/(Hauptworkflow und History-Workflow). - Google Sheet „Pammys Produktsuche - Verlauf“ mit mindestens Betrachterzugriff für
lp@dieseo.de: