Every stale reset link produced a bare 'Ungültiges Token', which sent
users into a loop of requesting ever more e-mails. The overridden core
messages now explain that only the link from the newest e-mail counts,
the auth message template offers a direct 'Neuen Link anfordern' button,
and the change-password page asks for the 'Aktuelles Passwort' with a
hint covering freshly reset passwords.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Symfony's required default forced an answer to every question no matter
what the mandatory checkbox said. Optional choice questions now offer a
dedicated 'Keine Antwort' option, optional range and text questions a
'Keine Angaben machen' checkbox (preselected for ranges, because a slider
always submits a value); the side that is not chosen gets dimmed but stays
clickable. Mandatory ranges start their value display at '?' and reject
the submit until the slider was actually used, so the browser's midpoint
default no longer leaks into the results.
Empty answers are stored as a deliberate 'no answer', kept out of counts,
averages and charts, and reported separately on the results page and in
the PDF export. Also gives the reader textarea its full width and field
styling, adds grid overflow guards for unbreakable content and styles the
form error box.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Quill 2's getSemanticHTML() serializes every space as U+00A0, turning a
whole paragraph into one unbreakable word that stretched the survey cards
far past the viewport. Normalize to plain spaces when sanitizing (which
also heals existing records on every output) and when the editor writes
the serialized HTML back into the textarea.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a template override for Contao's changePassword module with the
same card, explanatory copy and corporate design as the lost password
module.
The card rules keyed off .mod_lostPassword.block, which does not scale
to a third auth module. Move them to a .survey-auth-module class that
the overrides put on the wrapper themselves, so another auth module
needs one line and no new CSS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Give the lost password module the same centred card as the login,
right-align the reset link, add explanatory copy and a way back to
the login from every dead end Contao routes through mod_message.
Contao only sets a text body on the opt-in mail, so a MessageEvent
listener adds an HTML alternative in the corporate design. It reads
the locale from the fallback root page because mails can go out from
a CLI worker, where kernel.default_locale is "en".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
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>
Behebt die Fehler aus der Kunden-Testrunde (Praktikantin, Juli 2026):
- Ergebnisreihenfolge: Fragen werden vor dem Finalisieren nach _sorting
sortiert. finalizeQuestionResult entfernt _sorting, daher fiel die
bisherige Nachsortierung auf den alphabetischen Fallback zurück. Online,
PDF und Excel folgen jetzt derselben Frage-Sortierung.
- Excel-Export: Eigene Fragetext-Zeile über den Antwortspalten (je Frage
über die zugehörigen Spalten zusammengeführt). Zuvor fehlte der Fragetext.
- Range-Ergebnis: Verteilung deckt die komplette Skala rangeMin..rangeMax in
rangeStep-Schritten ab, damit die X-Achse linear und vollständig ist
(vorher nur tatsächlich vorkommende Werte in gleichen Abständen).
- Teilnahmen/Rücklauf pro Frage als absolute Zahlen ("X von Y beantwortet",
"Z übersprungen") statt reiner Prozent-Rücklaufquote.
- Freitextantworten gruppiert: jede Antwort einmal mit exakter Häufigkeit,
ohne Prozentangaben und ohne Doppel-Auflistung.
- Frontend-Liste: "Link kopieren"-Button (absolute Reader-URL) für
veröffentlichte Umfragen; Aktiv-Umschalter mit Textlabel statt nur Punkt;
Aktionslinks öffnen im selben Tab statt in neuen Tabs.
- Duplizieren: Titel-Kollisionsprüfung ohne Ausschluss der Quell-ID, damit
aus "... - Kopie" korrekt "... - Kopie 2" wird statt eines Dubletten-Titels.
Der internalNote-Fehler beim Anlegen/Duplizieren war ein fehlendes
DB-Schema-Update (Spalte tl_survey.internalNote) und wurde per
contao:migrate auf der Testumgebung nachgezogen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Questions, editor assignments and conditions were inserted without tstamp,
so Contao rendered them with tstamp=0 -> the backend "draft" styling
(opacity .5), making question rows look greyed out despite being published.
- SurveyQuestionRepository::insert()/update() (covers create, edit, duplicate)
- SurveyEditorRepository::insert()
- SurveyConditionRepository::insert()
SurveyRepository already set tstamp. Also widened the assigned-members
checkbox-wizard columns at smaller breakpoints.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The frontend condition create/edit path was never wired (no caller, no UI).
Conditions stay live where used: the SurveyFlowService reads tl_survey_condition
for jumps, the editor shows the read-only overview, and delete still works.
Removed:
- SurveyConditionEditorType (zero references)
- SurveyEditorService::saveCondition() + its SurveyConditionData import
- SurveyConditionData form model
- SurveyConditionRepository::update() (only caller was saveCondition)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CSRF / actions:
- List action forms now send both REQUEST_TOKEN (Contao gate) and _token
(Symfony, validated via isCsrfTokenValid) — mirrors the editor; fixes
the 400/500 "Ungültiger CSRF-Token" on publish/toggle/duplicate/delete
Public reader / URLs:
- Reader & results read auto_item via Input::get (marks the route param used)
so clean path URLs /<page>/<alias> no longer 404
- List controller generates path URLs via ['parameters' => '/'.$alias]
- Allow re-participation in the same session after a 60s cooldown
Review fixes:
- Results: merge answer snapshots by questionId+type (no more split cards on
label edits); seed "Vielleicht" when allowMaybe so screen matches Excel
- Reader: replace generic answer hint with per-option "weiter zu Frage X"
only when a jump is configured; strip HTML tags from survey description
- PDF: render free-text frequency summary; drop duplicate "Minimum" label
- Drag-sort: bundle SortableJS locally, drop the duplicated inline sort CSS/JS
from _survey_assets, throttle the backend MutationObserver
- Backend: move hardcoded tl_survey operation labels to TL_LANG (de+en)
- Remove dead code: SurveyEditorVoter, SurveyPermissionService,
categoryFilter/categorySummary + helpers, orphaned publishSurvey lang key
Reader layout:
- max-width 1000px (other views keep 1400px); back/next buttons fill the
width as equal, card-sized halves; sort handle icon offset tweak
Docs: update AI_HANDOVER (dual-token CSRF, clean URLs) and README
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 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