Ablauf

Der Label Compliance Check verbindet die DPP-Labels-Website mit einem n8n-Workflow. Das Frontend laedt ein Etikett-Bild hoch, der PHP-Server leitet es an n8n weiter, und das Frontend pollt, bis n8n die Ergebnisse zurueck-POSTet.

Frontend PHP-Server n8n-Workflow │ │ │ │── POST /api/label-check/submit ─────────────────────────────►│ │ (file + label_type) │ │ │◄── 202 { job_id } ─────────│ │ │ │ │ │── GET /status?job_id=… │ │ │ (Polling alle 5 Sek.) │ │ │◄── { status: "pending" } │ │ │ │ n8n verarbeitet… │ │ │◄── POST /callback │ │ │ + X-Callback-Secret │ │── GET /status (naechster Poll) │ │◄── { status: "complete", result: { … } } │ │ │ │ │ → Teaser-Dashboard │ │

Was n8n empfaengt (Submit → n8n)

Wenn ein Benutzer ein Etikett hochlaedt, sendet der PHP-Server eine multipart/form-data-Anfrage an die konfigurierte LABEL_CHECK_WEBHOOK_URL.

Feld Status Hinweis Beispiel
file Pflicht Das Etikett-Bild (JPG, PNG oder WEBP) label.jpg
job_id Pflicht 32-Zeichen Hex-ID zur Zuordnung "a1b2c3d4…"
label_type Pflicht Produkttyp "wein"
callback_url Pflicht URL, an die n8n das Ergebnis POSTen soll "https://dpp-labels.eu/api/label-check/callback"
payload Pflicht JSON-Metadaten inkl. Schema, Job, Callback und Datei-Meta {"schema_version":"1.1","job_id":"a1b2..."}

payload ist ein JSON-String und kann in n8n mit JSON.parse($json.body.payload) geparst werden. Der Payload enthaelt schema_version, source, Job-Felder sowie filename, mime_type, file_size und file_sha256. email ist beim initialen Upload immer null.

Authentifizierungs-Header:

Feld Status Hinweis Beispiel
X-Api-Key Optional Wird gesendet, wenn LABEL_CHECK_API_KEY in .env gesetzt ist "dpp-lc-key-abc123"
# Beispiel: So sieht der Request an n8n aus
curl -X POST https://your-n8n.com/webhook/label-check \
  -H "X-Api-Key: <LABEL_CHECK_API_KEY>" \
  -F "file=@etikett.jpg" \
  -F "job_id=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
  -F "label_type=wein" \
  -F "callback_url=https://dpp-labels.eu/api/label-check/callback" \
  -F 'payload={"schema_version":"1.1","source":"dpp-labels-label-check","job_id":"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6","status":"pending","label_type":"wein","callback_url":"https://dpp-labels.eu/api/label-check/callback","submitted_at":"2026-07-10T10:00:00+02:00","completed_at":null,"email_claimed":false,"email":null,"filename":"label.jpg","mime_type":"image/jpeg","file_size":123456,"file_sha256":"..."}'

Der Server versucht den n8n-Start-Webhook bis zu 3-mal mit je 8 Sekunden Timeout. HTTP <400 gilt als angenommen; Diagnosewerte werden ohne Secret-Werte in Jobdaten und Serverlog gespeichert.

POST /api/label-check/submit

Frontend-Endpunkt: Bild hochladen und Analyse starten.

Feld Status Hinweis Beispiel
file Pflicht Etikett-Bild (JPG, PNG, WEBP · max. 5 MB) (binaere Bilddaten)
label_type Pflicht wein | bier | kosmetik | lebensmittel | kerzen | elektronik "kosmetik"

Erfolgsantwort 202 Accepted

{
  "job_id": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
  "status": "pending"
}

Fehlerantworten

HTTP Ausloeser Beispiel
400 Datei fehlt, zu gross, falsches Format, ungueltiger Etikettentyp {"error": "Ungültiges Dateiformat. Erlaubt: JPG, PNG, WEBP."}
405 Nur POST erlaubt {"error": "Method not allowed"}
503 LABEL_CHECK_WEBHOOK_URL nicht konfiguriert oder n8n nicht erreichbar {"error": "Analyse-Service derzeit nicht erreichbar."}

POST /api/label-check/callback (n8n → PHP)

n8n ruft diesen Endpunkt auf, sobald die Analyse abgeschlossen ist. Wenn LABEL_CHECK_CALLBACK_SECRET konfiguriert ist, muss der Request den passenden Header X-Callback-Secret enthalten.

Header

Feld Status Hinweis Beispiel
Content-Type Pflicht application/json "application/json"
X-Callback-Secret Optional Pflicht, sobald LABEL_CHECK_CALLBACK_SECRET in .env gesetzt ist "mein-geheimnis-xyz"
🔒 Sicherheitshinweis Der X-Callback-Secret-Header verhindert, dass Dritte gefaelschte Ergebnisse an den Callback senden. Fuer produktiven Betrieb sollte derselbe Wert in .env und im n8n-HTTP-Node konfiguriert sein.

Body — Ergebnis-JSON

{
  "job_id": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
  "status": "complete",
  "label_type": "wein",
  "overall_score": 72,
  "categories": [
    {
      "name": "Pflichtangaben",
      "status": "pass",
      "teaser": "Alle gesetzlichen Mindestangaben vorhanden."
    },
    {
      "name": "EU-Lebensmittelrecht",
      "status": "warn",
      "teaser": "1 Angabe unvollstaendig oder fehlend."
    },
    {
      "name": "DPP-Bereitschaft",
      "status": "fail",
      "teaser": "Kein QR-Code / Digital Link erkannt."
    },
    {
      "name": "Sprachkonformitaet",
      "status": "pass",
      "teaser": "Sprachliche Anforderungen erfuellt."
    }
  ],
  "findings": [
    {
      "id": "f1",
      "severity": "warn",
      "title": "Naehrwertkennzeichnung unvollstaendig",
      "teaser_text": "Ballaststoffe und Salz fehlen in der Tabelle.",
      "full_text": "Gemaess EU 1169/2011 Art. 30 Abs. 1 muessen folgende Naehrwerte …"
    },
    {
      "id": "f2",
      "severity": "fail",
      "title": "Kein GS1 Digital Link erkannt",
      "teaser_text": "Kein QR-Code oder Digital-Link-URI auf dem Etikett gefunden.",
      "full_text": "Die EU-ESPR-Verordnung (Entwurf) sieht ab 2027 …"
    }
  ]
}

Datenvertrag im Detail

Root-Felder

Feld Status Hinweis Beispiel
job_id Pflicht Die 32-Zeichen Hex-ID aus Submit "a1b2c3d4…"
status Pflicht "complete" oder "error" "complete"
label_type Echo Echo des Etikettentyps "wein"
overall_score Pflicht 0–100 Compliance-Score 72
categories Pflicht Array von Kategorie-Bewertungen (Array)
findings Pflicht Array von Einzelbefunden (Array)

categories[*]

Feld Status Hinweis Beispiel
name Pflicht Name der Kategorie (Freitext) "Pflichtangaben"
status Pflicht pass | warn | fail "warn"
teaser Pflicht Einzeilige Zusammenfassung "1 Angabe fehlt."

Status-Werte (Ampel-System)

pass — Konform
⚠️ warn — Pruefbedarf
🔴 fail — Nicht konform

findings[*]

Feld Status Hinweis Beispiel
id Pflicht Eindeutige Befund-ID "f1"
severity Pflicht pass | warn | fail "warn"
title Pflicht Befund-Titel "Naehrwertkennzeichnung unvollstaendig"
teaser_text Pflicht Kurztext — im Teaser-Dashboard sichtbar "Ballaststoffe und Salz fehlen."
full_text Pflicht Volltext — nur im E-Mail-Report "Gemaess EU 1169/2011 Art. 30 …"
💡 Teaser vs. Volltext Das Frontend zeigt nur teaser_text der ersten 2 Befunde an. Alle weiteren Befunde (inkl. full_text) werden erst im per E-Mail versandten Vollbericht sichtbar. Dies dient als Lead-Magnet.

GET /api/label-check/status

Das Frontend pollt diesen Endpunkt alle 5 Sekunden, um den aktuellen Status abzufragen.

Feld Status Hinweis Beispiel
job_id Pflicht 32-Hex-ID als Query-Parameter "?job_id=a1b2c3d4…"

Antwort (ausstehend)

{
  "job_id": "a1b2c3d4…",
  "status": "pending",
  "submitted_at": "2026-07-08T10:00:00+02:00",
  "label_type": "wein"
}

Antwort (abgeschlossen)

Gibt das komplette Job-Objekt inkl. result zurueck. Das Feld visitor_email wird aus Datenschutzgruenden entfernt.

POST /api/label-check/claim

Besucher gibt seine E-Mail-Adresse ein, um den vollstaendigen Compliance-Bericht zu erhalten.

Feld Status Hinweis Beispiel
job_id Pflicht 32-Hex-ID "a1b2c3d4…"
email Pflicht Gueltige E-Mail-Adresse "info@example.de"
consent Pflicht Muss "1" sein (DSGVO-Einwilligung) "1"
_token Pflicht CSRF-Token aus der aktuellen Session "abc123…"

Umgebungsvariablen (.env)

Variable Beschreibung Beispiel
LABEL_CHECK_WEBHOOK_URL Webhook-URL des n8n-Label-Check-Workflows https://your-n8n.com/webhook/label-check
LABEL_CHECK_API_KEY Optionaler API-Key zur Authentifizierung beim n8n-Webhook (X-Api-Key Header) dpp-lc-key-abc123
LABEL_CHECK_CALLBACK_SECRET Optionaler geheimer Schluessel fuer n8n-Callbacks; empfohlen fuer produktiven Betrieb random-secret-string
# .env
LABEL_CHECK_WEBHOOK_URL=https://your-n8n.com/webhook/label-check
LABEL_CHECK_API_KEY=dpp-lc-key-abc123
LABEL_CHECK_CALLBACK_SECRET=generate-a-random-secret-here

Job-Dateistruktur

Jeder Analyse-Job wird als JSON gespeichert unter:

content/label-compliance-check/{job_id}.json

Lebenszyklus

Phase Aktion Status Ausloeser
1. Erstellt Job-Datei angelegt status: "pending" POST /api/label-check/submit
2. Aktualisiert Ergebnis eingetragen status: "complete" POST /api/label-check/callback (n8n)
3. Beansprucht E-Mail gespeichert email_claimed: true POST /api/label-check/claim

Fehlerbehandlung

Situation n8n-Aktion Frontend-Verhalten
Analyse erfolgreich POST callback mit "status": "complete" Teaser-Dashboard wird angezeigt
Analyse fehlgeschlagen POST callback mit "status": "error" Fehlermeldung im Loading-Panel
Bild nicht lesbar POST callback mit "status": "error" Fehlermeldung + Neuversuch-Option
Timeout (kein Callback) n8n antwortet nicht innerhalb 6 Min. Timeout-Meldung; wenn E-Mail angegeben, spaetere Benachrichtigung