Vom Fragebogen zum fertigen Report

Ein Restaurant-Feedback-Dashboard mit dem LimeSurvey Report-Plugin

Im ersten Artikel habe ich gezeigt was das Report-Plugin produziert. Dieser Artikel zeigt den kompletten Weg dorthin – von der Umfrage bis zum fertigen Report, Schritt für Schritt.

Als Beispiel dient eine Restaurant-Feedback-Umfrage. Ein alltagsnahes Szenario: Gäste bewerten ihren Besuch, das Restaurant will verstehen was gut läuft und wo Verbesserungsbedarf besteht.


Die Umfrage

Die Umfrage besteht aus neun Fragen – kompakt, aber ausreichend für einen differenzierten Report.

Code Typ Frage
q1 L – Radio List Wie bewerten Sie Ihren Restaurantbesuch insgesamt? (1–6)
nps L – Radio List Wie wahrscheinlich würden Sie uns weiterempfehlen? (0–10)
matrix F – Array Wie bewerten Sie die folgenden Aspekte? (9 Subfragen, Skala 1–6)
anlass L – Radio List Aus welchem Anlass waren Sie bei uns?
besuchszeit L – Radio List Wann haben Sie uns besucht?
frequency L – Radio List Wie häufig besuchen Sie unser Restaurant?
strengths M – Multiple Choice Welche Punkte sind Ihnen besonders positiv aufgefallen?
potentials O – List with Comment Wo sehen Sie Verbesserungsbedarf?
freetext T – Long Text Möchten Sie uns noch etwas mitteilen?

Wichtig dabei: die Fragen-Codesq1, nps, matrix und so weiter. Diese Codes vergebe ich beim Anlegen der Fragen in LimeSurvey bewusst und sprechend. Sie sind der Ankerpunkt für das Mapping im nächsten Schritt.


Das Ziel

Bevor ich das Mapping anlege oder eine Zeile Template-Code schreibe, definiere ich das Ziel: Wie soll der fertige Report aussehen?

Für die Restaurant-Feedback-Umfrage will ich sechs Seiten:

Das ist kein Zufallsprodukt – es ist eine bewusste Entscheidung. Nicht jede Frage braucht eine eigene Seite, und nicht jede Frage muss überall auftauchen.


Konzepte definieren

Das Template arbeitet nicht mit Fragen-Codes wie q1 oder matrix – es arbeitet mit Konzepten. Konzepte sind abstrakte Namen die beschreiben was eine Information bedeutet, nicht wo sie in der Datenbank liegt.

Für diesen Report definiere ich neun Konzepte:

Konzept Bedeutung
overall_satisfaction Gesamtbewertung des Besuchs
recommendation Weiterempfehlungsbereitschaft (NPS)
aspects Bewertung einzelner Aspekte (Matrix)
strengths Genannte Stärken (Multiple Choice)
potentials Verbesserungsbedarf (mit Kommentar)
visit_frequency Besuchshäufigkeit
occasion Besuchsanlass
visit_time Besuchszeit
freetext Offene Rückmeldungen

Das Template kennt nur diese Konzeptnamen. Welche konkrete Frage dahintersteckt, weiß das Template nicht – das ist Aufgabe des Mappings.


Mapping anlegen

Das Mapping verbindet Konzepte und Fragen. Die Admin-Oberfläche zeigt für jedes Konzept ein Dropdown mit den kompatiblen Fragen der gewählten Umfrage:

Mapping-Oberfläche – neun Konzept-Slots mit zugeordneten Fragen aus der Restaurant-Feedback-Umfrage

Das Plugin filtert die Frageauswahl automatisch nach kompatiblen Fragetypen. aspects akzeptiert nur Typ F – es erscheinen also nur Matrix-Fragen im Dropdown. recommendation akzeptiert nur L und ! – weil der NPS-Algorithmus numerische Codes 0–10 voraussetzt.

Nach dem Speichern ist das Mapping aktiv. Ab jetzt weiß das Plugin: wenn das Template overall_satisfaction anfragt, soll es die Daten aus q1 liefern.


Den Report definieren

Der vollständige Report umfasst sechs Seiten und knapp 200 Zeilen PHP. Dabei wird nicht beschrieben wie Daten geladen oder Diagramme gerendert werden. Das Template definiert ausschließlich Struktur und Semantik des Reports. Ich zeige die drei aussagekräftigsten Ausschnitte.

Das Dashboard – acht KPI-Karten in zwei Reihen:

$report->page('dashboard', function (PageBuilder $page): void {
    $page->title('Dashboard');

    $page->section(function (SectionBuilder $section): void {
        $section->kpi('response-count')
            ->title('Befragte gesamt')->icon('👥')->color('primary')->col(3);

        // Skala 1–6 (1 = Sehr gut) → invertProgress: niedriger Wert = besserer Balken
        $section->kpi('sc-mean', 'overall_satisfaction')
            ->title('Ø Gesamtbewertung')->icon('⭐')->color('success')
            ->invertProgress()->scaleMax(6)->col(3);

        // Farbe wird zur Laufzeit automatisch gesetzt (grün/gelb/rot je nach Score)
        $section->kpi('nps', 'recommendation')
            ->title('Net Promoter Score')->icon('📊')->color('info')->col(3);

        $section->kpi('completion-rate')
            ->title('Abschlussquote')->icon('✅')->color('secondary')
            ->withProgressBar()->col(3);
    });

    $page->section(function (SectionBuilder $section): void {
        $section->kpi('best-rated-aspect', 'aspects')
            ->title('Bester Aspekt')->icon('🏆')->color('success')->col(3);

        $section->kpi('worst-rated-aspect', 'aspects')
            ->title('Schwächster Aspekt')->icon('📉')->color('danger')->col(3);

        $section->kpi('mc-top-answer', 'strengths')
            ->title('Meist genannte Stärke')->icon('💪')->color('success')->col(3);

        $section->kpi('top-answer', 'potentials')
            ->title('Häufigster Kritikpunkt')->icon('🔧')->color('warning')->col(3);
    });
});

invertProgress() und scaleMax(6) tauchen mehrfach auf – das ist die Schulnoten-Logik: auf einer Skala von 1–6 ist ein niedriger Wert besser, der Fortschrittsbalken muss also invertiert werden damit er visuell korrekt ist.

Die Heatmap – Bewertungsverteilung je Aspekt:

$report->page('aspects', function (PageBuilder $page): void {
    $page->title('Aspekte des Besuchs');

    $page->section(function (SectionBuilder $section): void {
        $section->kpi('best-rated-aspect', 'aspects')
            ->title('Beste Kategorie')->icon('🏆')->color('success')->col(3);

        $section->kpi('worst-rated-aspect', 'aspects')
            ->title('Schwächste Kategorie')->icon('📉')->color('danger')->col(3);

        $section->kpi('mean-score', 'aspects')
            ->title('Ø Aspect Score')->icon('📊')->color('info')
            ->invertProgress()->scaleMax(6)->col(3);

        // Anteil kritischer Bewertungen (Noten 5+6) — letzte 2 Antwortoptionen
        $section->kpi('matrix-bottom-box', 'aspects')
            ->title('Kritische Bewertungen')->icon('⚠️')->color('warning')
            ->boxes(2)->col(3);
    });

    $page->section(function (SectionBuilder $section): void {
        $section->matrixHeatmap('aspects')
            ->title('Bewertungsverteilung je Aspekt')->fullWidth();
    });
});

Stärken & Verbesserungspotenziale – zwei Charts mit semantischer Farbwelt:

$report->page('feedback', function (PageBuilder $page): void {
    $page->title('Stärken & Verbesserungspotenziale');

    // …KPI-Zeile…

    // Stärken: grüne Farbwelt
    $page->section(function (SectionBuilder $section): void {
        $section->multipleChoiceFrequency('strengths')
            ->title('Was ist Ihnen besonders positiv aufgefallen?')
            ->asChart()->percentage()->barColor('#59a14f')->fullWidth();
    });

    // Verbesserungspotenziale: orange/warning Farbwelt
    $page->section(function (SectionBuilder $section): void {
        $section->singleChoiceFrequency('potentials')
            ->title('Wo sehen Sie Verbesserungsbedarf?')
            ->asChart('bar')->percentage()->barColor('#FF7043')->fullWidth();
    });
});

Die Farbwahl ist bewusst – grün für Stärken, orange für Verbesserungspotenziale. Ein einziger Parameter pro Chart.


Das Ergebnis

Hier ist was der Report produziert. Alle Screenshots basieren auf demselben Template und demselben Mapping – nicht auf fünf verschiedenen Reports.

Dashboard – acht KPI-Karten, sofort lesbar:

Restaurant Feedback Dashboard – acht KPI-Karten mit Gesamtbewertung, NPS, bestem und schwächstem Aspekt sowie meistgenannter Stärke und Kritikpunkt

Aspekte des Besuchs – Heatmap mit neun Aspekten:

Restaurant Feedback Aspekte – farbkodierte Heatmap mit Bewertungsverteilung, Mittelwert und Fallzahl pro Aspekt

Gesamtbewertung & Weiterempfehlung – Bewertungsverteilung und NPS-Breakdown:

Restaurant Feedback Gesamtbewertung – Balkendiagramm der Bewertungsverteilung und NPS-Segment-Balken mit Promotoren, Passiven und Kritikern

Stärken & Verbesserungspotenziale – was Gäste loben und was sie vermissen:

Restaurant Feedback Stärken – Balkendiagramme für Stärken und Verbesserungspotenziale mit KPI-Karten

Besuchskontext – Gruppenvergleiche nach Häufigkeit und Anlass:

Restaurant Feedback Besuchskontext – Besuchszeit als Balkendiagramm, Gruppenvergleiche als farbige Progressbars


Was wurde nicht programmiert?

Das ist der Teil der mich selbst immer wieder überrascht wenn ich einen neuen Report fertigstelle.

Für diesen Report – sechs Seiten, acht KPI-Karten allein auf dem Dashboard, Heatmap, NPS-Breakdown, Gruppenvergleiche, Freitext-Feed – wurde:

Was tatsächlich geschrieben wurde: knapp 200 Zeilen PHP.

Ein sechsseitiger Report mit Dashboard, Heatmap, NPS-Auswertung, Gruppenvergleichen und Freitext-Feed entstand aus knapp 200 Zeilen PHP.

Das ist die Struktur des Reports in der DSL. Seiten, Sektionen, Darstellungstypen, Konzeptnamen, Farbparameter. Der Rest ist Framework.

Das ist der eigentliche Wert eines Reporting-Frameworks gegenüber einer Eigenentwicklung: nicht dass man weniger kann – sondern dass man sich auf das konzentriert was den Report einzigartig macht, statt jedes Mal dieselbe Infrastruktur neu zu bauen.


Das Report-Plugin, die Dokumentation und Demo-Anfragen: Kontakt