Jede Dokumentationsseite endet mit „War diese Seite hilfreich?“, und die Ebene
tut nichts mit der Antwort: Sie hält sie für die Dauer des Besuchs im eigenen
Zustand der Komponente, sendet ein Ereignis und speichert nichts. Die Komponente
zu umhüllen ist der Weg, auf dem die Antwort bei dir ankommt.

## Schritte

::steps

1. **Umhülle die Komponente der Ebene unter ihrem eigenen Namen.** Nuxt löst
   deine Datei zuerst auf — `app/components/DuxtPageFeedback.vue` in deinem
   Projekt ersetzt also die der Ebene, und der `@duxt`-Alias erreicht das
   Original weiterhin über den Pfad, sodass die Hülle das Markup, die
   Übersetzungen und das Zurücksetzen bei Navigation der Ebene behält:

   ```vue [app/components/DuxtPageFeedback.vue]
   <script setup lang="ts">
   import DuxtPageFeedbackBase from '@duxt/components/DuxtPageFeedback.vue';

   const route = useRoute();

   // Das Ereignis trägt die Antwort und sonst nichts — die Seite, zu der sie
   // gehört, liest du selbst, und `fullPath` ist die, die die Locale-,
   // Repository- und Versionspräfixe behält, unter denen die Antwort tatsächlich
   // gegeben wurde.
   async function onFeedback(helpful: boolean) {
     await $fetch('/api/feedback', {
       method: 'POST',
       body: { path: route.fullPath, helpful }
     });
   }
   </script>

   <template>
     <DuxtPageFeedbackBase @feedback="onFeedback" />
   </template>
   ```

2. **Gib der Antwort einen Ort zum Landen.** Eine eigene Route, damit der
   Browser des Lesers nie mit einem Dritten spricht, den du nicht gewählt hast:

   ```ts [server/api/feedback.post.ts]
   export default defineEventHandler(async (event) => {
     const { path, helpful } = await readBody(event);

     // Dein Speicher, deine Analytik, deine Warteschlange.
     await recordFeedback({ path, helpful });

     return { ok: true };
   });
   ```

   Ein clientseitiger Analytik-Aufruf funktioniert genauso — ersetze das
   `$fetch` in der Hülle durch das, was das SDK deines Anbieters anbietet.

3. **Baue neu und beantworte die Frage einmal**, dann prüfe, ob die Antwort mit
   dem erwarteten Pfad ankam — unter einem Versionspräfix, nicht nur an der
   nackten URL.

::

::callout{type="tip" title="Ein Ziel für alles?"}
Dieselbe Antwort ist auch ein `feedback`-Analytik-Ereignis. Wenn Suchen, Kopien
und Try-it-Anfragen dort landen sollen, wo das Feedback landet, schreibe ein
Callback statt einer Hülle — siehe
[Analytik-Ereignisse senden](/guides/send-analytics-events). Die beiden sind
unabhängig: Das Ereignis und der Slot dieser Komponente funktionieren, ob
`duxt.analytics.track` gesetzt ist oder nicht.
::

## Ein eigenes Bedienelement rendern

Das Ereignis behält die Schaltflächen der Ebene. Um sie zu ersetzen, nimm
stattdessen den Standard-Slot: Er legt denselben Zustand offen, aus dem die
Komponente rendert, sodass das Zurücksetzen bei Navigation und der
„Danke“-Zustand Sache der Ebene bleiben.

```vue [app/components/DuxtPageFeedback.vue]
<script setup lang="ts">
import DuxtPageFeedbackBase from '@duxt/components/DuxtPageFeedback.vue';
</script>

<template>
  <DuxtPageFeedbackBase v-slot="{ answered, answer }">
    <form v-if="answered === undefined" @submit.prevent="answer(true)">
      <label>
        Sag uns, was fehlt
        <textarea name="comment" />
      </label>
      <button type="submit">Senden</button>
    </form>
    <p v-else>Danke.</p>
  </DuxtPageFeedbackBase>
</template>
```

`answer(helpful)` setzt den Zustand und sendet das Ereignis, Slot und Listener
lassen sich also kombinieren: Häng dein Formular an den Slot und behalte den
`@feedback`-Handler aus Schritt 1, um zu liefern, was es gesammelt hat.

::callout{type="warning" title="Zwei Antworten sind nicht zwei Leser"}
Nichts in der Komponente identifiziert einen Besucher, und das bleibt bewusst
so. Wenn du Antworten je Seite zählst, zähle sie als Antworten — ein Browser,
der neu lädt und erneut antwortet, ist eine zweite Antwort und kein zweiter
Leser, und das eine ins andere zu verwandeln ist eine Einwilligungsfrage, die
zuerst deine Datenschutzerklärung beantworten muss.
::

## Warum die Ebene nichts speichert

Ein Dokumentations-Theme, das standardmäßig nach Hause telefoniert, müsste ein
Ziel für die Leser eines anderen aussuchen, und es gibt kein vertretbares: Die
Ebene weiß weder, wo deine Analytik liegt, noch, was deine Datenschutzerklärung
verspricht. Die Frage mit einem Ereignis und ohne Backend auszuliefern hält die
Entscheidung dort, wo sie hingehört — aus demselben Grund werden die
Rechtszeile im Fußbereich und die Repository-Links leer ausgeliefert
([ADR 0005](/adr/0005-ship-the-layer-without-owner-specific-links)).

## Checkliste

- [ ] Die Hülle rendert die Komponente der Ebene, statt sie nachzubauen
- [ ] Die Antwort wird mit dem Pfad gesendet, auf dem sie gegeben wurde,
      Präfixe eingeschlossen
- [ ] Das Ziel gehört dir — eine Route, eine Warteschlange oder ein SDK deiner
      Wahl
- [ ] Nichts in der Nutzlast identifiziert den Leser