Ext Ops Panel
Dashboard öffnen

Start/Doks/Feedback

Feedback-Vertrag

Vertragsversion 1.0.0 · in jedem Tarif enthalten

Ein kleiner Dialog, den Besucher auf jeder Seite Ihrer Website oder Ihres Produkts öffnen können, um zu sagen, was nicht funktioniert oder fehlt. Fügen Sie ein Script-Tag ein oder rufen Sie den Endpunkt aus Ihrem eigenen Dialog auf. Was ankommt, landet in einem Block im Panel neben der Deinstallations-Umfrage und Rate Us, und der Eigentümer erhält eine Nachricht im Posteingang.

↓ OpenAPI 3.1 (YAML) herunterladen /feedback-openapi.yaml · info.version 1.0.0

1. Widget einfügen

Ein verzögert geladenes Script-Tag ohne Inline-Code, daher übersteht es eine strenge CSP:

<script src="https://extops.dev/widget.js"
        data-extops-widget="wk_XXXXXXXXXXXXXXXXXXXXXXXXXXXX" defer></script>

Erlauben Sie unseren Origin in script-src und connect-src. Die Datei wird von uns ausgeliefert, hat keine Abhängigkeiten und bleibt unter 7 KB gzip; ihre Stile laufen über das CSSOM in einem Shadow Root, daher brauchen Sie kein 'unsafe-inline', und das CSS Ihrer Seite kann den Dialog nicht verändern.

Optionale Attribute: data-locale, data-api, data-position="left" und data-button="false", wenn Sie den Dialog selbst mit window.ExtOpsFeedback.open() öffnen wollen. Außerdem: data-button-style="icon" für eine runde 48-px-Symbolschaltfläche, data-surface="app", um sie auf dem Telefon über die untere Navigation einer App zu heben, und data-color-preset, um die Farbe der Schaltfläche von der Seite aus festzulegen.

Helles und dunkles Design

Jede Farbvorlage wird in einem hellen und einem dunklen Design gezeichnet. Standardmäßig (data-theme="auto") folgt das Widget Ihrer Seite: <html data-theme>, einer Klasse dark oder light auf <html> oder deren color-scheme. Eine Seite ohne eigenes Design erhält das Design des Betriebssystems der Besucher. Wenn Ihr Design-Umschalter eine dieser Angaben ändert, färbt sich das Widget sofort um, ohne Neuladen.

Um das Design festzulegen, setzen Sie data-theme="light" oder data-theme="dark". Wenn Ihre Seite ihr Design an einer Stelle speichert, die das Widget nicht sieht, rufen Sie window.ExtOpsFeedback.setTheme('dark') aus Ihrem Umschalter auf, und setTheme('auto'), um wieder der Seite zu folgen.

2. Oder den Endpunkt selbst aufrufen

Für eine Website, die gar kein fremdes Skript erlaubt, oder ein Produkt, das das Formular im eigenen Designsystem haben will. Derselbe Endpunkt, an den unser Widget sendet: Sie müssen nie zwischen Ihrer Oberfläche und unserer Pipeline wählen.

await fetch('https://extops.dev/api/v1/feedback/widget', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    widget_key: 'wk_XXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    topic: 'bug',
    comment: userText,
    page: location.href,
    locale: navigator.language,
    event_id: crypto.randomUUID(),
    dwell_ms: Date.now() - openedAt,
  }),
});

Lesen Sie die vom Inhaber konfigurierten Themen aus GET /api/v1/feedback/widget/config?key=…, damit Ihr Dialog genau das anbietet, was das Panel anbietet. Verwenden Sie bei Wiederholungen dieselbe event_id: Der Server dedupliziert darüber, sodass ein wackeliges Netz aus einer Nachricht keine zwei macht.

3. Der Widget-Schlüssel ist absichtlich öffentlich

Er steht im Quelltext Ihrer Seite, und das ist in Ordnung: Er kann nur eine Feedback-Zeile anlegen. Er kann keine Installations- oder Deinstallationsereignisse schreiben, nichts außer der Dialogkonfiguration lesen und kein Projekt benennen (project_id im Body wird nicht akzeptiert). Deshalb bekommt ein Widget einen eigenen Schlüssel statt des webhook_token Ihrer Quelle, der Metrik-Ereignisse schreiben kann und nie im HTML stehen darf. Sie können den Schlüssel jederzeit neu ausstellen; der alte wird sofort nicht mehr akzeptiert.

4. Was wir speichern und was nicht

Wir speichern das Thema, den Text, die normalisierte Seite, die Sprache, einen optionalen Kontakt, die Zeit, die Art des Feedbacks und welches Widget es erfasst hat.

Die Aufbewahrungsdauer beträgt 180 Tage, dieselbe Regel wie für jede andere Art von Feedback.

5. Antworten und Fehlercodes

Ein Erfolg sieht so aus: {"status":"ok","recorded":true}. recorded: false ist ebenfalls ein Erfolg: Die Einsendung war ein Duplikat, oder eine Anti-Bot-Heuristik hat angeschlagen. Zeigen Sie in beiden Fällen denselben Dank: Ein Skript soll nicht erfahren, welche Regel es erwischt hat, und wer nach einem Timeout erneut sendet, soll keinen Fehler für eine Nachricht sehen, die wir bereits haben.

HTTPcodeWann
400validation_errorkein Schlüssel, kein Thema, ein Thema, das das Widget nicht anbietet, ein leerer Kommentar, ein fehlerhafter Body
403origin_not_allowedder Origin der Seite steht nicht auf der Allowlist des Widgets
404not_foundunbekannter Schlüssel oder ein deaktiviertes Widget: dieselbe Antwort, damit ein öffentlicher Schlüssel nicht ausloten kann, welche Projekte existieren
429rate_limited60/Stunde pro Schlüssel, 10/Stunde pro IP; enthält Retry-After
401source_token_invalidnur serverseitiger Weg: falsches Quell-Token
500internal_errorour fault

6. Themen, Arten und Status

Ein Thema besteht aus id und label. Die id ist ein Slug, weil sie in jeder Zeile gespeichert wird und im Panel zum Filterwert wird; das Label formuliert der Inhaber selbst. Ein Widget ohne konfigurierte Themen bietet die Standardthemen an: bug, idea, question, other.

Die Farbe des Dialogs ist eine von sechs Vorgaben, die mit den gehosteten Seiten geteilt werden: amber (Standard), teal, indigo, violet, rose, slate. Bewusst eine gemeinsame Liste: Widget und gehostete Seiten desselben Inhabers sollen gleich aussehen, und eine zweite Palette würde von der ersten abdriften.

Gespeicherte Zeilen haben eine Art: uninstall, rate_us oder widget. Die Art ist ein TAG, keine eigene Pipeline: Panel-Block, Benachrichtigungen und Aufbewahrung sind gemeinsam. Der Bearbeitungsstatus des Inhabers ist new, read oder spam; als Spam markieren nimmt eine Zeile aus der Arbeitsliste und aus den Benachrichtigungen, ohne zu löschen, was jemand geschrieben hat, und lässt sich rückgängig machen.

7. Der Missbrauchsschutz liegt auf dem Server

Weil der Schlüssel öffentlich ist, wäre eine Prüfung im Browser nur ein Rat, keine Regel. Deshalb prüft der Server: die Origin-Allowlist des Widgets (leer heißt jeder Origin, denn ein Kunde kann eine Website über ein Dutzend Subdomains ausliefern), zwei unabhängige Ratenlimits (pro Schlüssel und pro IP), ein Honeypot-Feld und eine Mindestverweildauer sowie Deduplizierung über (widget_id, event_id) in der Datenbank statt einer Vorabprüfung, weil zwei gleichzeitige Wiederholungen beide ein SELECT bestehen würden.

Beide Limiter sind fail-open: Fällt unser Redis aus, erreicht Sie das Feedback trotzdem. Für einen Endpunkt, der einen Absatz schreibt, ist das das kleinere Übel. Ein externes Captcha fügen wir nicht hinzu, es würde Ihre CSP und die Privatsphäre Ihrer Besucher brechen.

8. Der maschinenlesbare Vertrag

Die formale Beschreibung beider Annahme-Endpunkte, des Konfigurationsabrufs, der Enums und der Fehlercodes ist die OpenAPI-3.1-Datei. Sie trägt dieselbe Vertragsversion (1.0.0).

↓ OpenAPI 3.1 (YAML) herunterladen /feedback-openapi.yaml