Files
survey-bundle/AI_HANDOVER.md
T
admin.juergen 4fe142422a Warn on leaving the editor with unsaved changes
Ergänzt einen beforeunload-Handler im Frontend-Editor: Beim Verlassen der
Seite (Link, Zurück, Tab schließen) wird gewarnt, sobald mindestens ein
Editor-Formular ungespeicherte Änderungen hat. Der Handler koppelt an die
bestehende Dirty-Erkennung (data-survey-dirty-form) und wird nur
registriert, wenn solche Formulare existieren – also nur im Editor, nicht
in Liste/Reader/Ergebnissen.

Ein bewusstes Absenden (Speichern oder Aktion) setzt über einen globalen
submit-Listener ein Flag, sodass der normale Speicher-Flow nicht warnt.

Bewusst kein Auto-Save (getrennte Formulare mit eigenen CSRF-Tokens,
Struktur-Sperre nach Teilnahmen/Veröffentlichung); Dirty-Hinweis plus
beforeunload sind der risikoarme Kompromiss.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 20:24:09 +02:00

23 KiB
Raw Blame History

Survey Bundle AI Handover

Diese Datei beschreibt den aktuell gewünschten und umgesetzten Stand des Bundles. Ziel ist, dass ein KI-Modell oder ein neuer Bearbeiter die Logik, die Zustände und die wichtigsten Einstiegspunkte schnell versteht und darauf weiterarbeiten kann.

Zweck des Bundles

Das Bundle stellt ein Contao-Umfragesystem bereit mit:

  • Frontend-Liste für Redakteure
  • Frontend-Frageneditor
  • Öffentlicher Umfrageansicht über Alias-Link
  • Ergebnisseite im Frontend
  • Excel-Export der Ergebnisse
  • PDF-Export der Ergebnisse über Gotenberg
  • Backend-Verwaltung in Contao-DCA-Listen und Editmasken

Zentrale Zustandsfelder

Die Umfrage arbeitet mit drei relevanten Zuständen in tl_survey:

  • published

    • Fachlich: Die Umfrage wurde veröffentlicht.
    • Frontend: Ab Veröffentlichung darf der Redakteur im Frontend weder Fragen noch Metadaten bearbeiten.
    • Backend: Reversibel erlaubt. Der Admin darf den Status im Backend ändern.
  • isActive

    • Fachlich: Öffentliche Sichtbarkeit an/aus.
    • Gilt unabhängig vom Veröffentlichungsstatus als technischer Sichtbarkeitszustand.
    • Der öffentliche Reader liefert nur Umfragen aus, die published = 1 und isActive = 1 haben.
  • isLocked

    • Fachlich: Struktur wurde bereits benutzt oder veröffentlicht.
    • Wird automatisch gesetzt, wenn die erste Antwort gespeichert wird.
    • Wird beim Veröffentlichen ebenfalls gesetzt.
    • Im Backend gibt es bewusst keine harte Sperre mehr. Das Feld dient vor allem der internen Logik und Historie.

Gewollte Produktentscheidung

  • Frontend ist streng:

    • Keine Fragenbearbeitung nach Veröffentlichung
    • Keine Metadatenbearbeitung nach Veröffentlichung
    • Keine Fragenbearbeitung nach ersten Teilnahmen
  • Die Frontend-Sperre für veröffentlichte Umfragen soll bewusst nicht tief im System verankert sein.

    • Für Redakteure genügt das Ausblenden bzw. Deaktivieren der relevanten Buttons und Formulare im Frontend.
    • Es ist ausdrücklich keine zusätzliche harte Systembarriere gewünscht, solange die Redakteursoberfläche den Bearbeitungspfad sauber schließt.
  • Backend ist bewusst toleranter:

    • Ein einzelner Admin darf im Notfall weiter arbeiten
    • Statt harter Sperre gibt es nur einen Warnhinweis in der Liste bei veröffentlichten Umfragen
    • published ist im Backend editierbar
    • isActive ist im Backend per Contao-Toggle schaltbar
  • Bewusster Trade-off zwischen Frontend und Backend:

    • Ein veröffentlichter Survey soll für Frontend-Redakteure praktisch nicht mehr bearbeitbar sein.
    • Im Backend darf der Admin trotz Veröffentlichung weiterhin Änderungen vornehmen, zum Beispiel für Rechtschreibfehler oder kleine Korrekturen.
    • Dadurch bleibt bewusst das Risiko bestehen, dass der Admin auch Fragen oder Strukturen ändert, obwohl bereits Antworten vorliegen.
    • Mögliche Folgen sind verwässerte oder fachlich falsche Ergebnisseiten sowie Inkonsistenzen, wenn bestehende Antworten nicht mehr sauber zur später geänderten Struktur passen.
    • Dieses Risiko wird bewusst akzeptiert und organisatorisch über Briefing/Disziplin des Admins bzw. der zuständigen Redakteure abgefangen, nicht über eine harte technische Sperre im Backend.

Diese Entscheidung ist absichtlich so getroffen und kein Bug.

Datenmodell und wichtige Tabellen

  • tl_survey
    • Umfrage-Stammdaten und Statusfelder
    • Enthält zusätzlich die backend-only gepflegte internalNote
  • tl_survey_content
    • Fragen der Umfrage
  • tl_survey_condition
    • Generische Sprungregeln
  • tl_survey_editor
    • Zugewiesene Frontend-Redakteure
  • tl_survey_submission
    • Umfrage-Durchläufe
  • tl_survey_answer
    • Gespeicherte Antworten inklusive Snapshot-Feldern zur Ergebnisstabilität

Wichtige Snapshot-Felder in tl_survey_answer:

  • questionType
  • questionLabel
  • questionDescription
  • questionSorting

Diese Felder sorgen dafür, dass Ergebnisse auch dann stabil bleiben, wenn Fragen später im Backend verändert oder gelöscht wurden.

Frontend-Module und Controller

1. Redakteursliste

Controller:

  • src/Controller/FrontendModule/MemberSurveyListController.php

Template:

  • contao/templates/frontend/member_survey_list.html.twig

Zweck:

  • Zeigt alle dem eingeloggten Frontend-Mitglied zugewiesenen Umfragen
  • Sortierung ist bewusst fest auf Titel ASC
  • Hier liegen die Redakteursaktionen zur Veröffentlichung und Aktivierung

Aktuelle Button- und Sichtbarkeitslogik pro Umfrage:

  • Bearbeiten
    • Nur klickbar, solange published = 0
    • Nach Veröffentlichung disabled
  • Öffentliche Ansicht
    • Nur sichtbar, wenn published = 1
  • Link kopieren
    • Nur sichtbar, wenn published = 1
    • Kopiert die absolute öffentliche Reader-URL (copyUrl, erzeugt mit UrlGeneratorInterface::ABSOLUTE_URL) über den data-copy-text-Handler in _survey_assets.html.twig.
  • Entwurfs-Ansicht
    • Nur sichtbar, wenn published = 0
  • Ergebnisse anzeigen
    • Immer verfügbar, sofern Results-Seite konfiguriert ist
  • Tab-Verhalten (bewusste Produktentscheidung nach Kundenrückmeldung):
    • Bearbeiten öffnet im selben Tab (eigentlicher Arbeitsschritt).
    • Öffentliche Ansicht, Entwurfs-Ansicht und Ergebnisse anzeigen öffnen im neuen Fenster (target="_blank"), damit die Editor-/Listenansicht erhalten bleibt.
  • Umfrage veröffentlichen
    • Eigene Aktion in der Liste
    • Nach Veröffentlichung disabled und textlich als veröffentlicht markiert
  • Duplizieren
    • Legt eine Kopie der Umfrage für den Redakteur an
    • Titelvergabe ist fortlaufend: Titel - Kopie, danach Titel - Kopie 2, Titel - Kopie 3 usw.
    • Bestehende - Kopie-Suffixe werden fachlich normalisiert, damit keine Titel wie ... - Kopie - Kopie mehr neu entstehen
    • Wichtig: Die Titel-Kollisionsprüfung (SurveyEditorService::buildDuplicateTitle) prüft ohne Ausschluss der Quell-ID gegen titleExists. Sonst würde beim Duplizieren einer bereits ... - Kopie-Umfrage erneut derselbe Titel vergeben statt ... - Kopie 2 (früherer Bug).
  • Aktiv-Umschalter (grauer/grüner Punkt mit Textlabel „Aktiv"/„Deaktiviert")
    • Schaltet isActive
    • Ist bewusst kein Auge mehr
    • Das Textlabel wurde ergänzt, weil der reine Punkt ohne Beschriftung für den Kunden unklar war (survey-visibility-toggle in _survey_assets.html.twig).
    • Bei isActive = 0 ist der öffentliche Reader-Link deaktiviert: SurveyRepository::findByPublicAlias verlangt published = 1 UND isActive = 1, sonst liefert der Reader die Leer-/Hinweisseite.

Wichtiger technischer Punkt (CSRF):

  • Jedes Frontend-Aktionsformular (Liste und Editor) sendet bewusst zwei Tokens:
    • REQUEST_TOKEN ({{ contao.request_token }}) nötig für Contaos globalen Frontend-POST-Gate; fehlt er, lehnt Contao den POST schon vor dem Controller mit HTTP 400 ab.
    • _token ({{ csrf_token('<aktion>-' ~ id) }}) wird im Controller mit isCsrfTokenValid('<aktion>-'.$id, $token) geprüft (session-basierter Symfony-Token).
  • Beide sind erforderlich. Frühere Stände hatten nur einen davon das führte zu „Ungültiger CSRF-Token" (500) bzw. Bad Request (400). Der Listen-Controller spiegelt jetzt exakt die Token-Mechanik des Editors.
  • Der Contao-REQUEST_TOKEN allein reicht nicht als Controller-Prüfung: Er ist cookie-gebunden und bei anonymen/fragmentierten Frontend-Requests nicht stabil (Contao setzt das CSRF-Cookie dort teils gar nicht). Deshalb die zusätzliche session-basierte _token-Prüfung.

2. Frontend-Editor

Controller:

  • src/Controller/FrontendModule/MemberSurveyEditController.php

Template:

  • contao/templates/frontend/member_survey_edit.html.twig

Zweck:

  • Anlegen neuer Umfragen
  • Bearbeiten der Metadaten vor Veröffentlichung
  • Bearbeiten der Fragenstruktur

Aktueller Aufbau:

  • Bei neuer Umfrage:
    • Titel und Beschreibung
  • Bei bestehender, nicht veröffentlichter Umfrage:
    • Metadatenformular oberhalb des Frageneditors
    • Frage-für-Frage-Editor im Akkordeon
    • Neue Frage anlegen
    • Sprungregelübersicht rechts/unten je nach Breakpoint
  • Bei veröffentlichter Umfrage oder bei isLocked = 1:
    • Fragen im Frontend nicht mehr änderbar
    • Metadaten im Frontend ebenfalls nicht mehr bearbeitbar

Ungespeicherte Änderungen (bewusst kein Auto-Save):

  • Jedes Editor-Formular (data-survey-dirty-form: Metadaten, jede Frage, neue Frage) trackt clientseitig, ob sich der Inhalt gegenüber dem Ladezustand geändert hat, und blendet den roten „Ungespeicherte Änderungen"-Hinweis ein.
  • Zusätzlich gibt es einen beforeunload-Handler (_survey_assets.html.twig), der beim Verlassen der Seite (Link, Zurück, Tab schließen) warnt, sobald mindestens ein Formular ungespeicherte Änderungen hat.
    • Der Handler wird nur registriert, wenn dirty-getrackte Formulare existieren (also nur im Editor, nicht in Liste/Reader/Ergebnissen).
    • Ein bewusstes Absenden (Speichern oder eine Aktion) setzt ein surveyIsSubmitting-Flag über einen globalen submit-Listener, damit der normale Speicher-Flow nicht warnt.
  • Auto-Save wurde bewusst nicht umgesetzt (getrennte Formulare mit eigenen CSRF-Tokens, Struktur-Sperre nach Teilnahmen/Veröffentlichung). Der Dirty-Hinweis plus die beforeunload-Warnung sind der gewählte, risikoarme Kompromiss.

Wichtige Entscheidung:

  • Die Header-Badges im Fragen-Akkordeon wurden bewusst entfernt.

    • Typ, Pflicht usw. sollen nicht schon im Header gezeigt werden.
    • Die Details sieht man erst nach dem Aufklappen.
  • Die Sprungziel-Dropdowns im Frontend zeigen Positionsnummern der Umfrage (1. ..., 2. ...) statt globaler Datenbank-IDs.

    • Die aktuell bearbeitete Frage wird dort nicht als eigenes Sprungziel angeboten.

3. Öffentliche Umfrageansicht

Controller:

  • src/Controller/FrontendModule/ShowSurveyController.php

Services:

  • src/Service/SurveyFlowService.php
  • src/Service/SurveySubmissionService.php

Zweck:

  • Öffentliche Teilnahme an Umfragen
  • Zusätzlich Entwurfsansicht per ?preview=1

Wichtige Regeln:

  • Öffentliche Ansicht findet eine Umfrage nur, wenn:
    • published = 1
    • isActive = 1
  • Entwurfsansicht arbeitet ohne Speicherung
  • Öffentliche Ansicht speichert Antworten und erstellt/führt Submission fort
  • Rückwärtsnavigation ist implementiert
  • Nach Abschluss zeigt der gleiche Browser-Token für eine kurze Cooldown-Zeit (RESTART_COOLDOWN_SECONDS = 60) die Danke-Seite; danach darf dieselbe Session erneut teilnehmen (SurveySubmissionService::isRestartAllowed).

Saubere Link-URLs (Reader und Ergebnisseite):

  • Die Umfrage wird über den Alias als Pfad-Segment adressiert: /<reader-seite>/<alias> statt ?auto_item=<alias>.
  • URL-Erzeugung: per Route-Platzhalter ['parameters' => '/'.$alias] (Frontend-Liste MemberSurveyListController, Backend SurveyDcaListener::buildSurveyPageUrl), nicht ['auto_item' => $alias].
  • Auslesen im Controller: $this->getContaoAdapter(Input::class)->get('auto_item'). Wichtig: Input::get markiert den Route-Parameter als benutzt sonst wirft Contaos LegacyRouteParametersListener eine 404 wegen „unbenutzter Parameter". Ein reines $request->query->get('auto_item') reicht für Pfad-URLs nicht.

4. Ergebnisseite

Controller:

  • src/Controller/FrontendModule/ShowSurveyResultsController.php

Service:

  • src/Service/SurveyResultsViewService.php

Template:

  • contao/templates/frontend/show_survey_results.html.twig

Zweck:

  • Aggregierte Auswertung pro Frage
  • Anzeige von Anzahl Teilnahmen, Rücklauf und Frageergebnissen

Aktuelle Ergebnislogik:

  • yes_no_maybe
    • Optionsstatistik plus Kreisdiagramm
  • choice
    • Optionsstatistik plus Kreisdiagramm
  • range
    • Minimum, Maximum, Durchschnitt plus Verteilung und Linienchart
    • Diagramm (distribution): deckt die komplette Skala von rangeMin bis rangeMax in rangeStep-Schritten ab (inkl. Werte ohne Antworten), damit die X-Achse linear und vollständig ist. Antworten außerhalb der konfigurierten Grenzen erweitern die Skala. Siehe SurveyResultsViewService::buildRangeScale.
    • Werte-Liste/Tabelle (distributionRows): zeigt bewusst nur die tatsächlich beantworteten Werte (aufsteigend). So bläht sich die Ergebnisseite bei großen Skalen (z. B. Alter 1100 mit Schrittweite 1) nicht mit hunderten Nullzeilen auf. Die vollständige Skala bleibt trotzdem im Diagramm sichtbar. Online-Liste, PDF-Tabelle und die SVG-/Chart.js-Diagramme greifen entsprechend auf distributionRows (Liste) bzw. distribution (Diagramm) zu.
    • Bei großen Skalen werden die X-Achsen-Beschriftungen ausgedünnt (Chart.js autoSkip/maxTicksLimit, SVG jede n-te Beschriftung) und die Punkt-Marker verkleinert bzw. ab >40 Punkten weggelassen. Die PDF-Range-Tabelle hat keine Farb-Swatch-Spalte mehr (nur Wert/Anzahl/Anteil), weil die Kopplung an ein Vollskalen-Diagramm nicht mehr sinnvoll ist.
  • text
    • Kein Pie-Chart
    • Gruppierte Freitextantworten: jede unterschiedliche Antwort einmal mit exakter Häufigkeit (responseSummary, häufigste zuerst, kein Top-5-Limit). Prozentangaben und die frühere Doppel-Auflistung wurden bewusst entfernt.

Pro Frage werden statt einer reinen Prozent-Rücklaufquote absolute Zahlen ausgewiesen:

  • totalAnswers und completedSubmissionCount als „X von Y beantwortet".
  • skippedCount (= completedSubmissionCount - totalAnswers) als „Z übersprungen", nur wenn > 0. So sind per Sprungregel übersprungene Fragen sichtbar, statt überall die volle Teilnehmerzahl zu zeigen.

Reihenfolge:

  • Die Frageergebnisse werden vor dem Finalisieren nach _sorting sortiert. Wichtig: finalizeQuestionResult entfernt die internen _sorting-Werte würde man erst danach sortieren (früherer Bug), fiele die Reihenfolge auf den alphabetischen Fallback zurück. Online-Ansicht, PDF und Excel folgen dadurch derselben Frage-Sortierung.

Wichtig:

  • Die Ergebnisse werden aus den Antwort-Snapshots aufgebaut, nicht nur aus den aktuellen Fragen.
  • Dadurch bleiben historische Ergebnisse stabil.

Sprunglogik

Relevante Services/Repos:

  • src/Service/SurveyFlowService.php
  • src/Repository/SurveyConditionRepository.php
  • src/Controller/FrontendModule/MemberSurveyEditController.php

Reihenfolge der Navigation:

  1. Direkter Ja/Nein-Sprung über jumpOnYes / jumpOnNo
  2. Generische Bedingung aus tl_survey_condition
  3. Nächste Frage nach Sortierung

Wichtiger Detailpunkt:

  • In der Sprungregelübersicht im Frontend-Editor werden bewusst die Positionsnummern innerhalb der Umfrage angezeigt, nicht die globalen Datenbank-IDs der Fragen.
  • Gleiches gilt für die Sprungziel-Dropdowns in Backend und Frontend.

Wichtige technische Eigenschaft:

  • jumpOnYes, jumpOnNo und generische Bedingungen referenzieren Ziel-Fragen intern immer über die Frage-ID, nicht über die Position.
  • Dadurch bleiben Sprünge bei einer reinen Umordnung der Fragen fachlich stabil an dieselbe Frage gebunden.
  • Wenn eine Ziel-Frage an eine andere Position verschoben wird, zeigt die Oberfläche danach automatisch die neue Positionsnummer an.

Excel-Export

Controller:

  • src/Controller/SurveyResultsExportController.php

Service:

  • src/Service/SurveyResultsExportService.php

Bibliothek:

  • phpoffice/phpspreadsheet

Zweck:

  • Export aller abgeschlossenen Teilnahmen in eine XLSX-Datei

Aktuelle Spaltenlogik:

  • Ja/Nein/Vielleicht:
    • pro Antwortoption eigene Spalte
  • Choice:
    • pro Antwortoption eigene Spalte
  • Range:
    • eine Wertespalte
  • Text:
    • eine Textspalte

Wichtige Eigenschaft:

  • Die Spalten orientieren sich an den aktuell vorhandenen Fragen im Survey.
  • Die Zeilen enthalten nur abgeschlossene Submissions.
  • Über den Antwortspalten steht eine eigene Fragetext-Zeile (F1: <Fragetext>, F2: ...). Je Frage werden die Zellen dieser Zeile über alle zugehörigen Antwortspalten zusammengeführt (mergeCells). Zuvor fehlte der Fragetext im Excel komplett der Kunde sah nur F1 ja, F1 nein usw. Reihenfolge: Titel (Zeile 1), Fragetexte (Zeile 2), Spaltenköpfe (Zeile 3), Daten ab Zeile 4; Freeze-Pane auf A4.
  • Diagramme gibt es im Excel bewusst nicht (dafür ist der PDF-Export da).

PDF-Export

Controller:

  • src/Controller/SurveyResultsExportController.php

Service:

  • src/Service/SurveyResultsPdfService.php

Template:

  • src/Resources/views/pdf/survey_results.html.twig

Externe Abhängigkeit:

  • Gotenberg über surveyGotenbergUrl in den Contao-Einstellungen

Zweck:

  • Serverseitiger PDF-Export der Ergebnisse

Aktuelle Logik:

  • HTML wird serverseitig mit Twig gerendert
  • Diagramme werden als SVG/Data-URI vorbereitet
  • Gotenberg rendert daraus das PDF
  • Ist keine Gotenberg-URL gesetzt, wird im Frontend kein PDF-Download angeboten

Backend-Aufbau

tl_survey

Dateien:

  • contao/dca/tl_survey.php
  • contao/languages/de/tl_survey.php
  • contao/languages/en/tl_survey.php

Wichtige Listenoperationen:

  • Fragen bearbeiten
  • Umfrage bearbeiten
  • isActive als Contao-Toggle
  • Warnsymbol bei veröffentlichten Umfragen
  • Link kopieren
  • Ergebnisse anzeigen

Aktuelle Listen- und Filterlogik:

  • Die mehrspaltige Umfragenliste zeigt aktuell:
    • Titel
    • Zugewiesene Benutzer
    • Vorlage
    • Interne Notiz
  • Kategorien wurden bewusst aus der mehrspaltigen Liste und aus der rechten Filterspalte entfernt.
  • Die Spalte Zugewiesene Benutzer wird in der Listenmetadatenlogik gekürzt:
    • maximal 3 Namen direkt sichtbar
    • danach Zusatz wie ... und X weitere
  • internalNote
    • backend-only Feld in tl_survey
    • nur im Backend bearbeitbar
    • in der mehrspaltigen Liste sichtbar
    • bei Duplikaten wird der Wert mitkopiert
  • In der rechten Suchspalte ist Interne Notiz suchbar.
  • ID wurde für die Umfragenliste bewusst aus dem Suchfeld entfernt.
    • Das geschieht über einen kleinen backend-spezifischen JS-Workaround, weil Contao id im Core für DC_Table hart ergänzt.

Aktuelle Backend-Entscheidung:

  • Das Warnsymbol genügt als Hinweis bei veröffentlichten Umfragen
  • Es gibt bewusst keine harte Sperre für Fragen im Backend

Child-Tabellen

  • tl_survey_content
  • tl_survey_condition
  • tl_survey_editor

Hinweis:

  • isLocked wird in den Child-Headerfeldern nicht mehr angezeigt, weil der Backend-Lock bewusst keine führende Benutzerfunktion mehr ist.
  • In tl_survey_content ist der Fragenlisten-Header zusätzlich reduziert:
    • nur noch Titel und Veröffentlicht
    • kein öffentlicher Link-Schlüssel mehr
    • die rechte Header-Leiste mit Aktionen ist im Normalzustand ausgeblendet
    • im aktiven Verschiebe-/Clipboard-Modus wird sie wieder eingeblendet, damit Neu oben bzw. die Einfügepositionen erreichbar bleiben

Fragenliste tl_survey_content:

  • Direkt sichtbare Primäraktion pro Frage:
    • Bearbeiten-Stift
  • Verschieben:
    • erfolgt im Backend über den normalen Contao-Paste-/Move-Flow
    • die Aktion Verschieben liegt bewusst nur unter den drei Punkten
    • dort wird der Contao-Pfeil mover.svg verwendet, nicht die blaue Schere
    • nach Aktivierung des Clipboard-Zustands erscheinen die üblichen Einfügeziele wie Nach dem Element ... einfügen

Systemeinstellungen

Datei:

  • contao/dca/tl_settings.php

Wichtige Settings:

  • surveyReaderPage
  • surveyResultsPage
  • surveyGotenbergUrl

Aktuelle Produktregeln in Kurzform

  • Frontend-Liste:
    • Titel alphabetisch
    • Veröffentlichung und Aktivierung in der Liste
  • Frontend-Editor:
    • Metadaten nur vor Veröffentlichung
    • Fragenbearbeitung nur solange nicht veröffentlicht und keine Teilnahmen vorliegen
  • Öffentliche Ansicht:
    • Nur published = 1 und isActive = 1
  • Backend:
    • published reversibel erlaubt
    • isActive per Standard-Contao-Toggle
    • nur Warnsymbol statt Backend-Sperre
    • Admin darf Fragen auch nach Veröffentlichung oder nach vorhandenen Antworten umsortieren

Wichtige Dateien nach Themengebiet

Frontend-Liste:

  • src/Controller/FrontendModule/MemberSurveyListController.php
  • contao/templates/frontend/member_survey_list.html.twig

Frontend-Editor:

  • src/Controller/FrontendModule/MemberSurveyEditController.php
  • contao/templates/frontend/member_survey_edit.html.twig

Öffentliche Umfrage:

  • src/Controller/FrontendModule/ShowSurveyController.php
  • src/Service/SurveyFlowService.php
  • src/Service/SurveySubmissionService.php

Ergebnisse:

  • src/Controller/FrontendModule/ShowSurveyResultsController.php
  • src/Service/SurveyResultsViewService.php
  • contao/templates/frontend/show_survey_results.html.twig

Exporte:

  • src/Controller/SurveyResultsExportController.php
  • src/Service/SurveyResultsExportService.php
  • src/Service/SurveyResultsPdfService.php

Backend:

  • contao/dca/tl_survey.php
  • src/EventListener/SurveyDcaListener.php

Technische Validierung, die in diesem Projekt gut funktioniert

  • php -l auf die geänderten PHP-Dateien
  • ddev exec php bin/console lint:yaml ...
  • ddev exec php bin/console cache:clear

Offene technische Punkte / Deployment-Hinweise

  • Neue DB-Spalte in tl_survey:

    • internalNote
    • Typ aktuell: varchar(255) NOT NULL default ''
    • Für andere Umgebungen muss diese Spalte per Migration/SQL vorhanden sein, sonst fehlen Backend-Feld, Listenanzeige und Suchfunktion fachlich bzw. führen zu Inkonsistenzen.
  • Nach Änderungen an DCA, Backend-CSS oder Backend-JS ist in dieser Installation typischerweise nötig:

    • php vendor/bin/contao-console assets:install public --symlink --relative
    • php vendor/bin/contao-console cache:clear --env=prod
  • Es gibt aktuell zwei bewusst eingebaute backend-spezifische UI-Workarounds über Bundle-Assets:

    • In der Umfragenliste wird ID aus dem Suchfeld per JS entfernt, weil Contao das Feld im Core von DC_Table hart ergänzt.
    • In der Fragenliste (table=tl_survey_content) wird die rechte Parent-Header-Leiste per CSS/JS im Normalzustand ausgeblendet und nur im aktiven Clipboard-/Verschiebe-Modus wieder eingeblendet.
  • Lokale DDEV-Besonderheit, die bei Fehleranalyse relevant sein kann:

    • Das Bundle läuft hier als Path-Repository/Symlink.
    • Wenn Backend-Übersetzungen oder Assets trotz korrektem Code unerwartet fehlen, zuerst Bundle-Pfad, veröffentlichte Assets und Prod-Cache prüfen.

Bekannte bewusste Trade-offs

  • Backend kann veröffentlichte Umfragen technisch weiterhin verändern.
    • Das ist bewusst akzeptiert, weil nur ein Admin arbeitet.
  • isLocked bleibt als internes Logikfeld bestehen, obwohl der Backend-Lock nicht mehr durchgesetzt wird.
  • PDF-Export hängt von Gotenberg ab und ist absichtlich optional.
  • Eine reine Umordnung von Fragen ist für Sprungziele logisch unkritisch, weil Sprünge an Frage-IDs hängen.
  • Ergebnisse vorhandener, weiterhin existierender Fragen folgen bei der Anzeige jedoch der aktuellen Sortierung der Frage.
    • Historische Antwort-Snapshots speichern zwar questionSorting, die Ergebnisansicht sortiert vorhandene Fragen aber primär nach der aktuellen Frage-Sortierung.
    • Das ist im toleranten Backend-Modell ein bewusst akzeptierter Side-Effect.

Empfohlene Einstiegspunkte für künftige Änderungen

  • Status-/Sichtbarkeitslogik: SurveyRepository, SurveyEditorService, MemberSurveyListController
  • Fragerouting: SurveyFlowService, SurveyConditionRepository
  • Ergebnisdarstellung: SurveyResultsViewService
  • Exportlogik: SurveyResultsExportService, SurveyResultsPdfService
  • Backend-Operationen und DCA-Verhalten: tl_survey.php, SurveyDcaListener