954a5102ac
Zweite Runde Kundenrückmeldung: - Range-Ergebnisse: Das Diagramm behält die komplette lineare Skala (rangeMin..rangeMax), aber die Werte-Liste/Tabelle zeigt nur noch die tatsächlich beantworteten Werte. Sonst würde eine große Skala (z. B. Alter 1-100, Schrittweite 1) die Ergebnisseite mit hunderten Nullzeilen fluten. Neues Feld distributionRows für die Liste; distribution bleibt fürs Diagramm. - Große Skalen: X-Achsenbeschriftung wird ausgedünnt (Chart.js autoSkip/ maxTicksLimit, SVG jede n-te Beschriftung), Punkt-Marker verkleinert bzw. ab >40 Punkten weggelassen. Auch die Y-Ticks im PDF-SVG werden gedeckelt. - PDF-Range-Tabelle ohne Farb-Swatch-Spalte (nur Wert/Anzahl/Anteil), da die Kopplung an ein Vollskalen-Diagramm nicht mehr sinnvoll ist. - Aktionslinks in der Frontend-Liste: Öffentliche Ansicht, Entwurfs-Ansicht und Ergebnisse anzeigen öffnen wieder im neuen Fenster (target=_blank); nur Bearbeiten bleibt im selben Tab. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
526 lines
22 KiB
Markdown
526 lines
22 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`
|
||
- `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
|
||
|
||
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 1–100 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` |