Files
survey-bundle/AI_HANDOVER.md
T
Jürgen Mummert 1b16675ae9 Add survey question drag-sort and backend assets
- Frontend editor: drag-to-sort questions with dedicated sort assets/JS
- Backend list/search refinements for tl_survey and tl_survey_content
- Repository helpers for survey/question/editor queries
- Translations and AI handover notes update
2026-06-14 09:13:07 +02:00

493 lines
17 KiB
Markdown

# 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`
- `Entwurfs-Ansicht`
- Nur sichtbar, wenn `published = 0`
- `Ergebnisse anzeigen`
- Immer verfügbar, sofern Results-Seite konfiguriert ist
- `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
- Kreis grau/grün
- Schaltet `isActive`
- Ist bewusst kein Auge mehr
Wichtiger technischer Punkt:
- Die Frontend-Listenaktionen arbeiten nur noch mit dem Contao-`REQUEST_TOKEN` plus Berechtigungsprüfung.
- Die zusätzliche Symfony-Aktions-CSRF-Prüfung wurde bewusst entfernt, weil sie in diesem Frontend-Flow zu ungültigen Tokens führte.
### 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
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
### 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
- `text`
- Kein Pie-Chart
- Stattdessen Response-Summary und Liste der Freitextantworten
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.
## 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`