Search by

tabsl / tabslfeedback

tabsl

Feedback-Formular für Backend und Frontend mit KI-Aufbereitung und Ticket-Anlage in GitLab, weclapp, Jira Cloud oder über einen eigenen Endpunkt.

Package info

github.com/tabsl/tabslFeedback

Type:oxideshop-module

pkg:composer/tabsl/tabslfeedback

Statistics

Installs: 528

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 1

2.3.1 2026-11-06 14:52 UTC

This package is auto-updated.

Last update: 2026-11-06 14:55:02 UTC


README

OXID eShop Modul für ein Feedback-Formular in Backend und Shop. Der Freitext des Melders wird wahlweise von OpenAI, Anthropic oder einem eigenen Endpunkt zu Titel und Beschreibung aufbereitet; daraus entsteht ein GitLab-Issue, ein weclapp-Helpdesk-Ticket, ein Jira-Cloud-Vorgang oder ein Vorgang über einen eigenen Endpunkt, mit Screenshots und technischem Kontext. Auch ganz ohne KI nutzbar.

Statt „Das geht nicht" per Telefon oder E-Mail — ohne URL, ohne Browser, ohne Screenshot, und ohne dass jemand die Meldung von Hand ins Ticketsystem überträgt.

Funktionen

Zwei Einstiege, getrennt schaltbar — im Backend ein Link im Header oben links, im Shop ein kleiner Button auf jeder Seite (Position wählbar). „Beide aus" ist ein zulässiger Zustand; ist das Ticket-Ziel nicht vollständig eingerichtet, erscheint gar kein Einstieg.

GitLab, weclapp, Jira Cloud oder eigener Endpunkt — tabslfeedback_ticket_target bestimmt, wo das Ticket entsteht: als GitLab-Issue, als Ticket im weclapp-Helpdesk, als Vorgang in Jira Cloud oder über einen eigenen Endpunkt, der den Vorgang anlegt; der Shop braucht dann keine Zugangsdaten zum Ticketsystem. Inhalt und Ablauf sind für den Melder identisch. In weclapp hängen die Screenshots als Dokumente, in Jira als Anhänge am Ticket; die Beschreibung ist dort HTML bzw. Atlassian Document Format statt Markdown.

Screenshots aus der Zwischenablage, abschaltbar — Bild kopieren, im Formular Strg+V bzw. ⌘+V. Mehrere Bilder pro Meldung, jedes mit Vorschau und einzeln entfernbar. Feedback ohne Bild bleibt möglich. Über tabslfeedback_screenshots_enabled lässt sich die Funktion komplett ausblenden, etwa wenn Screenshots datenschutzrechtlich vermieden werden sollen.

KI-Aufbereitung mit Rückfallebene — oder ganz ohne KI — der ursprüngliche Wortlaut steht immer zusätzlich im Ticket. tabslfeedback_ai_provider wählt zwischen OpenAI, Anthropic, einem eigenen Endpunkt und „Ohne KI". Der eigene Endpunkt ist eine frei eintragbare Adresse, die den unten beschriebenen Vertrag erfüllt; er erhält anders als OpenAI und Anthropic bei erlaubten Screenshots auch die Bilder. Fehlt bei aktivem Anbieter der API-Key (beim eigenen Endpunkt Adresse oder Token) oder antwortet der Dienst nicht, entsteht das Ticket trotzdem: mit Rohtext, Screenshots, Kontext und einem Vermerk, dass keine Aufbereitung stattfand. Bei „Ohne KI" zeigt das Formular stattdessen ein Betreff-Feld, dessen Inhalt direkt zum Ticket-Titel wird. Der Melder bemerkt in keinem Fall einen Unterschied im Ablauf.

Konfigurierbarer Hinweistext — tabslfeedback_notice_text zeigt einen kurzen, frei editierbaren Satz unmittelbar vor dem Absenden-Knopf, etwa zur Transparenz über die Übermittlung von Screenshots oder an einen KI-Dienst. Leer lässt den Hinweis entfallen.

Technischer Kontext am Ticket — in einem eingeklappten Block: Herkunft der Meldung, aufgerufene Seite, Referrer, Browser inkl. Version und Betriebssystem, Fenster- und Bildschirmgröße, Shop-ID, Sprache, Währung, Theme mit Version, aktive Module mit Versionen (abschaltbar über tabslfeedback_send_module_list), Shop- und PHP-Version. Bei angemeldeten Kunden optional Kundennummer, Name und E-Mail. Öffnet eine Shop-Seite das Formular selbst, steht davor zusätzlich der Bezug (siehe unten). Seite und Referrer werden zuvor bereinigt: Sitzungskennungen und geheimnisverdächtige Parameter (sid, stoken, token, password, secret …) werden durch … ersetzt; fachlich nützliche Parameter wie Kategorie, Suchbegriff oder Seitenzahl bleiben erhalten.

Formular ohne sichtbaren Button öffnen

Jede Shop-Seite lässt sich mit ?tabslFeedback=1 aufrufen — das Formular öffnet sich sofort, auch bei ausgeblendetem Button. Gedacht für Testende und Redaktion: Man verschickt den Link, ohne den Button für alle einzuschalten. Der Aufruf wird in der Session vermerkt: Auf den folgenden Seiten bleibt das Widget eingebunden, öffnet sich aber nicht mehr von selbst. ?tabslFeedback=0 (ebenso false, off, no) löscht den Vermerk und verhindert das sofortige Öffnen; ein eingeschalteter Button bleibt sichtbar.

Für Gäste ohne Session-Cookie startet OXID keine Session. Damit der Vermerk auch beim ersten Aufruf greift, gehört der Parameter in die config.inc.php:

$this->aRequireSessionWithParams = ['tabslFeedback' => true];

Mit tabslfeedback_frontend_access_key lässt sich der Wert festlegen, der das Formular öffnet: Ist ein Schlüssel eingetragen, wirkt nur noch ?tabslFeedback=<schlüssel>, ?tabslFeedback=1 bleibt ohne Wirkung. Ein geänderter Schlüssel beendet auch den Zugang laufender Sessions. Das gilt nur, solange tabslfeedback_frontend_enabled aus ist: Eingeschaltet liegt das Widget ohnehin für alle Besucher auf jeder Seite. Im Ticket wird der Wert des Parameters wie andere geheimnisverdächtige Parameter durch … ersetzt. Der Schlüssel steht trotzdem in Adresszeile, Browserverlauf und Server-Logs; er ist ein Link für Testende, kein Passwort.

⚠️ Der Zugangsschlüssel regelt nur, ob das Formular erscheint. Ohne Schlüssel ist der Parameter durch kein Geheimnis geschützt, und sein Name steht in diesem quelloffenen Repository. Die Einstellung „Feedback-Button im Shop anzeigen" regelt deshalb nur die Sichtbarkeit, nicht die Erreichbarkeit: Sobald das Ticket-Ziel vollständig eingerichtet ist, nimmt der Shop Feedback entgegen — auch bei ausgeblendetem Button. Wer das nicht möchte, lässt die Zugangsdaten leer oder deaktiviert das Modul. Gegen automatisierten Missbrauch schützt allein tabslTurnstile (siehe unten).

Formular aus dem Shop heraus öffnen

Wo eine Meldung entsteht, steht selten der Feedback-Button: im Bestellabschluss, in einem Konfigurator, in einem geöffneten Dialog. Solche Stellen öffnen das Formular selbst — ohne Seitenwechsel:

window.tabslFeedback.open({ reference: 'Entwurf 4711' });

reference ist frei wählbar und erscheint im Ticket als eigene Zeile Bezug, direkt über der Seite. Sie beantwortet, was die URL nicht beantworten kann: worum es in der Meldung geht. Ohne Angabe öffnet der Dialog wie über den Button.

Die Schnittstelle steht bereit, sobald das Widget auf der Seite liegt — also sobald „Feedback-Button im Shop anzeigen" eingeschaltet ist oder die Seite oder eine frühere Seite derselben Session mit ?tabslFeedback=1 aufgerufen wurde.

Soll der Shop den Dialog ausschließlich selbst öffnen, ohne dass irgendwo ein Button erscheint, braucht es beides: die Einstellung „Feedback-Button im Shop anzeigen" bleibt eingeschaltet und die Position steht auf none. Der Schalter bindet das Widget ein, die Position entscheidet über den Knopf. Nur die Position auf none zu stellen genügt nicht — bei ausgeschaltetem Schalter liegt auf gewöhnlichen Seiten kein Widget und damit kein window.tabslFeedback.

Der Wert reist als Angabe des Browsers und ist damit fälschbar wie jede andere Client-Angabe. Er wird auf 200 Zeichen gekürzt und maskiert ins Ticket geschrieben — als Hinweis gedacht, nicht als Beleg.

Schnellstart

composer require tabsl/tabslfeedback
vendor/bin/oe-console oe:module:activate tabslFeedback

Alternativ manuell nach source/modules/tabsl/tabslFeedback/ entpacken und im Backend unter Erweiterungen → Module aktivieren.

GitLab vorbereiten

  1. Projekt-ID — steht auf der Startseite des Zielprojekts unter dem Projektnamen bzw. im Menü ⋮ → „Projekt-ID kopieren".
  2. Zugangs-Token — im Zielprojekt unter Settings → Access tokens einen Project Access Token mit Scope api und Rolle Reporter (oder höher) anlegen. Einem persönlichen Token vorziehen: dessen Reichweite umfasst alle Projekte des Kontos, ein Project-Access-Token nur dieses eine.
  3. Benutzer-ID der zuständigen Person — steht in deren GitLab-Profil. Bleibt das Feld leer, entstehen Issues ohne Zuweisung.

weclapp vorbereiten

Nur nötig bei Ticket-Ziel weclapp.

  1. Adresse — die Adresse des Mandanten, z. B. https://firma.weclapp.com. Nur https ist zulässig.
  2. API-Benutzer und Token — einen eigenen weclapp-Benutzer anlegen, der nur Helpdesk-Rechte hat, und dessen Token unter Benutzername → Meine Einstellungen → API-Token kopieren. Der Token trägt sämtliche Rechte seines Benutzers, eine feinere Beschränkung bietet weclapp nicht. Tickets und Kommentare erscheinen unter diesem Benutzer. Wer einen neuen Token erzeugt, macht den bisherigen ungültig.
  3. Priorität und Kanal (dringend empfohlen) — die numerische ID steht in der Adresszeile, wenn der Eintrag in weclapp geöffnet ist. Beide sind in weclapp Pflichtfelder eines Tickets; für den Status gibt es eine Voreinstellung, für die Priorität dokumentiert weclapp keine. Ohne eingetragene ID kann deshalb jede Meldung abgelehnt werden. Das Shop-Log nennt dann das fehlende Feld, etwa ticketPriorityId (not_empty). Dasselbe gilt für Pflicht-Zusatzfelder, die der Mandant am Ticket eingerichtet hat; sie unterstützt das Modul nicht.
  4. Optional: Status, Kategorie, zuständige Person — ebenfalls als numerische ID; leer bleibt die Voreinstellung des Mandanten wirksam.

Jira Cloud vorbereiten

Nur nötig bei Ticket-Ziel jira. Unterstützt wird ausschließlich Jira Cloud, nicht Jira Data Center oder Server.

  1. Konto — ein eigenes Atlassian-Konto für den Shop anlegen, das im Zielprojekt nur Vorgänge anlegen darf. Der API-Token trägt die Rechte seines Kontos. Vorgänge und Kommentare erscheinen unter diesem Konto.
  2. API-Token — unter id.atlassian.com → Sicherheit → API-Token erstellen. Ein Token läuft nach höchstens einem Jahr ab; danach entstehen keine Vorgänge mehr und das Shop-Log meldet http 401. Ablaufdatum notieren.
  3. Adresse — die Site-Adresse, z. B. https://firma.atlassian.net. Wer statt eines normalen Kontos einen Atlassian-Service-Account nutzt, trägt die Gateway-Adresse https://api.atlassian.com/ex/jira/<Cloud-ID> ein und gibt dem Token die Scopes read:jira-work und write:jira-work. Die Cloud-ID steht unter https://firma.atlassian.net/_edge/tenant_info.
  4. Projekt-Key und Vorgangstyp — etwa SHOP; der Vorgangstyp steht auf Task voreingestellt. Er muss im Projekt existieren, sonst nennt das Shop-Log das Feld issuetype. Statt des Namens lässt sich die numerische ID des Vorgangstyps eintragen; sie hängt nicht von der Sprache der Site ab. Der Vorgangstyp darf außer Zusammenfassung und Beschreibung keine weiteren Pflichtfelder haben. Sonst lehnt Jira jede Meldung ab, und das Shop-Log nennt das fehlende Feld, etwa customfield_10020.
  5. Optional: zuständige Person — deren accountId steht in der Adresse ihres Jira-Profils. Die Person muss im Projekt zuweisbar sein.
  6. Optional: Kommentar am Vorgang der Seite — mit tabslfeedback_jira_comment_page_issue sucht das Shop-Widget im Quelltext der Seite nach Verweisen wie …/browse/SHOP-123. Gehört einer davon zum eingestellten Projekt, wird die Meldung als Kommentar an diesem Vorgang gespeichert, die Screenshots hängen mit Zeitstempel im Dateinamen am Vorgang. Es gilt der erste passende Verweis. Lehnt Jira den Kommentar ab (Vorgang gelöscht, keine Berechtigung), entsteht wie sonst ein neuer Vorgang. Enthält die Seite einen solchen Verweis, zeigt der Dialog das Kästchen "Als neuen Vorgang anlegen"; angehakt entsteht statt des Kommentars ein neuer Vorgang. Das Kästchen erscheint auch, wenn kein Verweis zum eingestellten Projekt gehört, und ist dann wirkungslos. Setzt einen Projekt-Key voraus, eine numerische Projekt-ID genügt nicht. Das Konto braucht im Projekt zusätzlich das Recht, Vorgänge zu kommentieren und Anhänge hinzuzufügen. Der Verweis kommt aus dem Browser: Wer das Formular erreicht, kann jeden Vorgang des Projekts kommentieren lassen, den das Konto sehen darf. Die Option deshalb nur einschalten, wo das Formular nicht öffentlich erreichbar ist oder Turnstile davor steht.

Eigener Endpunkt vorbereiten

Nur nötig bei Ticket-Ziel custom. Das Modul schickt jede Meldung in genau einem Aufruf an tabslfeedback_custom_ticket_url; Anlage, Anhänge und Upload-Vermerk übernimmt der Endpunkt. Jede Gegenstelle, die diesen festen Vertrag erfüllt, ist nutzbar. Er ist kein allgemeiner Webhook: Die Gegenstelle muss Atlassian Document Format, Projekt-Key und Vorgangstyp verstehen.

  • Aufruf: POST, immer multipart/form-data, auch ohne Bild, Token im Header X-API-Token. Beispieladresse: https://tickets.example.com/api/v1/jira/ticket-actions
  • Felder: action (fest create_issue), projectKey, issueType, summary (höchstens 255 Zeichen, einzeilig), description (ADF als JSON-String), ticketLanguage (source oder en, für die Sprache des Upload-Vermerks), internal (true oder false nach tabslfeedback_custom_ticket_internal, immer gesendet), je Bild eine Datei unter images[].
  • Mit aktivem tabslfeedback_custom_ticket_comment_page_issue und einem passenden Verweis auf der Shop-Seite zusätzlich commentOnIssue (Key) und comment (ADF als JSON-String). Die Meldung soll dann als Kommentar an diesen Vorgang gehen; lehnt das Ticketsystem ihn ab, legt der Endpunkt aus den übrigen Feldern einen neuen Vorgang an. Für die Option gelten die Hinweise bei Jira Cloud (Punkt 6): Der Verweis kommt aus dem Browser.
  • Erfolg: HTTP 201 mit {"key": "SHOP-123", "created": true, "attachmentsFailed": 0}. key muss zum eingestellten Projekt gehören. created: false meldet den Kommentar am bestehenden Vorgang. Eine Zahl in attachmentsFailed steht im Shop-Log; den Vermerk am Vorgang schreibt der Endpunkt.
  • Jede andere Antwort beendet den Vorgang mit der allgemeinen Fehlermeldung. Als sicher nicht entstanden gelten 3xx, 4xx, 503 mit {"reason": "instance_not_ready"} und 502 mit {"issueStateUnknown": false}. Alles andere gilt als unbekannter Zustand, auch ein anderes 2xx oder eine abgebrochene Antwort.
  • Fürs Shop-Log wertet das Modul reason, jiraStatus, fields und bei 429 den Header Retry-After aus, jeweils nur bekannte Werte. Freie Texte wie message übernimmt es nie, damit keine zurückgespiegelten Meldungsinhalte im Log landen. Die genaue Ursache einer Ablehnung steht dann nur bei der Gegenstelle.
  • Das Modul wartet höchstens 95 Sekunden, folgt keinen Weiterleitungen und wiederholt keine Anfrage. assigneeAccountId sendet es nicht.

Modul konfigurieren

Backend → Erweiterungen → Module → tabslFeedback → Einstellungen:

Einstellung Bedeutung Standard
tabslfeedback_admin_enabled Feedback-Link im Backend-Header einblenden aus
tabslfeedback_frontend_enabled Widget im Shop einbinden — mit Button, außer die Position steht auf none (nur Sichtbarkeit, nicht Erreichbarkeit) aus
tabslfeedback_button_position bottom-left, center, bottom-right oder none (kein Button, siehe unten) bottom-right
tabslfeedback_frontend_access_key Zugangsschlüssel: Gesetzt öffnet nur ?tabslFeedback=<schlüssel> das Formular, leer jeder Wert außer 0/false/off/no (siehe unten) leer
tabslfeedback_ticket_target gitlab, weclapp, jira oder custom (eigener Endpunkt) — wo das Ticket entsteht gitlab
tabslfeedback_gitlab_url Basis-Adresse der GitLab-Instanz inkl. Schema, ohne /api/v4 — Pflicht bei Ziel gitlab leer
tabslfeedback_gitlab_project_id Numerische ID des Zielprojekts — Pflicht bei Ziel gitlab leer
tabslfeedback_gitlab_token Project-Access-Token mit Scope api — Pflicht bei Ziel gitlab leer
tabslfeedback_gitlab_assignee_id Benutzer-ID für die Zuweisung; leer = keine Zuweisung leer
tabslfeedback_weclapp_url Adresse des weclapp-Mandanten mit https:// — Pflicht bei Ziel weclapp leer
tabslfeedback_weclapp_token API-Token eines weclapp-Benutzers — Pflicht bei Ziel weclapp leer
tabslfeedback_weclapp_ticket_status_id Status-ID neuer Tickets; leer = Voreinstellung leer
tabslfeedback_weclapp_ticket_priority_id Prioritäts-ID — dringend empfohlen, siehe oben leer
tabslfeedback_weclapp_ticket_channel_id Kanal-ID — dringend empfohlen, siehe oben leer
tabslfeedback_weclapp_ticket_category_id Kategorie-ID; leer = keine Kategorie leer
tabslfeedback_weclapp_assignee_id Benutzer-ID für die Zuweisung; leer = keine Zuweisung leer
tabslfeedback_jira_url Site- oder Gateway-Adresse mit https:// — Pflicht bei Ziel jira leer
tabslfeedback_jira_email E-Mail des Kontos, zu dem der Token gehört — Pflicht bei Ziel jira leer
tabslfeedback_jira_token API-Token — Pflicht bei Ziel jira leer
tabslfeedback_jira_project_key Projekt-Key oder numerische Projekt-ID — Pflicht bei Ziel jira leer
tabslfeedback_jira_issue_type Name oder ID des Vorgangstyps; leer = Task Task
tabslfeedback_jira_assignee_account_id accountId für die Zuweisung; leer = Standardzuweisung des Projekts leer
tabslfeedback_jira_comment_page_issue Meldung als Kommentar an dem Vorgang, auf den die Seite verweist (/browse/KEY-123), statt als neuer Vorgang; siehe oben aus
tabslfeedback_custom_ticket_url Adresse des Endpunkts, z. B. https://tickets.example.com/api/v1/jira/ticket-actions; nur https://, http:// nur für localhost — Pflicht bei Ziel custom leer
tabslfeedback_custom_ticket_token Token für den Header X-API-Token, unabhängig vom Token des KI-Endpunkts — Pflicht bei Ziel custom leer
tabslfeedback_custom_ticket_project_key Projekt-Key, mindestens zwei Zeichen, Buchstaben und Ziffern, keine numerische ID — Pflicht bei Ziel custom leer
tabslfeedback_custom_ticket_issue_type Name oder ID des Vorgangstyps; leer = Task Task
tabslfeedback_custom_ticket_comment_page_issue Meldung als Kommentar am Vorgang der Seite, wie bei Jira; siehe oben aus
tabslfeedback_custom_ticket_internal Neuen Vorgang als intern markieren (internal = true); aus sendet internal = false aus
tabslfeedback_notice_text Kurzer Hinweistext vor dem Absenden-Knopf; leer = kein Hinweis Hinweis auf Screenshot-Übermittlung
tabslfeedback_ai_provider none, openai, anthropic oder custom (eigener Endpunkt) — bei none erscheint statt der Aufbereitung ein Betreff-Feld openai
tabslfeedback_openai_key OpenAI API-Key; nur bei Anbieter openai; leer = Ticket ohne Aufbereitung leer
tabslfeedback_openai_model Verwendetes OpenAI-Modell gpt-4o-mini
tabslfeedback_anthropic_key Anthropic API-Key; nur bei Anbieter anthropic; leer = Ticket ohne Aufbereitung leer
tabslfeedback_anthropic_model Verwendetes Anthropic-Modell claude-haiku-4-5-20251001
tabslfeedback_custom_ai_url Adresse des eigenen Endpunkts, z. B. https://ki.example.com/feedback/drafts; nur https://, http:// nur für localhost; leer = Ticket ohne Aufbereitung leer
tabslfeedback_custom_ai_token Token für den Header X-API-Token; leer = Ticket ohne Aufbereitung leer
tabslfeedback_ticket_language source = Sprache der Meldung behalten, en = immer Englisch source
tabslfeedback_show_contact_fields Optionale Felder für Name und E-Mail anzeigen aus
tabslfeedback_send_customer_data Bei angemeldeten Kunden Kundennummer, Name und E-Mail ins Ticket übernehmen aus
tabslfeedback_send_module_list Liste der aktiven Module mit Versionen ins Ticket übernehmen an
tabslfeedback_screenshots_enabled Screenshot-Funktion im Formular anzeigen an

Fehlt eine Pflichtangabe des gewählten Ziels — bei GitLab eine der drei Angaben oder das http:// bzw. https:// in der Adresse, bei weclapp Token oder https://, bei Jira Cloud eine der vier Pflichtangaben, https://, ein gültiger Projekt-Key oder eine Adresse ohne zusätzlichen Pfad (außer der Gateway-Adresse), beim eigenen Endpunkt Token, gültiger Projekt-Key oder eine zulässige Adresse —, erscheint weder Header-Link noch Frontend-Button: ein Formular, das kein Ticket erzeugen kann, wird gar nicht erst angeboten. Das Modul enthält keine Vorbelegung für Adressen, Projekt-IDs oder Zugangsdaten.

⚠️ Die GitLab-Adresse sollte auf https:// lauten. Der Zugangs-Token wird als HTTP-Header übertragen; über http:// wandert er unverschlüsselt durchs Netz. Für interne Instanzen bleibt http:// möglich, wird aber bei jeder Absendung im Shop-Log vermerkt.

Eigener KI-Endpunkt

Mit tabslfeedback_ai_provider = custom schickt das Modul jede Meldung per POST an tabslfeedback_custom_ai_url, mit dem Token im Header X-API-Token. Jede Gegenstelle, die diesen Vertrag erfüllt, ist nutzbar.

  • Ohne Bilder: Content-Type: application/json, Body {"text": "…", "language": "de", "ticketLanguage": "source"}
  • Mit Bildern: multipart/form-data mit den Feldern text, language, ticketLanguage und je Bild einer Datei unter images[]. Bilder gehen nur mit, wenn tabslfeedback_screenshots_enabled aktiv ist.
  • language ist die Shop-Sprache als ISO 639-1 in Kleinbuchstaben, ticketLanguage der Wert von tabslfeedback_ticket_language.
  • Erfolg: HTTP 200 mit {"title": "…", "description": "…"}. Der Titel wird auf 120 Zeichen gekürzt, die Beschreibung darf leer sein.
  • Jeder andere Status, am besten mit {"code": "…", "message": "…"}, führt zum Ticket ohne Aufbereitung; Status, code, message und bei 429 der Header Retry-After stehen im Shop-Log.
  • Das Modul wartet höchstens 25 Sekunden, folgt keinen Weiterleitungen und wiederholt keine Anfrage.

Grenzwerte

Fest eingebaut, bewusst nicht konfigurierbar: 5 Bilder je Meldung, 10 MB je Bild, 20 MB für alle Bilder zusammen, 5.000 Zeichen Freitext, 120 Zeichen für den Betreff (nur bei Anbieter „Ohne KI" sichtbar), je 255 Zeichen für Name und E-Mail, 200 Zeichen für den Bezug; Formate PNG, JPG, GIF, WebP.

Alle Grenzen werden serverseitig durchgesetzt. Der Vertrag des eigenen KI-Endpunkts hat dieselben Grenzen. Damit mehrere Screenshots durchkommen, sollten post_max_size und memory_limit der PHP-Installation oberhalb von 20 MB liegen.

Bei den Ticket-Zielen weclapp und Jira Cloud entsteht das Ticket vor den Screenshots. Für deren Übertragung gilt ein festes Zeitbudget von 20 Sekunden; nicht mehr übertragene Bilder vermerkt ein Kommentar am Ticket. Der Timeout des Webservers (etwa fastcgi_read_timeout bei nginx, Standard 60 Sekunden) sollte bei diesen Zielen mindestens 120 Sekunden betragen. Sonst kann der Melder eine Fehlermeldung sehen, obwohl das Ticket bereits angelegt ist, und durch erneutes Absenden ein zweites Ticket erzeugen. Mit einem eigenen KI-Endpunkt kann schon die Aufbereitung bis etwa 30 Sekunden dauern; die Empfehlung von 120 Sekunden gilt dann für alle Ziele, auch für GitLab.

Beim Ticket-Ziel custom gehen Meldung und Screenshots in einem Aufruf, der bis zu 95 Sekunden dauern darf. Der Webserver-Timeout sollte dort mindestens 130 Sekunden betragen. Die Bilder liegen beim Absenden als Daten-URL, dekodiert und im Aufruf zugleich im Speicher; memory_limit entsprechend großzügig wählen. Der Vertrag des Endpunkts hat dieselben Bildgrenzen wie das Modul. Lehnt der Endpunkt die Bilder trotzdem ab, entsteht kein Ticket.

Welche Daten gehen an wen

Grundlage für die Datenschutzerklärung des einsetzenden Shops. Übermittelt wird ausschließlich beim Absenden einer Meldung.

An OpenAI (api.openai.com) oder Anthropic (api.anthropic.com) — je nach tabslfeedback_ai_provider ausschließlich der Freitext der Meldung, an genau einen der KI-Dienste. Nicht: Screenshots, Name, E-Mail, Kundendaten, Umgebungsdaten, IP-Adresse, Shop-Adresse. Schreibt ein Melder personenbezogene Angaben in den Freitext, werden diese mit übertragen — darauf hat das Modul keinen Einfluss. Steht der Anbieter auf „Ohne KI" oder fehlt der API-Key, findet keine Übermittlung statt.

An den eigenen Endpunkt — bei Anbieter custom der Freitext, die Shop-Sprache, die Ticket-Sprache und bei aktivem tabslfeedback_screenshots_enabled alle angehängten Screenshots. Empfänger ist die in tabslfeedback_custom_ai_url eingetragene Adresse; deren Wahl verantwortet der Betreiber. Nicht: Name, E-Mail, Kundendaten, Umgebungsdaten, IP-Adresse des Melders. Fehlen Adresse oder Token, findet keine Übermittlung statt.

An den eigenen Endpunkt als Ticket-Ziel — bei Ziel custom dasselbe wie an ein direktes Ticket-Ziel, also deutlich mehr als an den KI-Endpunkt: Freitext, aufbereiteter Titel und Beschreibung, alle Screenshots, optional Name und E-Mail, der technische Kontext samt Seitenadresse und, bei aktivem tabslfeedback_send_module_list, Modulliste, Kundendaten nur bei aktivem tabslfeedback_send_customer_data. Empfänger ist die in tabslfeedback_custom_ticket_url eingetragene Adresse; was dort gespeichert oder weitergegeben wird, bestimmt deren Betreiber, und die Wahl verantwortet der Shop-Betreiber. Ist dieselbe Gegenstelle auch KI-Endpunkt, erhält sie beides. Mit aktivem tabslfeedback_custom_ticket_comment_page_issue sendet das Widget zusätzlich bis zu zehn im Quelltext gefundene Vorgangs-Keys an den Shop, der ausgewählte geht an den Endpunkt.

An die konfigurierte GitLab-Instanz, den weclapp-Mandanten bzw. die Jira-Cloud-Site — je nach tabslfeedback_ticket_target an genau eines der drei Ziele: Freitext, aufbereiteter Titel und Beschreibung, alle Screenshots, optional Name und E-Mail sowie der oben beschriebene technische Kontext; bei einem vom Shop selbst geöffneten Dialog zusätzlich der übergebene Bezug. Kundendaten nur bei aktivem tabslfeedback_send_customer_data. Nicht: IP-Adresse, Warenkorb- und Bestellkontext, Browser-Konsolenmeldungen. Bei einer eigenen GitLab-Installation verlassen die Daten die eigene Infrastruktur nicht; bei weclapp liegen sie beim Mandanten in der weclapp-Cloud, Screenshots als Dokumente am Ticket; bei Jira Cloud in der Atlassian-Cloud, Screenshots als Anhänge am Vorgang. Mit aktivem tabslfeedback_jira_comment_page_issue sendet das Widget zusätzlich bis zu zehn im Quelltext gefundene Vorgangs-Keys an den Shop; sie dienen nur der Wahl des Vorgangs und stehen nicht im Kommentar. Hakt der Melder "Als neuen Vorgang anlegen" an, sendet das Widget keine Keys.

An Cloudflare (challenges.cloudflare.com) — nur bei aktivem tabslTurnstile: der Turnstile-Token und die von Cloudflare selbst erhobenen Browser-Signale. Die IP-Adresse des Melders wird ausdrücklich nicht weitergegeben; das optionale Feld remoteip bleibt leer.

Nirgendwohin — das Modul legt keine eigene Datenbanktabelle an und speichert Meldungen nirgends im Shop. Kein Zwischenspeicher, keine Wiedervorlage: Ist das Ticket-Ziel nicht erreichbar, ist die Meldung verloren, und der Melder erhält eine Fehlermeldung statt einer falschen Bestätigung.

Ins Shop-Log

Damit ausbleibende Tickets auffallen, hält das Modul technische Störungen im Shop-Log fest, jeweils mit dem Präfix [tabslFeedback]:

Ereignis Stufe
Issue- bzw. Ticket-Anlage fehlgeschlagen (Meldung verloren) — bei weclapp und Jira inkl. HTTP-Status und abgelehnter Felder, bei Jira 401 mit Hinweis auf abgelaufenen Token error
weclapp bzw. Jira antwortet bei der Ticket-Anlage nicht (Zeitüberschreitung) — Ticket kann trotzdem entstanden sein, vor erneutem Absenden nachsehen error
Screenshot-Upload fehlgeschlagen (Bild fehlt im Ticket) error
Kommentar am weclapp-Ticket bzw. Jira-Vorgang fehlgeschlagen error
Jira lehnt den Kommentar am Vorgang der Seite ab — stattdessen entsteht ein neuer Vorgang error
Jira antwortet beim Kommentar am Vorgang der Seite nicht oder mit 5xx — Kommentar kann trotzdem stehen, vor erneutem Absenden nachsehen error
Eigener Endpunkt lehnt ab (Meldung verloren) — mit HTTP-Status und bekannten Werten aus reason und fields, bei 400 und 413 Anzahl und Größe der Bilder, bei 429 retry-after error
Eigener Endpunkt antwortet nicht eindeutig (ticket state unknown) — Ticket kann trotzdem entstanden sein, vor erneutem Absenden nachsehen error
Eigener Endpunkt meldet nicht angehängte Screenshots (Anzahl und Vorgang) error
KI-Aufbereitung fehlgeschlagen — inkl. HTTP-Status und Fehlermeldung error
Absendung bei unvollständiger Konfiguration abgewiesen error
Unerwarteter Fehler beim Absenden (einzeilig und gekürzt) error
Zustand des Schutzmoduls nicht ermittelbar error
Schutzmodul aktiv, liefert aber nicht die erwartete Schnittstelle error
GitLab-Adresse nutzt http statt https warning
Bot-Prüfung nicht bestanden (Normalbetrieb) info

Nicht protokolliert werden Meldungstext, Kontaktangaben, Kundendaten, Screenshots und Zugangsdaten.

Hinweis: OXID protokolliert standardmäßig erst ab Stufe error. Für warning und info muss sLogLevel in source/config.inc.php gesetzt werden: $this->sLogLevel = 'warning';

Entsteht ein Ticket ohne Aufbereitung, steht der Grund als error im Log — etwa openai request failed — http 401, api: invalid_api_key oder custom ai request failed — http 429, retry-after: 30, api: …. Abgelaufener Schlüssel, erschöpftes Kontingent und Zeitüberschreitung sind daran unterscheidbar. Eine unzulässige Adresse des eigenen Endpunkts erscheint als custom ai url rejected — https required; Adresse und Token stehen nie im Log.

Missbrauchsschutz im Shop

Das Frontend-Formular ist öffentlich erreichbar. Jede Absendung erzeugt ein Ticket im gewählten Ziel und einen kostenpflichtigen KI-Aufruf — ein Bot kann also sowohl das Projekt bzw. den Helpdesk fluten als auch Kosten verursachen.

Das Modul unterstützt dafür tabslTurnstile (Cloudflare Turnstile für OXID 6): Ist es installiert, aktiviert und mit Site-Key konfiguriert, erscheint im Formular ein Turnstile-Widget und die Absendung wird serverseitig geprüft — besteht die Prüfung nicht, entsteht weder ein Ticket noch wird der KI-Anbieter angesprochen. Fehlt das Modul, läuft tabslFeedback vollständig weiter; der Schutz entfällt ersatzlos, ohne Fehler und ohne Installationsaufforderung. Das Backend-Formular ist von der Prüfung ausgenommen, da bereits durch die Anmeldung geschützt.

⚠️ Der öffentliche Betrieb des Frontend-Formulars ohne Schutzmodul erfolgt auf eigenes Risiko. Wer keinen Bot-Schutz einsetzen möchte, sollte das Frontend-Formular deaktiviert lassen und nur das Backend-Formular nutzen.

Es gibt bewusst kein eigenes Rate-Limiting: ohne Zwischenspeicher wäre es nur über die Session abbildbar und damit gegen Bots wirkungslos.

Kosten

GitLab — keine zusätzlichen Kosten. weclapp — keine Kosten über die bestehende weclapp-Lizenz hinaus; der API-Benutzer belegt allerdings einen Benutzer-Platz. Jira Cloud — keine Kosten über die Jira-Lizenz hinaus; ein normales Konto für den Shop belegt allerdings einen Benutzer-Platz. Eigener Endpunkt als Ticket-Ziel — nach Vereinbarung mit dessen Betreiber. OpenAI oder Anthropic — je Meldung ein Aufruf mit dem Freitext (höchstens 5.000 Zeichen) und einer kurzen Antwort; mit den voreingestellten Modellen (gpt-4o-mini bzw. claude-haiku-4-5-20251001) liegen die Kosten pro Meldung bei Bruchteilen eines Cents, Bilder werden nicht übermittelt. Eigener Endpunkt — nach Vereinbarung mit dessen Betreiber; Bilder werden mitübertragen. Bei Anbieter „Ohne KI" entfällt dieser Posten vollständig. Cloudflare Turnstile — dauerhaft kostenlos.

Was das Modul nicht tut

  • Keine Feedback-Übersicht, kein Archiv, keine Wiedervorlage — das gewählte Ticket-Ziel ist die einzige Ablage
  • Keine Hintergrundverarbeitung: das Ticket entsteht beim Absenden
  • Keine Bildauswertung durch OpenAI oder Anthropic; beim eigenen Endpunkt entscheidet dessen Betreiber, ob er die übermittelten Screenshots auswertet
  • Keine Labels, keine automatische Einstufung von Priorität oder Kategorie, keine Duplikaterkennung; bei weclapp lassen sich Priorität und Kategorie fest vorgeben
  • Keine Rückmeldung an den Melder über den Bearbeitungsstand
  • Genau ein Ziel je Shop: ein GitLab-Projekt, ein weclapp-Mandant, ein Jira-Cloud-Projekt oder ein eigener Endpunkt, nicht mehrere zugleich; kein Jira Data Center, keine GitHub- oder E-Mail-Ziele
  • Bei Jira und beim eigenen Endpunkt keine Zusatzfelder: Vorgangstypen mit weiteren Pflichtfeldern werden nicht unterstützt
  • Beim eigenen Endpunkt keine frei abbildbaren Felder oder Formate und keine Wiederholung; schöpft das öffentliche Formular ein Limit der Gegenstelle aus, gehen Meldungen verloren, Turnstile davor senkt das Risiko
  • Keine Verknüpfung des Melders mit einem weclapp-Kunden oder -Kontakt

Kompatibilität

OXID eShop 6.x, PHP 7.4 und PHP 8.x. Getestet mit den Themes wave und ps; das Frontend-Widget bindet sich an den Block base_js und setzt weder jQuery noch Bootstrap voraus.

Frontend-Assets

Ausgeliefert werden out/src/js/tabslfeedback.min.js und out/src/css/tabslfeedback.min.css. Die lesbaren Quelldateien liegen unter demselben Namen ohne .min daneben und sind die einzige Stelle, an der Änderungen vorgenommen werden — die minifizierten Fassungen entstehen daraus:

make minify   # erzeugt die .min-Dateien neu
make verify   # prüft, ob die .min-Dateien zum Quellstand passen

Beides braucht Node. Die Werkzeuge (terser, clean-css-cli) sind in package.json auf exakte Versionen festgelegt und werden beim ersten Lauf per npm ci installiert. Das ist kein Zufall: Eine andere terser-Version erzeugt aus derselben Quelle ein anderes Ergebnis, und da die minifizierten Dateien im Repository liegen, entstünde sonst bei jedem Beitragenden ein Komplett-Diff auf unveränderter Quelle.

make minify bricht ab, wenn ein Werkzeug einen Fehler meldet oder keine bzw. eine leere Ausgabedatei entsteht; das erzeugte JavaScript wird zusätzlich mit node --check geprüft. Warnungen von clean-css werden ausgegeben, brechen den Lauf aber nicht ab — sie sind kein verlässliches Qualitätssignal: eine leere Property löst eine Warnung aus, obwohl die Ausgabe in Ordnung ist, während eine verworfene leere Regel stillschweigend passiert.

make verify vergleicht den Inhalt: Es erzeugt die Assets in ein temporäres Verzeichnis neu und prüft sie byteweise gegen die eingecheckten Dateien. Ein Zeitstempel-Vergleich wäre wertlos, weil Git keine mtimes wiederherstellt — nach einem Clone liegen Quelle und .min in derselben Sekunde. So findet verify auch eine von Hand bearbeitete .min-Datei und eignet sich damit sowohl für einen Pre-Commit-Hook als auch für CI.

⚠️ Wer nur die Quelldatei ändert, ändert nichts am Shop. Eingebunden wird ausschließlich die .min-Fassung; ohne make minify läuft weiterhin der alte Stand.

Support

Open Source, ohne Anspruch auf Support oder Reaktionszeiten. Fehlerberichte und Verbesserungsvorschläge sind über die GitHub-Issues willkommen; eine Bearbeitung erfolgt nach Möglichkeit.

Changelog

Siehe CHANGELOG.md.

License

GNU General Public License v3.0 — siehe LICENSE.

Copyright

Tobias Merkl | https://oxid-module.eu