The back-to-top button was hidden as long as the consent question was open, on every device - and on a phone the question tends to stay open. Instead of `display:none` it now anchors itself 12px above the bar wherever the bar covers its corner: below 800px for the centred card, at every width for the full-width bar and the corner card. Browsers without anchor positioning keep hiding it there. The bar renders before the button so it can be an anchor, and the reserved bottom padding grows to 320px below 620px, where the bar with its default text is up to 299px tall. The notice itself gets a face. Settings → Einwilligung now carries layout (card, bar, corner), shape (soft, round, square - one setting for the box and its buttons), a heading and four colours, each as #hex or @palette key. `Theme::cssColor()` resolves both, replacing the copy inside the back-to-top code; `Consent::styles()` writes the values as `--kant-consent-*` into the hashed style block. The base layout changes with it: an accent stripe and shield icon, equal-width buttons, a disclosure with a chevron, underlined legal links, a two-column bar on wide screens. Declining stays an outlined button of the same size next to accepting. The archive and the consent page carry the same variables - the archive had no palette at all until now. In the editor, rows with an own value are labelled in orange rather than bold with a dot; the device chips sit 6px apart with the focus ring inside the gap. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
82 KiB
Qualitätsbericht – erster ausführbarer Prototyp
Ergänzung: Elektro Bernhard gemessen, 14.09.2026 (1.12.1)
Lighthouse 13 (scripts/audit.mjs, je drei Läufe Mobil und Desktop, Mediane) gegen den lokalen Produktionsmodus der Referenzwebsite Elektro Bernhard (var/elektro-bernhard.db, Port 8090), vier Adressen: /, /leistungen, /leistungen/notdienst, /kontakt. Ergebnis nach den Korrekturen: Barrierefreiheit, Best Practices, SEO und agentisches Browsing überall 100, Leistung überall 100 bis auf die mobile Startseite mit 99 (LCP 2,1 s durch das Hero-Foto als Hintergrund unter Mobildrosselung; CLS 0, TBT 30 ms). Berichte unter reports/lighthouse-elektro-bernhard-2/; der erste Lauf davor (reports/lighthouse-elektro-bernhard/) zeigte Barrierefreiheit 95–97.
axe (WCAG 2.0/2.1 A+AA und Best-Practice-Regeln, Playwright, 1440 und 390 px) auf sechs Seiten: null Verstöße. Vorher gab es drei echte Befunde, alle behoben: Markennamen #9aa0a6 auf Weiß (2,6:1 → #6b7178, 4,7:1), der rote Link „Kant-IT Solutions“ im dunklen Fuß (3,0:1 → hell), und auf der Leistungsübersicht sprang die Gliederung von H1 auf H3 (jetzt eine H2 vor den Karten). Ein vierter Befund lag im CMS: der Pause-Knopf des Sliders hatte den sichtbaren Text „Pause“, aber den zugänglichen Namen „Automatische Wiedergabe pausieren“ (WCAG 2.5.3); der Name beginnt jetzt mit dem sichtbaren Text. Achtung beim Messen: unmittelbar nach dem Laden meldet axe Kontrastverstöße an Elementen, die gerade eingeblendet werden (halb transparente Zwischenzustände); erst nach dem Durchscrollen und zwei Sekunden Wartezeit sind die Befunde belastbar.
Maschinenlesbar: llms.txt, robots.txt, sitemap.xml werden ausgeliefert, LocalBusiness mit drei sameAs-Profilen auf der Startseite, BreadcrumbList auf Unterseiten, og:image auf allen Inhaltsseiten. Nicht gemessen: Felddaten (LCP/INP/CLS am 75. Perzentil), Screenreader, Firefox/Safari, das tatsächliche Hosting.
Ergänzung: Sichtbare leere Layouts, 14.09.2026 (1.6.2)
30 JavaScript-Tests und 27 PHP-Editor-/Sicherheitstests mit 312 Assertions bestanden. Vollständiger isolierter Chromium-Editortest einschließlich axe ohne Verstöße: direkte Tastatureinfügung in leere Sektionen/Spalten, genaues Drag-and-drop-Ziel und Scrollen am Rand, Spaltenreihenfolge auf Desktop und Mobil, Undo/Redo, Speichern/Neuladen, Veröffentlichung und Konflikte. Die Tests prüfen ausdrücklich, dass die neuen Editorhilfen weder im gespeicherten Blockbaum noch im öffentlichen HTML stehen. Desktop-, Mobil- und Drag-Screenshots visuell geprüft; Bericht unter reports/editor/result.json.
Vergleich mit lokalen Flatsome-3.20.9-Quelldateien, keine laufende WordPress-Referenz geprüft. Kein neuer Lighthouse-Lauf, da der öffentliche Renderer und dessen CSS unverändert sind; die Messung von 1.6.1 ist weiterhin als solche zu lesen. Kein neuer Screenreader-, Firefox-, Safari-, Touchgeräte- oder Felddatennachweis.
Ergänzung: Flexible Editorfläche und Inhaltsbreiten, 14.09.2026 (1.6.1)
npm.cmd test: 30 Modelltests; PHP 8.4.22: 452 Tests / 3476 Assertions. Der vollständige isolierte Playwright-Lauf einschließlich axe, Speichern/Neuladen, Veröffentlichung, Konfliktbehandlung und neuer Panel-/Sektionsprüfungen besteht. Bildschirmbreiten 390/850/1100/1920 px ohne horizontalen Überlauf geprüft. Screenshotprüfung für Desktop, Bildinspektor und Telefon; kein neuer Screenreader-Test.
PHP_BINARY=C:\php84\php.exe, npm.cmd run test:editor -- --audit: Lighthouse 13.4.1, lokaler Symfony-Produktionsmodus mit isolierter Datenbank und den vom Editortest erstellten Inhalten/Bildern. Je drei Läufe im Mobil- und Desktopprofil aus scripts/audit.mjs. Leistung, Barrierefreiheit, Best Practices, SEO und agentisches Browsing in jedem Lauf und damit in beiden Medianen 100. Vollständige Geräte-/Drosselungs- und Umgebungseinstellungen sowie Ergebnisse stehen in reports/lighthouse-editor/summary.json und den sechs Einzelberichten; funktionale Ergebnisse in reports/editor/result.json.
Die Messung prüft die gemeinsame öffentliche Ausgabe nach Entfernung der festen Text-/Überschriftenbreiten. Sie ist keine Abnahme aller Pilot- oder Kundenseiten. Felddaten zu LCP/INP/CLS wurden nicht erhoben; INP wird aus diesem Ladelauf nicht abgeleitet. GEO/Auffindbarkeit ist durch den Agentic-Browsing-Score nicht nachgewiesen.
Ergänzung: Autorotation, Blättern, eigene Texte, 13.09.2026
- 395 PHP-Tests / 1672 Assertions unter PHP 8.2.12 und 8.4.22, 18 JavaScript-Modelltests, Playwright-Editortest, öffentliche Browserprüfung. axe: null Verstöße auf Startseite, Projekteseite, Beitrag.
- Die Autorotation ist als Verlauf geprüft, nicht als Schnappschuss: 0 → 666 → 1332 → 1998 in drei Schritten zu je sieben Sekunden, und nach einem Mausrad-Ereignis bleibt der Wert stehen. Dabei fiel der Fehler der ersten Fassung auf: das Sprungziel wurde aus
offsetLeftberechnet und der Offset des Sliders doppelt abgezogen – Ergebnis −78, also keine Bewegung. - Belegt ist außerdem, dass das Skript nur auf Seiten mit einem solchen Slider geladen wird und die Richtlinie sonst bei
script-src 'none'bleibt. - Blättern in der Beitragsliste mit sieben Beiträgen geprüft: erste Seite ohne „Neuere“, letzte ohne „Ältere“, Seite 99 landet auf der letzten, und ohne den Schalter bleibt es eine Auswahl ohne Leiste.
- Acht Projekttexte sind geschrieben, nicht übernommen – für die Beiträge, die auf der laufenden Website keinen Text haben (zwei davon nicht einmal einen Auszug). Sie beschreiben Aufgabe, Weg und Ergebnis, ohne Zahlen, Namen oder Zusagen zu erfinden. Sie gehören vor einem Livegang gegengelesen, denn sie sind meine Formulierung über Umuts Projekte.
- Nicht geprüft: die Autorotation auf einem echten Touchgerät und in Firefox oder Safari; gemessen ist sie im Chromium der Browserprüfung.
Ergänzung: Nachbau vollständig, 13.09.2026
- 390 PHP-Tests / 1641 Assertions unter PHP 8.2.12 und 8.4.22, 18 JavaScript-Modelltests, Playwright-Editortest, öffentliche Browserprüfung. axe: null Verstöße auf Startseite, Projekteseite, Datenschutzerklärung, Projektbeitrag und mobiler Projekteseite.
- Der Nachbau ist jetzt vollständig: 29 Projektbeiträge mit den echten Bildern, Titeln, Auszügen und Texten der laufenden Website, die vollständige Datenschutzerklärung (27 Überschriften, rund 22.000 Zeichen), Impressum, Startseite, Projekteseite. 41 Medien, 33 Seiten.
- Ein Befund, der für den echten Umzug zählt: 11 der 29 Projektbilder hätte die Mediathek auf einem Hosting mit 128 MB abgewiesen, zwei davon (13,5 und 12,0 Megapixel) auch mit mehr Speicher – sie überschreiten die Pixelgrenze. Der Umzug muss solche Bilder vorher verkleinern; für den Nachbau ist genau das geschehen (9 Bilder auf 2400 px). Die Meldung der Mediathek ist dabei richtig und verständlich, sie kommt nur an einer Stelle, an der niemand mit ihr rechnet.
- Die Größe der Kennzahl und der Kundenstimme ließ sich nicht einstellen:
.block-stat strongund.block-quote phatten feste Werte, gegen die eine Blockeinstellung nicht ankam. Beide erben jetzt vom Block – dieselbe Familie wie die Theme-Skala, die die Kartenüberschriften überschrieb. - Gemessen: Startseite 56 KB HTML mit 15 Bildern, Projekteseite 32 KB mit 13, Datenschutzerklärung 38 KB. Kein ausführbares Skript auf keiner Seite; das einzige
<script>ist strukturierte Daten alsapplication/ld+json, und die Richtlinie sendet weiterhinscript-src 'none'. - Nicht geprüft: die Projektbeiträge sind inhaltlich übernommen, nicht redaktionell überarbeitet – einzelne Texte der laufenden Website sind kurz oder fehlen dort ganz (8 von 29 haben nur den Auszug). Und nichts davon steht auf echtem Hosting.
Ergänzung: Detailabgleich mit dem Original, 13.09.2026
- 390 PHP-Tests / 1641 Assertions unter PHP 8.2.12 und 8.4.22, 18 JavaScript-Modelltests, Playwright-Editortest, öffentliche Browserprüfung. axe: null Verstöße auf Startseite, Projekteseite und Handybreite des Nachbaus.
- Der ernsteste Fund ist eine beinahe entstandene Lücke: beim Freigeben von Auszeichnungen in Überschriften war die Dokumentfassung in der Schliessung des Filters nicht gebunden – der Filter lief nie, während die Ausgabe schon unescaped war. Ein Test, der
<script>alert(1)</script>in eine Überschrift schreibt, hat es im ersten Lauf gezeigt. Er prüft jetzt beides: das hervorgehobene Wort kommt durch, das Skript nicht. - Gegen das Original nachgemessen statt geschätzt: Kartenbreite 316 px (Original 324), Kartenhöhe 342 (330), Kartentitel 19 px/800 in beiden, Überschrift zweiter Ebene 44 px in beiden, Hauptüberschrift 66 px (68).
- Nicht geprüft: Punkte am Slider in Firefox und Safari – dort greift der Rückfall auf ein wischbares Schiebefeld, gesehen habe ich ihn in diesen Browsern nicht.
Ergänzung: Nachbau überarbeitet, Dokumentschema v17, 13.09.2026
- 389 PHP-Tests / 1636 Assertions unter PHP 8.2.12 und 8.4.22, 18 JavaScript-Modelltests, Playwright-Editortest, öffentliche Browserprüfung.
- Der schwerste Fund des Tages kommt aus dem Editor, nicht aus dem Nachbau: in einem Dokument ab v13 ließ sich kein Baustein mehr einfügen, und Symbol, Fortschritt, Slider und eingebetteter Inhalt in gar keinem. Der bestehende Editortest hat das nicht bemerkt, weil er ein altes Dokument bearbeitet. Der neue Test fügt jeden Typ in Dokumente von v1 bis v17 ein.
- Ein zweiter, der nur in der Gegenprobe sichtbar wird:
|default(true)macht in Twig aus einem gespeichertenfalseeintrue. Die neuen Anzeigeoptionen der Beitragsliste hätten sich speichern lassen und nichts getan – dieselbe Krankheit wie Rahmenstärke und Bildrundung. Der Test prüft beide Richtungen. - Neu geprüft: verlinktes Bild (mit denselben Linkregeln, sechs Fälle), klebender Kopfbereich als Einstellung, Projektraster gegen Blogarchiv.
- Am Nachbau nachgemessen: Lösungskarte 213 px statt 300, Abstand zur Projektliste 54 px, Projektkarte 337 px mit Bild und Titel – das Original liegt bei 324 px.
- Nicht geprüft: ob der klebende Kopfbereich auf einem Telefon mit dynamischer Adressleiste gut aussieht, und der Slider ist nicht auf einem echten Touchgerät gewischt worden.
Ergänzung: kant-it.de nachgebaut, 12.09.2026
- 381 PHP-Tests / 1619 Assertions unter PHP 8.2.12 und 8.4.22, 17 JavaScript-Modelltests, Playwright-Editortest, öffentliche Browserprüfung.
- Der Nachbau ist die Prüfung: Startseite mit neun Abschnitten, Projekteseite, vier Beiträge, Impressum, Datenschutzgerüst, Kopf- und Fußbereich, zwei Menüs, Kontaktformular, zwölf Bilder, eigene Palette und Schrift – gegen eine eigene Datenbank und einen eigenen Medienordner, nicht gegen die Entwicklungsinstallation.
- Gefunden dabei: fünf Fehler (ADR 042), darunter der größte: die Palette färbte Symbole, Knöpfe, Rahmen und den Einwilligungsdialog überhaupt nicht. Vier davon sind behoben und durch Tests abgesichert, der fünfte war mein eigener Kontrastfehler beim Beheben des ersten.
- axe: null Verstöße auf Startseite, Projekteseite, Beitrag und Impressum, in 1440 px und 390 px – gemessen an der nachgebauten Seite, nicht an der Demo.
- Gemessen am Nachbau: Startseite 45 KB HTML, 33 KB CSS, rund 430 KB Bilder in WebP, 0 Skripte, 21 Abfragen. Die Abfragezahl ist die höchste bisher gemessene und erklärt sich aus der Beitragsliste; sie liegt unter der Obergrenze, ist aber der nächste Kandidat fürs Zusammenfassen.
- Nicht geprüft: die vollständige Datenschutzerklärung der laufenden Website (nur das Gerüst), die restlichen Projektbeiträge, die Produktseiten von HausKlar und KantTresor, und nichts davon auf echtem Hosting. Der Nachbau ist ein Abbild, keine Migration: die Inhalte sind neu geschrieben, nicht aus WordPress exportiert.
Ergänzung: Installer, 12.09.2026
- 379 PHP-Tests / 1606 Assertions unter PHP 8.2.12 und 8.4.22, 17 JavaScript-Modelltests, Playwright-Editortest, öffentliche Browserprüfung.
- Die Abnahme des Pakets ist ein Test, kein Bericht: ein Test geht die sechs Bildschirme durch die echte HTTP-Schicht, mit einem Kernel in einem wegwerfbaren Projektverzeichnis – leere Adresse → Weiterleitung auf
/install, Datenbank, Migration, Website, Konto, fertig. Danach antwortet/installmit 404 und/mit 200, und auf der Startseite steht der Name, den das Formular bekommen hat. Die Migrationen darin sind die echten. - Von Hand im Browser nachgestellt, gegen eine Kopie der Anwendung in einem leeren Verzeichnis mit leerer Datenbank: erste Anfrage 302 auf
/install, Systemprüfung, Datenbank (SQLite), 13 Migrationen, Website „Tischlerei Berg“. Den letzten Schritt – das Konto – habe ich nicht im Browser ausgefüllt, sondern dem Test überlassen; ich tippe keine Passwörter in Formulare. - axe auf allen vier erreichbaren Installationsbildschirmen: null Verstöße (wcag2a, wcag2aa, wcag21a, wcag21aa).
- Das Releasearchiv wurde entpackt und gestartet, nicht nur gebaut:
kantsites-1.3.0.zipin ein leeres Verzeichnis, Server darauf, erste Anfrage → Installer. Damit ist belegt, dassvendor/vollständig ist und auf dem Zielsystem weder Composer noch eine Konsole gebraucht wird. - Die einzelne
install.phpist dort geprüft, wo sie gefährlich wäre: neun Archiveinträge, die aus dem Zielverzeichnis ausbrechen wollen (../, absolut, Windows-Laufwerk, Rückwärtsschrägstrich, Nullbyte), landen nirgends – und ein Archiv mit einem solchen Eintrag bricht ab, ohne die Datei außerhalb anzulegen. Der Eintrag im Testarchiv ist echt: ZIP speichertkantsites-1.2.0/../entwischt.txtunverändert. - Nicht geprüft: der Download selbst. Solange das Archiv nicht unter seiner Adresse liegt, ist die Kette „Datei hochladen → lädt → entpackt“ nur bis zum Entpacken belegt. Ebenso ungeprüft: MySQL als Zieldatenbank im Installer (der Verbindungstest ist da, ein echter MySQL-Server war es nicht), echtes Hosting, und ein Screenreader.
Ergänzung: Bildgrößen und Releasearchiv, 12.09.2026
- 352 PHP-Tests / 1479 Assertions unter PHP 8.2.12 und 8.4.22, 17 JavaScript-Modelltests, Playwright-Editortest, öffentliche Browserprüfung.
- Der Browsertest hat den Fehler gefunden, den die Unittests nicht sehen konnten: der Dokumentprüfer ließ höchstens drei
sourcesje Bild zu. Mit der vierten Variante war jedes Dokument mit einem Bild darin ungültig – und eine abgewiesene Speicherung sieht im Editor so aus, als wäre nichts passiert. Gefunden wurde er, weil ein Galeriebild im Vorschaurahmen nicht erschien. Die Grenze hängt jetzt anMediaLibrary::WIDTHSstatt an einer Zahl, und ein Test prüft beide Seiten: vier Quellen werden angenommen, fünf abgewiesen. - Die Bildpipeline ist nachgerechnet, nicht behauptet: ein Test lädt ein erzeugtes Foto hoch, öffnet jede entstandene Datei und prüft, dass sie WebP ist, dass die vier Breiten 480/960/1600/2400 entstehen und dass das Seitenverhältnis erhalten bleibt. Ein zweiter Upload mit 700 px Breite bekommt zwei Stufen – 480 und 700 –, womit „nie hochskalieren“ geprüft ist und nicht nur im Kommentar steht.
- Ein Testfehlschlag, der keiner war: derselbe Test fiel um, sobald er in der gesamten Suite lief, mit der Meldung „dieses Bild benötigt mehr Arbeitsspeicher als das Hosting bereitstellt“. Das ist die Schutzprüfung vor dem Decodieren, die den bereits belegten Speicher mitrechnet – sie hat richtig gehandelt. Der Test benutzt jetzt eine kleinere Quelle und hebt das Limit für seine Dauer an, weil sein Gegenstand die Pipeline ist und nicht die Schutzprüfung.
- Hintergrundbilder sind je Gerät geprüft: die Desktopregel nennt die größte Variante, die Regel im
max-width:767px-Block die 960er. - Das Releasearchiv ist gebaut, nicht geplant:
kantsites-1.2.0.zip, 3465 Dateien, 4,4 MB, SHA-256950eaa4c…. Nachgesehen wurde, was nicht drin ist: kein PHPUnit, keine Tests, keinvar/, kein.env. - Der Abbruch bei geänderten Abhängigkeiten ohne Composer ist mit zwei Tests belegt: geänderte
composer.lockohne Composer bricht ab und stellt den alten Stand wieder her; unverändertecomposer.lockläuft durch. - Nicht geprüft: das Archiv ist auf keinem echten Hostingpaket entpackt und gestartet worden – das gehört zu den Arbeitspaketen J und N. Der Installer, der es herunterlädt, existiert noch nicht.
Ergänzung: Ladeverhalten, 12.09.2026
- 347 PHP-Tests / 1422 Assertions unter PHP 8.2.12 und 8.4.22, 17 JavaScript-Modelltests, Playwright-Editortest, öffentliche Browserprüfung mit neuem Ladebudget.
- Die Messung hat sofort etwas gefunden: die Startseite brauchte 18 Datenbankabfragen, weil Einstellungen und Theme je Aufrufer erneut gelesen wurden. Mit einem Merker für die Dauer einer Anfrage sind es 8. Das ist der Unterschied zwischen „vermutlich in Ordnung“ und einer Zahl.
- Und die Messung hat einen Fehler von mir gefunden, den ich beim Merken eingebaut hatte: der Merker wurde am Anfang des Speicherns geleert, das Speichern liest den Stand aber noch einmal und füllte ihn damit erneut – der Rest der Anfrage bekam den alten Stand. Ein bestehender Test über die Gestaltungsvorlagen fiel sofort um. Geleert wird jetzt nach dem Schreiben.
- Das Ladebudget prüft je Seite HTML-Größe, CSS-Größe, Anzahl Anfragen, Anzahl Skripte und Abfragen gegen Obergrenzen. Heute: Startseite 7,4 KB HTML, 22,7 KB CSS, 2 Anfragen, 8 Abfragen, 0 Skripte; Beitragsübersicht 3,5 KB HTML, 29,8 KB CSS, 3 Anfragen, 13 Abfragen, 0 Skripte. Die Null bei den Skripten ist die wichtigste Zahl – sie hält als Test fest, was bisher nur Absicht war.
- Blättern ist mit 30 Fassungen und 12 Weiterleitungen geprüft, einschließlich einer Seitenzahl jenseits des Endes.
- Nicht geprüft: die Grenzen sind an der heutigen Demoseite gemessen; eine Seite mit vielen Bildern wird andere Zahlen haben, und die Obergrenzen müssen dann begründet angehoben werden statt stillschweigend. Auf echtem Hosting ist nichts davon gemessen (Arbeitspaket J).
Ergänzung: Sicherung und Wiederherstellung, 12.09.2026
- 344 PHP-Tests / 1397 Assertions unter PHP 8.2.12 und 8.4.22, 17 JavaScript-Modelltests, Playwright-Editortest, öffentliche Browserprüfung.
- Der Nachweis, um den es geht: Sicherung anlegen, eine Seite und eine Bilddatei löschen, zurückspielen – beides ist wieder da. Einmal als Test gegen eine wegwerfbare Installation, einmal von Hand auf der Entwicklungsinstallation mit einer eigens angelegten Testseite (5 Seiten → gesichert → gelöscht, 4 → zurückgespielt, 5 → Testseite entfernt, 4). Damit ist der älteste offene Punkt aus Arbeitspaket I erledigt: „Eine Wiederherstellung ist nachgewiesen.“
- Geprüft ist außerdem, dass die Kopie der Datenbank eine benutzbare Datenbank ist, nicht nur eine Datei, die existiert: der Test öffnet sie und zählt die Seiten darin.
- Eine manipulierte Sicherung wird abgewiesen, bevor irgendetwas angefasst wird – nicht einmal die Sicherheitskopie entsteht. Eine Sicherung aus einer neueren Fassung wird abgewiesen, mit
--forcegeht sie durch. Rotation behält die neuesten und meldet, was sie entfernt hat. - Ein Fall, den erst der Test zeigte: zwei Sicherungen in derselben Sekunde. Nicht akademisch, denn die Wiederherstellung legt selbst eine Sicherheitskopie an – die landet in derselben Sekunde wie die Sicherung, die gleich eingespielt wird. Statt die zweite scheitern zu lassen, bekommt der Name eine Nummer.
- Nicht geprüft: MySQL (dort fehlt das Sichern über
mysqldump, der Code sagt es), sehr große Medienordner, und ein Download der Sicherung über den Browser gibt es bewusst noch nicht.
Ergänzung: Breite, Menüs, Seiten ohne Kopfbereich, 12.09.2026
- 336 PHP-Tests / 1354 Assertions unter PHP 8.2.12 und 8.4.22, 17 JavaScript-Modelltests, Playwright-Editortest, öffentliche Browserprüfung.
- Ein bestehender Test ist absichtlich umgeschrieben worden, und das ist erwähnenswert: er sicherte zu, dass ein zweiter Kopfbereich abgewiesen wird. Diese Regel war richtig, solange keine Seite wählen konnte, und wurde falsch, sobald sie es kann. Der Test prüft jetzt die neue Regel – mehrere Bereiche mit eigener Adresse, doppelte Adresse weiter abgewiesen, Standardbereich nicht löschbar.
- Der dritte Fehler des Tages aus derselben Familie: die globale Seitenbreite ließ sich im Designbereich einstellen, aber
site.cssdeckelte bei 1180 px. Schmaler wirkte, breiter nicht. Wie bei der Rahmenstärke und der Bildrundung: eine Einstellung, die sich speichern lässt und nichts tut, ohne jede Fehlermeldung. Ein Test liest jetzt die Regel aussite.cssund prüft, dass sie den Theme-Wert nimmt. - Seitenbereiche sind über echte Auslieferung geprüft: mit „keiner“ steht weder
site-headernochsite-footerim HTML, der Seiteninhalt aber schon; ein Verweis auf einen gelöschten Bereich fällt auf den Standard zurück. - Nicht geprüft: der Burger ist nicht auf einem Touchgerät bedient worden, und kein Screenreader war beteiligt. Die vier Menüplätze sind im Test benutzt, aber nicht alle vier von Hand in der Menüverwaltung durchgeklickt.
Ergänzung: Designer ausgebaut, 12.09.2026
- 315 PHP-Tests / 1309 Assertions unter PHP 8.2.12 und 8.4.22, 16 JavaScript-Modelltests, Playwright-Editortest (axe auf dreizehn Bildschirmen, null Verstöße), öffentliche Browserprüfung.
- Die Gestaltungseigenschaften sind nicht „vorhanden“, sondern einzeln nachgerechnet: 16 Datensätze vergleichen die erzeugte Deklaration Zeichen für Zeichen mit der erwarteten. Das ist die Prüfung, die die beiden Fehler unten gefunden hätte, wenn es sie vorher gegeben hätte.
- Zwei Fehler, die vorher niemand gesehen hat. Erstens: eine Rahmenstärke je Seite wurde zu
border-width-top. Das ist kein CSS, der Browser verwirft die Zeile stillschweigend – Rahmenstärken je Seite hatten nie eine Wirkung, und es gab keine Fehlermeldung, die darauf hingewiesen hätte. Zweitens: eine Rundung auf einem Bildblock landete auf demfigure, das Bild darin blieb eckig. Beides ist genau das, wonach Umut gefragt hat – er hat zwei echte Defekte gefunden, indem er die Funktion benutzen wollte. - Ein Test hält das Schema und das Editorpanel zusammen: jede Gruppe im Schema muss im Panel einen Namen haben, sonst landen ihre Eigenschaften in einem unbenannten Aufklappfeld.
- Die drei neuen Bausteine sind über echte Seitenauslieferung geprüft, nicht nur über den Validator: Markup, Rollen, Klassen – und dass die Seite weiterhin
script-src 'none'sendet, denn keiner von ihnen braucht ein Skript. - Nicht geprüft: kein Screenreader. Der Slider ist nicht mit Touch auf einem echten Gerät bedient worden, nur mit Tastatur und Mausrad im Browser. Und der Vergleich mit Flatsome ist Wissen, keine Messung – die Erweiterung war nicht installierbar, das steht so im Vergleichsdokument.
Ergänzung: Updater, 12.09.2026
- 285 PHP-Tests / 1244 Assertions unter PHP 8.2.12 und 8.4.22, Playwright-Editortest (axe auf dreizehn Bildschirmen, null Verstöße), öffentliche Browserprüfung.
- Sechs Tests fahren den Updater gegen echte Git-Repositorys in einem Temp-Verzeichnis: ein bares Repository als Herkunft, ein Autorenklon, ein Installationsklon. Die zwei Befehle, die der Updater aufruft, sind dort Platzhalterskripte – so wird die Reihenfolge und der Rückweg mit echtem Git und echten Dateikopien geprüft, ohne zwei Minuten Composer.
- Der wichtigste davon ist der Fehlschlag: die neue Fassung bringt ein Migrationsskript, das mit Exitcode 1 endet. Geprüft wird danach, dass der Code auf dem alten Commit steht, die Datenbank den Inhalt von vor dem Update enthält, der Wartungszustand aufgehoben ist (weil der alte Stand antwortet) und im Protokoll
FEHLERsteht. - Die Reihenfolge der Schritte ist als Liste festgehalten, nicht nur ihr Ergebnis: Vorprüfung, Ziel, Sicherung, Wartung, Checkout, Fassung prüfen, Abhängigkeiten, Migration, Cache, Rauchtest, Fertig. Wer sie umstellt, bricht den Test.
- Geprüft ist außerdem, dass die Sicherung vor dem Checkout entsteht, dass sie die Datenbank enthält und den Medienordner nicht, und dass Datenbank und Medienordner der Installation unverändert bleiben.
- Am echten Repository durchgespielt, nicht nur im Test:
git.kant-it.de/kantarci/KantSites, Tagv1.0.0gesetzt, die Entwicklungsinstallation darauf gestellt (git checkout v1.0.0),v1.0.1veröffentlicht undphp bin/console cms:updateausgeführt. Ergebnis: elf Schritte, alle ok, in dieser Reihenfolge – Vorprüfung, Ziel (v1.0.1 von52f0ab38, Fassung 1.0.0), Sicherung (220 KB nachvar/backups/update-20260912-181159, darincms.db,.env,.env.local, kein Medienordner), Wartungszustand, Checkout, Fassung geprüft, Abhängigkeiten (Composer fehlt, vendor/ bleibt liegen), Migration („Already at the latest version“), Cache, Rauchtest („Datenbank erreichbar, Migration 20260912001200, Startseite /home lesbar, Fassung 1.0.1“), fertig. Danach:VERSION1.0.1,git describev1.0.1, kein Wartungszustand,/antwortet 200,var/updates.logenthältOK v1.0.1 (11 Schritte). - Der Wartungszustand ist danach einzeln geprüft: eingeschaltet antwortet
/mit 503 undRetry-After: 600und der Wartungsseite,/admin/loginmit 200; ausgeschaltet wieder 200. - Nicht geprüft: MySQL (dafür fehlt die Installation, siehe
docs/UPDATE.md, „Was anders wurde“), ein Hosting ohneproc_open(die Vorprüfung meldet es, der Fall selbst ist nicht durchgespielt), und ein Update über die Weboberfläche unter einem knappen Zeitlimit.
Ergänzung: Statistik, 12.09.2026
- 279 PHP-Tests / 1119 Assertions unter PHP 8.2.12 und PHP 8.4.22, Playwright-Editortest (axe auf jetzt zwölf Bildschirmen, null Verstöße), öffentliche Browserprüfung.
- Der wichtigste Test ist der langweiligste: er liest die Spaltenliste von
stat_hitund vergleicht sie mit der Zusage. Es gibt keine Spalte für IP-Adresse, Kennung, Sitzung, Cookie oder Hash – und wenn jemand später eine hinzufügt, bricht dieser Test, nicht erst eine Datenschutzprüfung. - 14 Anfragearten sind abgedeckt: Verwaltung, Bild, Stylesheet, Feed, Einwilligungsseite, Weiterleitung, Formularabsendung, Googlebot, Überwachungsdienst, Headless-Chrome und curl werden nicht gezählt; eine Seite und ein 404 werden gezählt, auch ohne Kennung.
- Durch echte Anfragen über den Kernel geprüft: fünf Aufrufe derselben Seite in derselben Stunde werden ein Zähler mit dem Wert 5. Dafür musste der Testaufruf
kernel.terminateauslösen – ohne das hätte der Test eine andere Anwendung geprüft als die, die läuft. - Der Bildschirm ist im Browser mit echten Zahlen angesehen worden (sechs Aufrufe, ein Verweis von Google, ein 404), und der CSV-Export ist im Test abgeholt und auf seinen Inhalt geprüft.
- PHP 8.4 hat dabei eine Verwarnung ausgesprochen, die der Testlauf sichtbar machte:
fputcsv()ohne ausdrücklichen Escape-Parameter. Jetzt ausdrücklich leer, was ein CSV-Leser erwartet. - Nicht geprüft: kein Screenreader. Die Aufbewahrung ist mit gestellten Daten geprüft, nicht über echte 425 Tage. Ob die Maschinenerkennung in der Praxis trifft, lässt sich erst am Piloten sehen – deshalb heißt die Zahl auf dem Bildschirm nicht „Besucher“.
Ergänzung: Einwilligung, Pflichtseiten und ein Layoutfehler im Kopfbereich, 12.09.2026
- 245 PHP-Tests / 976 Assertions unter PHP 8.2.12 und PHP 8.4.22, Playwright-Editortest, öffentliche Browserprüfung.
- Sieben Cookiezustände und zehn abgewiesene Einbettungsadressen sind abgedeckt. Der Kern der Prüfung ist nicht das Banner, sondern die Aussage „ohne Einwilligung entsteht keine Anfrage“: geprüft wird, dass weder ein iframe noch die Adresse des Anbieters im Markup steht und dass
frame-src 'none'bleibt. - Im Browsertest wird der Hinweis über den echten Einstellungsbildschirm eingeschaltet, dann aus einem zweiten Browserkontext ohne Verwaltungscookies geprüft: Banner da, kein iframe, Einwilligen über den Knopf des Platzhalters lädt den Inhalt, „Nur notwendige“ auf der Einwilligungsseite hält ihn wieder zurück. axe ohne Verstöße auf Banner und Einwilligungsseite.
- Der Browsertest hat zwei echte Fehler gefunden, die ich selbst eingebaut hatte. Erstens: meine Regel für die Textfarbe im Fußbereich schlug
.tone-inkund setzte grauen Text auf dunklen Grund – 2,24:1. Farbe gehört in die Tonregeln, nicht in eine Chromregel. Zweitens: das fixierte Banner verdeckte den Einwilligungsknopf des Platzhalters am Seitenende, sodass Playwright ihn nicht anklicken konnte – jetzt endet die Seite oberhalb des Banners, solange die Frage offen ist. Beides wäre einem Menschen erst beim Benutzen aufgefallen. - Umut hat einen Fehler gefunden, den keine Prüfung gemeldet hatte: im Kopfbereich stand die Wortmarke als Buchstabenkolonne in einem schmalen Kasten.
.site-headerwar noch ein Flexcontainer aus der Zeit des handgeschriebenen Markups, unddesign.cssband jede Designklasse an#main, wo Kopf- und Fußbereich nicht liegen. Kein Test hat es gesehen, weil kein Test das Aussehen des Kopfbereichs prüft – axe beanstandet keine 60 Pixel breite Spalte. Behoben; die Prüfung dafür bleibt das Hinsehen. - Nicht geprüft: kein Screenreader. Ob eine echte Einbettung (Karte, Video, Bewertungen) nach der Einwilligung tatsächlich lädt, ist mit einer erfundenen Adresse geprüft, nicht mit einem echten Anbieter – dafür braucht es die Pilotwebsite.
Ergänzung: Benutzerverwaltung und Mediathek, 12.09.2026
- 217 PHP-Tests / 845 Assertions unter PHP 8.2.12 und PHP 8.4.22, davon 16 neue für die Benutzerverwaltung; Playwright-Editortest und öffentliche Browserprüfung grün.
- axe deckt jetzt elf Bildschirme ab statt drei: Anmeldung, Seitenübersicht, Benutzer, eigenes Konto, Mediathek, Menüs, Formulare, Bereiche, Design, Einstellungen und der Editor in Desktop und Mobil. Null Verstöße. Das war der offene Punkt aus der Umgestaltung.
- Zwei gleichzeitige Sitzungen im Test zeigen die Sperrwirkung: nach einem zurückgesetzten Passwort und nach einer geänderten Rolle ist die Sitzung des betroffenen Kontos bei der nächsten Anfrage abgemeldet, die des handelnden Administrators nicht. Beim eigenen Passwortwechsel bleibt die wechselnde Sitzung angemeldet, die zweite nicht.
- Acht abgewiesene Kontoanlagen erreichen die Datenbank nicht, darunter ein Passwort mit Nullbyte und eines mit 73 Bytes – letzteres, weil bcrypt alles über 72 Bytes stillschweigend ignoriert und ein längeres Passwort damit kürzer wäre, als es aussieht.
- Die Migration lief mit Sicherung (
var/backups/before-users-*.db) und erst als Probelauf gegen die Entwicklungsdatenbank: dreiALTER TABLE ... ADD COLUMN, kein Tabellenneubau. - Dabei aufgefallen: der lokale Vorschauserver lieferte 500 für die neuen Bildschirme, weil sein Prozess einen älteren kompilierten Container hielt –
cache:clearohne--env=prodräumt den nicht ab. Kein Codefehler, aber der Grund, warum eine Änderung im Browser gegen einen frisch gestarteten Server anzusehen ist. - Mediathek über das Formular geprüft: zwei Dateien in einem Absenden, Upload ohne Token wird abgewiesen und legt nichts an, Bildangaben mit Versionskonflikt (zweites Speichern mit derselben Version ändert nichts und meldet es), Archivfilter, und Blättern mit 26 eingesetzten Bildern – 24 auf Seite eins, neueste zuerst,
?seite=99wird auf die letzte Seite begrenzt, und Speichern von Seite zwei kommt auf Seite zwei zurück. - Die Ablagefläche ist zweimal geprüft: im Browsertest über das echte Dateifeld (die Auswahl erscheint im Feld und wird benannt) und von Hand mit einem echten Drop aus zwei Dateien, von denen die Nicht-Bilddatei übersprungen und gemeldet wurde. Ohne JavaScript bleibt ein gewöhnliches Dateifeld mit Beschriftung übrig; abgeschickt wird nie automatisch.
- Nicht geprüft: kein Screenreader; die Mediathek ist mit 2 und mit 26 Einträgen geprüft, nicht mit einer wirklich großen Bibliothek. Vom Updateverfahren ist nichts geprüft, weil nichts gebaut ist –
docs/UPDATE.mdist ein Plan.
Ergänzung: Verwaltung neu gestaltet, 12.09.2026
- 201 PHP-Tests / 716 Assertions grün, Playwright-Editortest mit axe ohne Verstöße auf Anmeldung, Seitenübersicht und Editor (Desktop und Mobil), öffentliche Browserprüfung unverändert grün.
- Zwei Testselektoren zeigten auf Klassen, die die Umgestaltung umbenannt hat; sie prüfen jetzt dieselbe Sache über den neuen Namen. Die Klasse, an der die Rechteprüfung für das endgültige Löschen hängt, ist absichtlich geblieben.
- Der Browsertest hat einen Fehler gefunden, den ich selbst eingebaut hatte. Beim Zerlegen des Stylesheets schnitt mein Skript am Ende jedes
@media-Blocks alle schließenden Klammern ab statt nur einer. Damit wareditor.cssab dem ersten Medienblock ungültig: der Browser behielt 29 von 202 Regeln. Aufgefallen ist es an einer Vorschaubreite von 1236 statt 1240 Pixeln, weil der Standardrahmen des iframe nicht mehr entfernt wurde – vier Pixel als einziges Symptom dafür, dass dreiviertel des Editor-Stylesheets fehlte. Behoben, und die Datei wird jetzt auf ausgeglichene Klammern geprüft. - Nicht geprüft: kein Screenreader. Die Bildschirme Menüs, Formulare, Bereiche, Design, Einstellungen und Fassungen habe ich im Browser angesehen und ihre Tabellen und Formulare bedient, aber die automatische Barrierefreiheitsprüfung deckt sie nicht ab – sie prüft Anmeldung, Seitenübersicht und Editor.
- Der Editor selbst behält seinen Aufbau. Er übernimmt die neuen Farben, Schaltflächen und die Systemschrift, ist aber nicht neu gestaltet worden.
Ergänzung: Verwaltung neu gestaltet, 12.09.2026
- 201 PHP-Tests / 716 Assertions grün, Playwright-Editortest mit axe ohne Verstöße auf Anmeldung, Seitenübersicht und Editor (Desktop und Mobil), öffentliche Browserprüfung unverändert grün.
- Zwei Testselektoren zeigten auf Klassen, welche die Umgestaltung umbenannt hat; sie prüfen jetzt dieselbe Sache über den neuen Namen. Die Klasse, an der die Rechteprüfung für das endgültige Löschen hängt, ist absichtlich geblieben.
- Der Browsertest hat einen Fehler gefunden, den ich selbst eingebaut hatte. Beim Zerlegen des Stylesheets schnitt mein Skript am Ende jedes
@media-Blocks alle schließenden Klammern ab statt nur einer. Damit wareditor.cssab dem ersten Medienblock ungültig: der Browser behielt 29 von 202 Regeln. Aufgefallen ist es an einer Vorschaubreite von 1236 statt 1240 Pixeln, weil der Standardrahmen des iframe nicht mehr entfernt wurde – vier Pixel als einziges Anzeichen dafür, dass dreiviertel des Editor-Stylesheets fehlte. Behoben und mit ausgeglichenen Klammern nachgerechnet. - Von Hand bedient: Seitenübersicht mit Aufklappfeld, Menüs, Formulare, Bereiche, Design, Einstellungen, Mediathek und der Editor in allen drei Vorschaugrößen.
- Nicht geprüft: kein Screenreader. Die automatische Barrierefreiheitsprüfung deckt Anmeldung, Seitenübersicht und Editor ab, nicht die übrigen Verwaltungsbildschirme.
Ergänzung: eigenes CSS und eigenes Skript, 12.09.2026
- 201 PHP-Tests / 716 Assertions unter PHP 8.2.12 und PHP 8.4.22, 15 JavaScript-Modelltests, der vollständige Playwright-Editortest mit axe (null Verstöße) und die öffentliche Browserprüfung.
- Zehn abgewiesene CSS-Eingaben erreichen kein Dokument, darunter die Ausbruchsversuche:
color:red} body{display:none, ein fremder Selektorbody { … },@import,@media,url(javascript:alert(1)),url(//fremd.example/x.png), ein Backslash-Escape undexpression(). - Fünf erlaubte CSS-Formen werden korrekt auf das Element bezogen, einschließlich
& > pund& .block-text. - Zwei echte Löcher kamen dabei heraus.
& .block-textwurde zu#id.block-text, weil das führende Leerzeichen wegtrimmt wurde – aus dem Nachfahren wurde derselbe Knoten, die Regel traf das falsche Element. Undurl(//fremd.example/x.png)kam durch, weil jede Adresse mit/erlaubt war: eine protokollrelative Adresse hätte über das Schema der Seite von Dritten geladen. Beides behoben, beides durch einen Test abgedeckt. - Skriptauslieferung geprüft: eigenes Skript erscheint nie im HTML, sondern nur unter
/assets/seite/{id}.jsmittext/javascript, in einer eigenen Closure mit gesuchtemelement. Die Seite mit Skript sendetscript-src 'self', eine Seite ohne behältscript-src 'none'und liefert für ihre Adresse 404. Ein Skript aus einem gespeicherten, aber unveröffentlichten Entwurf wird nicht ausgeliefert. - Rollenprüfung geprüft: der Vergleich mit dem gespeicherten Stand weist Ändern, Entfernen und Hinzufügen eines Skripts ab und lässt ein unverändertes Skript durch – ein Editor kann eine Seite mit Skript also weiter bearbeiten, ohne das Skript anfassen zu können.
- Nicht geprüft: der Reiter „Erweitert“ ist nicht von Hand bedient und nicht mit einem Screenreader getestet. Ob ein eingesetztes Skript im Browser tatsächlich läuft, ist ebenfalls nicht ausgeführt worden – geprüft ist, dass die Datei mit dem erwarteten Inhalt ausgeliefert wird und dass die Richtlinie sie zulässt.
Ergänzung: formatierter Text, 12.09.2026
- 182 PHP-Tests / 685 Assertions unter PHP 8.2.12 und PHP 8.4.22, 15 JavaScript-Modelltests, der vollständige Playwright-Editortest mit axe (null Verstöße) und die öffentliche Browserprüfung.
- Dreizehn Fälle durch den Filter, davon acht Angriffe:
<script>alert(1)</script>Text danachbehält nur den Text, einonclick-Attribut verschwindet,classundstyleverschwinden mitsamt dem Element (der Text bleibt), einjavascript:-Link wird zu Text, ein<img src=x onerror=…>verschwindet vollständig, ein<iframe>verschwindet, unausgeglichene Auszeichnung wird geschlossen, und Klartext mit<wird maskiert. - Geprüft, wo gefiltert wird: nach dem Speichern liegt in der Datenbank bereits die gefilterte Fassung. Damit kann kein Renderer das Filtern vergessen, und eine manipulierte Anfrage speichert nichts, was der Editor nicht anbietet.
- Geprüft, dass ältere Dokumente unberührt bleiben: dieselbe Auszeichnung wird in einem v3-Dokument maskiert ausgegeben und in einem v12-Dokument als Auszeichnung. Der bestehende XSS-Test für v1 gilt unverändert.
- Geprüft, dass derselbe Filter in einem geteilten Bereich greift, und dass ein nach dem Filtern leerer Textblock abgewiesen wird, ohne zu schreiben.
- Eine Inkonsistenz wurde dabei behoben: ein Text, der zufällig ein
<enthielt, behielt echte Zeilenumbrüche, während alles andere<br>benutzte – zwei Darstellungen desselben Umbruchs. Beide Zweige erzeugen jetzt<br>; innerhalb voncodebleiben Umbrüche erhalten. - Die Werkzeugleiste selbst ist nicht bedient worden und nicht mit einem Screenreader geprüft. Geprüft ist der Filter, der Speicherweg und die Ausgabe.
Ergänzung: Kopf, Fuß und verknüpfte Sektionen, 12.09.2026
- 165 PHP-Tests / 660 Assertions unter PHP 8.2.12 und PHP 8.4.22, 15 JavaScript-Modelltests, der vollständige Playwright-Editortest mit axe (null Verstöße) und die öffentliche Browserprüfung.
- Bereiche geprüft: Kopf- und Fußbereich erscheinen als gewöhnliche Blöcke, der Navigationsblock zeigt das Menü, eine Änderung am Kopfbereich erreicht beide geprüften Seiten gleichzeitig, und ein geleerter Bereich rendert nichts statt einer kaputten Hülle.
- Verknüpfte Sektion geprüft: auf zwei Seiten sichtbar, die Seitendokumente enthalten nur die Adresse, eine Änderung wirkt an beiden Stellen,
usedBynennt beide Seiten, und nach dem Entfernen bleiben beide Seiten mit HTTP 200 heil, mit erhaltenem Verweis. - Abgewiesen werden: eine Hauptüberschrift in einem geteilten Bereich, eine Sektion mit Selbstbezug (ohne zu schreiben), ein zweiter Kopfbereich und das Löschen von Kopf- oder Fußbereich.
- Ein echter Fehler, den der axe-Lauf gefunden hat, und zwar nicht nur im eingesetzten Fußbereich: die Token-CSS war für die flache Struktur Sektion → Text geschrieben.
.block-column>.block-text:first-childsetzt eine Farbe für helle Hintergründe und gewinnt auf Spezifität gegen.tone-ink .block-text; Text in einer Spalte auf dunklem Grund war damit unlesbar, gemessen 1,87:1. Das betraf jede dunkle Sektion mit Spalten, nicht nur die neuen Bereiche. Zwei gezielte Selektoren gleicher Spezifität stellen es richtig, helle Farbwelten bleiben unberührt.
Ergänzung: Startseite, erreichbare Standarddateien, getrennte Befunde, 12.09.2026
- 162 PHP-Tests / 636 Assertions unter PHP 8.2.12 und PHP 8.4.22, 15 JavaScript-Modelltests, der vollständige Playwright-Editortest und die wieder grüne öffentliche Browserprüfung.
- Lighthouse 13.4.1: je drei Läufe mobil und Desktop, alle fünf Kategorien 100.
- Startseite geprüft: eine andere veröffentlichte Seite wird zur Wurzel und antwortet unter
/, ihre eigene Adresse leitet mit 301 dorthin, die bisherige Wurzel wird eine gewöhnliche Seite und ist wieder verschiebbar. Sitemap, strukturierte Daten und Menüauflösung folgen. Umbenennen und Papierkorb sind für die Wurzel gesperrt. Drei ungültige Angaben ändern nichts. - Ein weiterer echter Fehler, den nur ein HTTP-Aufruf zeigt:
/sitemap.xml,/robots.txt,/llms.txtund/feed.xmlwaren lokal nie erreichbar. Der eingebaute PHP-Server antwortet für fehlende Pfade mit Dateiendung selbst mit 404, ohne den Frontcontroller zu fragen – alle Kernel-Tests bestanden trotzdem, weil sie die Anwendung direkt aufrufen.bin/dev-router.phpbildet die Rewrite-Regel nach, Start- und CI-Befehl nutzen es, und die Browserprüfung ruft die vier Adressen jetzt über HTTP auf und prüft den Inhaltstyp. Der Grund, warum es so lange unbemerkt blieb, war genau diese fehlende Prüfung. - Barrierefreiheitsbefunde werden nach Ursache getrennt. Ein Kontrastfehler aus Theme oder Stylesheet bleibt ein Defekt und bricht den Lauf ab – so wurde die Linkfarbe gefunden, die jeden dunklen Abschnitt überschrieb. Ein Kontrastfehler an einem Element, das eine eigene Regel im erzeugten Seiten-Stylesheet hat, ist eine redaktionelle Feststellung: sie wird bei jedem Lauf mit Seite, Farbe und Verhältnis ausgegeben und in
reports/browser.jsongeschrieben, macht aber einen Codewechsel nicht rot. Stillschweigend durchgelassen wird nichts. - Aktuell offen und bei jedem Lauf gemeldet:
/grundlagen, Textblock#d08080auf hellem Grund, 2,75:1 statt 4,5:1. Nicht verändert, weil es eine Nutzerentscheidung ist.
Ergänzung: Seiten verwalten, 12.09.2026
- 160 PHP-Tests / 622 Assertions unter PHP 8.2.12 und PHP 8.4.22, 15 JavaScript-Modelltests und der vollständige Playwright-Editortest mit axe (null Verstöße).
- Verschieben geprüft: eine Seite mit Kind und Enkel wird umbenannt, alle drei Adressen ändern sich, jede neue antwortet mit 200, jede alte mit 301 auf genau ihr neues Ziel, und Slug sowie Elternbeziehung der Nachkommen bleiben unverändert.
- Vier abgewiesene Verschiebungen bewegen nichts und erzeugen keine Weiterleitung: unter die eigene Unterseite, in sich selbst, auf eine vergebene Adresse und mit einem unbrauchbaren Slug. Die Startseite wird ebenfalls abgewiesen.
- Papierkorb geprüft: der Teilbaum geht mit, die Seiten antworten öffentlich mit 404 und verschwinden aus Navigation, Sitemap, Beitragsarchiv, Feed und Editorliste. Ein Kind lässt sich nicht vor seinem Elternteil wiederherstellen, und das Wiederherstellen einer Seite holt keine andere zurück.
- Fassungen geprüft: Reihenfolge neueste zuerst, Wiederherstellen erzeugt eine zusätzliche Fassung statt zu überschreiben, eine Fassung einer anderen Seite wird abgewiesen.
- Zeitplan geprüft: ein künftiger Zeitpunkt veröffentlicht nichts, ein vergangener genau einmal, danach ist der Zeitpunkt verbraucht, ein ungültiges Format wird abgewiesen, und eine Seite im Papierkorb wird nie durch den Zeitplan veröffentlicht.
- Ein echter Fehler kam dabei heraus: die Reihenfolge des Fassungsverlaufs war nicht eindeutig.
created_athat Sekundengenauigkeit, mehrere Speichervorgänge fallen in dieselbe Sekunde, und die Liste richtete sich dann nach der zufälligen Revisions-ID – „vorherige Fassung wiederherstellen“ hätte die falsche treffen können. Jede Fassung trägt jetzt einen je Seite streng aufsteigenden Zähler; die Migration füllt ihn aus den vorhandenen Zeitstempeln und wurde vorher gegen eine Kopie der Datenbank geprüft. - Migration
20260912000900erst gegen eine Kopie ausgeführt und der Backfill kontrolliert (drei Fassungen von/grundlagenerhielten seq 1 bis 3 in der richtigen Reihenfolge), danach nach Backup angewendet.cms:publish-dueausgeführt.
Ergänzung: Browsertests wiederhergestellt, 12.09.2026
- 155 PHP-Tests / 579 Assertions unter PHP 8.2.12 und PHP 8.4.22, 15 JavaScript-Modelltests und erstmals seit dem Editorumbau wieder der vollständige Playwright-Editortest.
- Der Editortest war durch den Umbau kaputt: er steuerte die abgeschafften Auswahllisten. Er wurde auf die freien Bedienelemente umgeschrieben und prüft jetzt Einheitenfelder, Vererbung über drei Geräte, einzelnes Zurücksetzen, Palettenfarbe, Abstand je Seite, die Hover-Regel, freie Rasterspalten und die Bewegungseffekte.
- axe-core: null Verstöße auf Login, Seitenliste, Editor in Desktop- und Mobilbreite, Medienauswahl und der bearbeiteten veröffentlichten Seite.
- Lighthouse 13.4.1: je drei Läufe mobil und Desktop auf der Startseite, alle fünf Kategorien 100 – mit Theme-System, gehashtem Stylesheet und den neuen Blöcken.
Drei echte Fehler, die nur der Browserlauf gezeigt hat:
- Die frei gestalteten Werte wirkten in der Editorvorschau überhaupt nicht. Ein
srcdoc-Iframe erbt die Richtlinie des einbettenden Dokuments; die Verwaltung verbietet Inline-Styles, also wurde das erzeugte<style>stillschweigend verworfen. Ausgeliefert wurde es korrekt – die Vorschau log. Behoben über ein inertes<template>plusadoptedStyleSheets. - Die Einrückung der Unterseiten in der Seitenliste hat nie funktioniert, weil sie über ein
style-Attribut lief, das dieselbe Richtlinie verwirft. Die Hierarchie sah immer flach aus. Jetzt über Klassen. - Das Theme setzte alle Links auf die Akzentfarbe und überschrieb die kontextabhängigen Farben: 3,08:1 auf dunklem Grund, 4,36:1 im Fußbereich. Die Regel gilt jetzt nur für Links in Textblöcken, und die voreingestellte Linkfarbe liegt auf allen hellen Tönen über 4,5:1.
Eine offene Feststellung im Inhalt: npm run test:browser schlägt fehl, weil /grundlagen einen im Editor gesetzten Textblock in #d08080 auf hellem Grund trägt – 2,75:1, unter der AA-Schwelle. Die Revisionen stammen aus dieser Sitzung und nicht aus einem Testlauf (die Tests arbeiten auf eigenen Datenbanken). Die Farbe wurde nicht verändert, weil sie eine Nutzerentscheidung ist. Die Kontrastwarnung im Editor meldet genau diesen Fall.
Ergänzung: Direktbearbeitung, Kontrastwarnung, Vorlagen, 12.09.2026
- 155 PHP-Tests / 579 Assertions unter PHP 8.2.12 und PHP 8.4.22 erfolgreich, dazu 15 JavaScript-Modelltests.
- Erstmals wurde der neue Editor im laufenden Betrieb bedient, nicht nur sein Aufbau abgefragt. Geprüft: ein Doppelklick auf die Hauptüberschrift setzt das Element auf
contenteditable="plaintext-only", eine Texteingabe erreicht das Modell (der Speicherstatus wechselt auf „Ungespeicherte Änderungen“ und der Strukturbaum zeigt den neuen Text), und das Verlassen entfernt den Bearbeitungszustand wieder. Die Änderungen wurden anschließend verworfen; es wurde nichts gespeichert und keine echte Seite verändert. - Die Kontrastwarnung wurde mit echten Werten ausgelöst:
#ccccccauf#ffffffergibt „Kontrast 1.6:1 – zu wenig“ in der roten Stufe. Die Berechnung folgt der relativen Leuchtdichte aus WCAG 2.1 und löst Palettenverweise vorher auf. - Gestaltungsvorlagen über HTTP geprüft: anonymer Zugriff führt zur Anmeldung, das CSRF-Token ist Pflicht, ein Stil mit eingeschleuster Deklaration (
32px;position:fixed) und ein leerer Name werden mit HTTP 422 abgewiesen, ohne etwas zu schreiben; Speichern und Entfernen funktionieren. Damit kann über den Umweg Vorlage kein Wert in ein Dokument gelangen, für den ein Block abgewiesen würde. - Weiterhin keine axe- und keine Lighthouse-Messung und keine Erprobung mit einem Screenreader. Bei der Direktbearbeitung ist das ein besonderer Vorbehalt: ob der Fokus sinnvoll wandert und der Wechsel in den Bearbeitungszustand angekündigt wird, ist nicht nachgewiesen – geprüft ist nur, dass die Mechanik funktioniert.
Ergänzung: freie Gestaltung, 12.09.2026
- 154 PHP-Tests / 563 Assertions unter PHP 8.2.12 und PHP 8.4.22 erfolgreich, dazu 15 JavaScript-Modelltests.
- Ein v10-Dokument mit Palettenfarbe, eigenem Farbwert, Abständen je Seite, Ecken je Ecke, Schatten, Buchstabenabstand, Hover-Zustand und eigenem Mobilwert wird Byte für Byte gespeichert und zu blockgenauem CSS: Regel für den Block, eigene Regel für
:hover,:focus-withinund eine Media Query für die schmale Breite. - Vierzehn abgewiesene Eingaben schreiben nichts. Darunter gezielt die Ausbruchsversuche: eine Farbe als Funktion (
rgb(1,2,3)), eine Länge als Ausdruck (calc(1px + 2px)), eine angehängte Deklaration (18px;position:fixed), ein Schriftschlüssel mit Anführungszeichen und ein Hintergrundbild als Dateipfad. Jeder dieser Werte scheitert am verankerten Muster seines Typs, bevor er gespeichert wird. - Die Sicherheitsrichtlinie wurde eigens geprüft: das erzeugte Stylesheet ist über seinen eigenen SHA-256-Hash erlaubt,
unsafe-inlinekommt im Kopf nicht vor, und Skripte bleiben auf Seiten ohne Tabs abgeschaltet. Ein fremder Schrifthost wird nie erlaubt und nie kontaktiert: Schriften liefert seit 1.14.0 ausschliesslich der eigene Server (ADR 096). - Acht ungültige Themes werden abgewiesen, ohne das gespeicherte Theme zu verändern; danach liefert das Theme weiterhin die Voreinstellungen.
- Im Editormodell geprüft: Vererbung, einzelnes Zurücksetzen, Entfernen leerer Reste, Kopieren ohne geteilte Objekte und vollständiges Undo.
- Im Browser geprüft wurde nur der Aufbau, nicht die Bedienung. Im laufenden Editor wurde über das DOM bestätigt, dass das Designpanel aus dem Serverschema entsteht: sieben Gruppen, 58 Felder, 11 Farbwähler, 12 Schieberegler, 34 Einheitenauswahlen. Es wurde kein Gestaltungsvorgang von Hand ausgeführt, keine Tastaturbedienung erprobt und keine axe- oder Lighthouse-Messung gemacht. Für ein Werkzeug dieser Größe ist das ein erheblicher Vorbehalt.
- Die Bildschirmfotos des Vorschaufensters blieben bei der Editoransicht unbrauchbar (zu schmale Fläche, zeitweise leere Bilder). Die Beurteilung stützt sich deshalb auf DOM-Abfragen und die erzeugte Ausgabe, nicht auf Augenschein.
Ergänzung: SEO und maschinelle Zugänglichkeit, 12.09.2026
- 128 PHP-Tests / 507 Assertions unter PHP 8.2.12 und PHP 8.4.22 erfolgreich, dazu 14 JavaScript-Modelltests.
- Sitemap geprüft: wohlgeformtes XML, enthält weder eine
noindex-Seite noch einen unveröffentlichten Entwurf, dafür Startseite, indexierbare Seiten, Beitragsübersicht und Begriffsarchiv.robots.txtverweist auf die Sitemap und sperrt/admin. Dieselbenoindex-Seite trägt zusätzlich einnoindex-Meta, eine indexierbare Seite keines. - Weiterleitungen geprüft: 301 mit Zielangabe und 410 ohne, beide vor dem 404; eine vorhandene Seite gewinnt gegen eine gleichnamige Weiterleitung; Selbstbezug, Weiterleitungskette, Großbuchstaben im Pfad und ein anderer Statuscode als 301 oder 410 werden abgewiesen, ohne etwas zu schreiben.
- Strukturierte Daten geprüft: ohne gepflegte Unternehmensdaten wird kein Block ausgegeben. Danach
LocalBusinessmit Anschrift und Ländercode, doppelte Profile entdoppelt, und kein Feld ohne gepflegten Wert. Ein Beitrag trägtArticlemit Überschrift und Autor aus seinen Metadaten, eine UnterseiteBreadcrumbListmit absoluten Adressen. Die Brotkrumen erscheinen erst ab zwei Ebenen. llms.txtantwortet ausgeschaltet mit HTTP 404 und listet eingeschaltet weder einenoindex-Seite noch einen Entwurf.- Fünf ungültige Unternehmensangaben (E-Mail, Telefon, Ländercode, unsicheres Profil, lokales Unternehmen ohne Anschrift) schreiben nichts. In
robots.txtüberleben weder Markup noch eine zweiteSitemap:-Zeile aus dem Freitextfeld. - Ein bestehender Flattermacher im Testabbau wurde behoben: unter Windows gab ein Kernel den Dateizeiger auf die Testdatenbank manchmal erst kurz nach dem Herunterfahren frei, wodurch das Aufräumen mit einer Warnung fehlschlug und den ganzen Lauf rot färbte. Der Abbau wartet jetzt kurz und lässt die temporäre Datei notfalls dem Betriebssystem.
- Erstmals seit Paket A wieder im Browser angesehen – auf ausdrücklichen Wunsch, und ausdrücklich keine Messung: eine lokale Demoseite mit allen neuen Bausteinen wurde im Produktionsmodus aufgerufen und die Ausgabe geprüft. Kennzahlen, Symbolkarten mit Inline-SVG, Kundenstimme, Akkordeon, Kontaktdaten, Formular und Aufruf-Band erscheinen wie vorgesehen, die Tabs zeigen mit aktivem JavaScript nur den gewählten Abschnitt. Das ist eine Sichtprüfung, kein Audit: es liegen weiterhin keine axe- und keine Lighthouse-Ergebnisse für die Pakete B bis E vor, und die Bildschirmfotos des Vorschaufensters waren auf langen Seiten unzuverlässig, sodass Teile nur über die Auszeichnung und die gemessenen Elementhöhen beurteilt wurden.
- Kosmetisch aufgefallen: eine Symbolkarte innerhalb einer Spalte zeigt zwei ineinanderliegende Rahmen, weil Spalte und Karte je einen eigenen Rahmen haben. Nicht behoben, weil es eine Gestaltungsentscheidung ist und keine Fehlfunktion.
Ergänzung: Formulare, 12.09.2026
- 117 PHP-Tests / 450 Assertions unter PHP 8.2.12 und PHP 8.4.22 erfolgreich, dazu 14 JavaScript-Modelltests.
composer auditmeldet keine bekannten Advisories, auch nach Aufnahme vonsymfony/mailer. - Vollständiger Ablauf geprüft: Ausgabe ohne Skript, gültige Absendung wird gespeichert und mit HTTP 303 zurückgeleitet, damit ein Neuladen nichts doppelt sendet, und die Erfolgsmeldung erscheint auf der Zielseite.
- Datenschutz gezielt geprüft: in der gespeicherten Zeile steht keine Absenderadresse, sondern ein 64-stelliger Hash; der Zeitpunkt der Einwilligung wird getrennt festgehalten.
- Fehlerhafte Absendung: HTTP 422, nichts gespeichert und nichts gesendet, vier Meldungen an den richtigen Feldern, verbunden über
aria-describedbyundaria-invalid, genau eine Zusammenfassung mitrole=alert, und sämtliche Eingaben bleiben erhalten. - Vier Spamfälle werden still verworfen, ohne zu speichern, und wie ein Erfolg beantwortet: gefüllter Honeypot, Absendung innerhalb der Mindestzeit, gefälschte Zeitstempelsignatur und ein zu alter Zeitstempel. Das Limit stoppt die sechste Absendung innerhalb einer Stunde.
- Die Formularverwaltung verlangt Anmeldung, Editorrolle und CSRF-Token; eine ungültige Empfängeradresse wird mit einer Meldung abgewiesen statt gespeichert.
- Ein echter Fehler wurde dabei gefunden und behoben: das Stundenfenster des Limits entstand aus der lokalen Uhrzeit, die Zeitstempel der Einsendungen aber aus UTC. Auf einer Uhr vor UTC – etwa in Deutschland – hätte das Limit nie gegriffen und der Spamschutz wäre an dieser Stelle wirkungslos gewesen. Beide Seiten rechnen jetzt in UTC; der Test deckt genau diesen Fall ab.
- Der E-Mail-Versand wurde nie wirklich ausgeführt. Die Tests nutzen einen Transport, der nichts sendet. Ob
sendmailauf dem Zielhosting funktioniert, ob Nachrichten zugestellt werden und ob sie im Spamordner landen, ist damit vollständig offen und gehört zu Arbeitspaket J. - Auch für diesen Schritt wurden auf Wunsch des Nutzers keine Browser-, axe- und Lighthouse-Läufe ausgeführt. Formularausgabe und Verwaltung sind nicht visuell und nicht mit einem Screenreader geprüft. Gerade bei Formularen ist das ein erheblicher Vorbehalt: die Fehlerauszeichnung ist im Markup korrekt gesetzt, aber nicht in einer echten Hilfstechnik gehört worden.
Ergänzung: Tabs, 12.09.2026
- 109 PHP-Tests / 395 Assertions unter PHP 8.2.12 und PHP 8.4.22 erfolgreich, dazu 14 JavaScript-Modelltests.
- Geprüft, dass die Seite ohne JavaScript vollständig bleibt: beide Panels stehen mit Inhalt und Überschrift im HTML, keines ist serverseitig versteckt, und die Ankerliste verweist auf sie. Verstecken ist ausschließlich Aufgabe des Skripts.
- Die Sicherheitsrichtlinie wurde gezielt geprüft:
script-src 'self'erscheint nur auf der Seite, die tatsächlich einen Tab-Block enthält. Eine Seite ohne Tabs und die 404-Seite senden weiterhinscript-src 'none'und laden kein Skript. Das Skript wird als externe Datei eingebunden; Inline-Skript kommt nicht vor. - Abgewiesen werden ein Tab außerhalb einer Tabgruppe (auch auf oberster Dokumentebene), eine Tabgruppe mit einem Textkind und Tabs in einem v6-Dokument.
- Im Editormodell geprüft: eine neue Tabgruppe bringt zwei Tabs mit eigenen IDs mit, nimmt ausschließlich Tabs auf, und ein Tab lässt sich weder in eine Sektion noch in ein Akkordeon einfügen; ein Tab selbst nimmt gewöhnlichen Inhalt auf.
- Das Skript selbst wurde nicht ausgeführt. Pfeiltastenbedienung,
aria-selected, das Umschalten der Panels und die Auswahl über ein Sprungziel sind im Code umgesetzt, aber ohne Browserlauf weder funktional noch auf Barrierefreiheit geprüft. Für ein Tab-Widget ist das ein erheblicher Vorbehalt: gerade die Tastaturbedienung und die ARIA-Rollen sind der Grund, warum diese Umsetzung überhaupt gewählt wurde. Ein Browserlauf steht dafür aus.
Ergänzung: Blöcke für die Pilotseite, 12.09.2026
- 107 PHP-Tests / 380 Assertions unter PHP 8.2.12 und PHP 8.4.22 erfolgreich, dazu 13 JavaScript-Modelltests.
- Eine Testseite aus allen zehn neuen Abschnittsarten wird Byte für Byte gespeichert, veröffentlicht und ausgegeben. Geprüft sind die erzeugten
tel:- undmailto:-Verweise samt bereinigter Telefonnummer, das Akkordeon als echtesdetails-Element mitsummary, Symbole als Inline-SVG, die für Screenreader ausgeschriebene Bewertung und die Abwesenheit vonscriptin der Ausgabe. - Vierzehn abgewiesene Eingaben schreiben nichts: unbekanntes Symbol, fehlender Titel,
javascript:-Linkziel, Bewertung außerhalb 0–5 sowie als Zeichenkette statt Zahl, leerer Kontaktblock, ungültige Telefonnummer, ungültige E-Mail-Adresse, unbekannte Abstandsgröße, unerlaubtes Linkschema am Aufruf-Band, Text in einer Logoleiste, Text direkt in einem Akkordeon, Akkordeon-Eintrag ohne Akkordeon und Kinder an einer Trennlinie. Zusätzlich abgesichert, dass die neuen Blöcke in Schema v5 weiterhin abgewiesen werden. - Zwei echte Fehler wurden durch diese Tests gefunden und behoben. Im Validator griff die Regel „ein Akkordeon-Eintrag gehört in ein Akkordeon“ nicht auf oberster Dokumentebene, weil sie nur beim Durchlaufen der Kinder lief; sie sitzt jetzt an der Typprüfung selbst. Im JavaScript-Test wurde
history.document.blocksvorhistory.change()ausgewertet und damit im vorherigen Dokumentstand gesucht – ein Fehler im Test, nicht im Modell, aber einer, der bei umgekehrtem Ausgang eine falsche Bestätigung erzeugt hätte. - Im Editormodell geprüft: ein neues Akkordeon bringt einen Eintrag mit, damit es nie leer ausgegeben wird; ein Eintrag lässt sich nur in ein Akkordeon einfügen und nirgendwo sonst; eine Logoleiste nimmt nur Bilder; Blattblöcke bleiben Blätter und behalten ihre Vorgabewerte; das vollständige Rückgängigmachen stellt den Ausgangszustand her.
composer lint,lint:twig,lint:yaml,lint:containerund die Syntaxprüfung der Editormodule sind erfolgreich. Die erzeugtedesign.cssbleibt unverändert, obwohl das Tokenmanifest neue Typen führt, und der bestehende Abgleich zwischen Manifest und Stylesheet greift weiterhin.- Auch für diesen Schritt wurden auf Wunsch des Nutzers keine Browser-, axe- und Lighthouse-Läufe ausgeführt. Für die zehn neuen Blöcke liegt damit keine visuelle Kontrolle, keine Barrierefreiheitsprüfung und keine Messung vor. Das wiegt hier schwerer als in den Schritten davor, weil es sich um sichtbare Gestaltungsbausteine mit eigenem CSS handelt; die Aussagen oben betreffen ausschließlich die erzeugte Auszeichnung.
Ergänzung: Beiträge, 12.09.2026
- 91 PHP-Tests / 347 Assertions unter PHP 8.2.12 und PHP 8.4.22 erfolgreich, dazu 12 JavaScript-Modelltests.
- Archiv geprüft: Sortierung nach Datum über mehrere Seiten, Begrenzung zu großer und negativer Seitenzahlen auf den gültigen Bereich statt einer leeren Ausgabe, gewöhnliche Seiten und unveröffentlichte Beiträge erscheinen nicht, Canonical und Datumsausgabe stimmen.
- Kategorien und Schlagwörter geprüft: eigene Archive, getrennte Namensräume (ein Schlagwort-Slug ist keine Kategorie), unbekannter Begriff ergibt HTTP 404, erneutes Speichern ersetzt die Zuordnung statt sie zu ergänzen, und ein dadurch leer gewordenes Archiv antwortet weiter mit HTTP 200 und leerer Liste. Beim Löschen einer Seite verschwinden ihre Zuordnungen, die Begriffe selbst bleiben erhalten.
- Der Block
postlistwurde gezielt darauf geprüft, dass er keine Beitragsdaten speichert. Das gespeicherte Dokument enthält nach dem Veröffentlichen ausschließlich Anzahl und Filter; die angezeigten Beiträge stellt der Controller zusammen. Ein Beitrag aus einer anderen Kategorie erscheint nicht. Damit kann ein gespeichertes Dokument keinen unveröffentlichten Beitrag zeigen. - Feed geprüft: wohlgeformtes XML (
simplexml_load_string), absolute Adressen, Kategorien alscategory-Elemente, kein unveröffentlichter Beitrag. - Sechs abgewiesene Metadateneingaben (zu langer Auszug, zu langer Autorname, falsches Datumsformat, unbekanntes und fehlerhaftes Beitragsbild, unbrauchbarer Begriffsname) schreiben nichts und erhöhen die Seitenversion nicht.
- Veröffentlichen stempelt ein fehlendes Beitragsdatum, lässt ein gepflegtes unangetastet und rührt gewöhnliche Seiten nicht an.
- Migration
20260912000600zuerst gegen eine Kopie der lokalen Datenbank ausgeführt und kontrolliert, danach nach Backup (var/backups/before-posts-*.db) angewendet.composer lint,lint:twig,lint:yaml,lint:containerund wiederholtes Seeding sind erfolgreich. - Auch für diesen Schritt wurden auf Wunsch des Nutzers keine Browser-, axe- und Lighthouse-Läufe ausgeführt. Archivseiten, Beitragsliste, Paginierung und das Formular für Beitragsdaten sind nicht visuell, nicht auf Barrierefreiheit und nicht auf Leistung geprüft. Insbesondere liegt für die Archivseiten keine Messung vor.
Ergänzung: Menüs, 12.09.2026
- 79 PHP-Tests / 285 Assertions unter PHP 8.2.12 und PHP 8.4.22 erfolgreich, dazu 11 JavaScript-Modelltests.
- Geprüft, dass die Navigation nicht mehr aus dem Template stammt: die ausgegebenen Links der Hauptnavigation entsprechen genau den gespeicherten Menüeinträgen. Seiten-, Anker- und externe Ziele einschließlich
tel:werden korrekt gebildet,aria-currenterscheint nur auf der tatsächlich aktuellen Seite und nicht auf einem Ankereintrag derselben Seite. - Geprüft, dass eine gelöschte und eine noch unveröffentlichte Seite aus der Navigation fallen, ohne die übrigen Einträge zu verlieren, dass die Kinder eines übersprungenen Eintrags nachrücken und dass der gespeicherte Baum unangetastet bleibt: nach dem Veröffentlichen erscheint der Eintrag wieder. Ein Entwurf wird über das Menü nicht öffentlich.
- Zehn abgewiesene Eingaben schreiben nichts in die Datenbank: leere und überlange Beschriftung, unbekannte Zielart, fehlende Seite, Sprungziel mit Rautezeichen, Sprungziel mit führender Ziffer,
javascript:,http:, protokollrelative Adresse und eine dritte Ebene. Dazu unbekannter Platz, Überschreitung der Eintragsgrenze und ein veralteter Schreibstand. - Über HTTP geprüft: anonymer Schreibversuch führt zur Anmeldung, CSRF-Token ist Pflicht, ein veralteter Versionsstand überschreibt kein neueres Menü, und der Baum entsteht korrekt aus flachen Formularzeilen über Position und Ebene, einschließlich normalisiertem Sprungziel und ignorierter Leerzeile.
- Migration
20260912000500zuerst gegen eine Kopie der lokalen Datenbank ausgeführt, dann nach Backup (var/backups/before-menus-*.db) angewendet. Wiederholtes Seeding legt fehlende Menüs an und lässt vorhandene unverändert.composer lint,lint:twig,lint:yamlundlint:containersind erfolgreich. - Ein Fehler in der Testumgebung wurde dabei sichtbar und behoben. Das Testkernel läuft ohne Debug; Symfony prüft dann weder den kompilierten Container noch die Vorlagen auf Aktualität. Ein geänderter Konstruktor schlug mit einem
TypeErroraus einem veralteten Container fehl, zuvor war bereits eine Vorlagenänderung übergangen worden.tests/bootstrap.phpverwirftvar/cache/testjetzt einmal pro Lauf. Damit gilt für frühere Berichte: Ergebnisse, die vor dieser Behebung entstanden sind, wurden unter einer Bedingung gemessen, die einen veralteten Cache nicht ausschloss. Die hier berichteten Läufe entstanden nach der Behebung. - Auch für diesen Schritt wurden auf Wunsch des Nutzers keine Browser-, axe- und Lighthouse-Läufe ausgeführt. Die Menüverwaltung und die Aufklappmenüs in der Ausgabe sind nicht visuell, nicht auf Barrierefreiheit und nicht auf Leistung geprüft.
Ergänzung: Erhalt unbekannter Blöcke, 12.09.2026
- 64 PHP-Tests / 229 Assertions unter PHP 8.2.12 und PHP 8.4.22 erfolgreich, dazu 11 JavaScript-Modelltests.
- Geprüft, dass ein v4-Dokument mit einem Baustein
acme.slidersamt verschachteltem Text unverändert gespeichert, veröffentlicht und wieder geladen wird, und dass aus diesem Block nichts in die öffentliche Ausgabe gelangt: weder seine ungeprüften Props noch seine Kindinhalte noch eine darin abgelegtejavascript:-URL. Die übrige Seite rendert normal. Sechs fehlerhafte Namensraumformen sowie Plugin-Blöcke in den Schemaversionen v1 bis v3 werden weiterhin vor jedem Schreibzugriff abgewiesen. - Im JavaScript-Modell geprüft: Erkennung des Namensraums, Beschriftung und Symbol ohne Wörterbucheintrag, kein Einfügen in den Baustein, keine Erzeugung über die Elementbibliothek, Verschieben und Duplizieren mit neuen IDs bei unveränderten Props sowie ein vollständiges Undo auf den Ausgangszustand.
- Beim Schreiben dieser Tests wurde ein Fehler in der Testumgebung sichtbar: das Testkernel läuft ohne Debug, wodurch eine im Cache liegende kompilierte Twig-Vorlage den Ausgang des Laufs bestimmen konnte. Twig lädt in der Testumgebung jetzt automatisch neu; die Wirkung wurde gegengeprüft, indem die Vorlage bewusst verändert wurde und der Test daraufhin fehlschlug.
composer lint,lint:twig,lint:yaml,lint:containerund die Syntaxprüfung der Editormodule sind erfolgreich.- Auch für diesen Schritt wurden auf Wunsch des Nutzers keine Browser-, axe- und Lighthouse-Läufe ausgeführt. Der Platzhalter in der Editorvorschau und der Hinweis im Eigenschaftenpanel sind nicht visuell geprüft.
Ergänzung: Seitenerstellung und Adresshierarchie, 12.09.2026
- 56 PHP-Tests / 212 Assertions unter PHP 8.2.12 und PHP 8.4.22 erfolgreich, dazu 10 JavaScript-Modelltests. Neu gegenüber dem vorigen Stand sind 15 Tests zu Seitenerstellung, Adresshierarchie, Löschen und Zugriffsrechten; die Liste steht in STATUS.
- Migration
20260912000400zuerst gegen eine Kopie der lokalen Datenbank ausgeführt und die erzeugten Anweisungen geprüft: vier reineALTER TABLE … ADD COLUMN, kein Tabellenneuaufbau und damit kein Konflikt mit dem Fremdschlüsselrevision.page_id. Backfill, Wegfall des alten eindeutigen Slug-Index und Anlage vonuniq_page_pathundidx_page_parentkontrolliert. Anschließend nach konsistentem Backup (var/backups/before-hierarchy-20260912-102402.db) auf die lokale Datenbank angewendet; die drei vorhandenen Seiten und ihre Dokumente sind unverändert. composer lint(PHP-CS-Fixer),lint:twig,lint:yaml,lint:container, wiederholtescms:seed-demound der Produktionscacheaufbau sind erfolgreich.- Für diesen Schritt wurden auf Wunsch des Nutzers keine Browser-, axe- und Lighthouse-Läufe ausgeführt. Die neuen Formulare für Anlegen und Löschen sind über Funktionstests geprüft (Formulare werden dort tatsächlich abgeschickt), aber nicht visuell, nicht auf Barrierefreiheit und nicht auf Leistung. Die zuletzt gemessenen Lighthouse- und axe-Ergebnisse gelten für den vorigen Stand und schließen die Verwaltungsoberfläche dieses Schritts nicht ein.
- Beim Testen wurde ein bestehender Fehler in der Testumgebung behoben: die Zähler des Login-Throttlings lagen im dauerhaften Cache und sperrten nach mehreren Testläufen die Anmeldung aus. In der Testumgebung nutzt der Rate-Limiter jetzt einen Array-Cache; die Drosselung selbst bleibt aktiv und wird weiterhin getestet. Zwei aufeinanderfolgende Läufe ohne Cachelöschung waren erfolgreich.
- Weiterhin offen: MySQL/MariaDB, tatsächliches Hosting, Felddaten, vollständige manuelle Barrierefreiheitsprüfung und repräsentative Kundeninhalte.
Ergänzung: Medienverwaltung, Galerie und Effekte, 12.09.2026
- 41 PHP-Tests / 155 Assertions unter PHP 8.2.12 und 8.4.22 sowie 10 JavaScript-Modelltests bestanden. Neu: geschützte Medien-API/CSRF, als JPEG getarnte SVG-Abweisung, tatsächliche Bilddecodierung/Neuencodierung, entfernte angehängte Nutzdaten, drei WebP-Varianten, Metadata-CAS/409, Archivieren/Wiederherstellen und weiter erreichbare Bilddateien. Zusätzlich ungültige Effekt-/Schemaschlüssel, Galerie-Kindtypen und
srcset-Quellen sowie v3-Undo und Galerie-Verschieberegeln geprüft. - Isolierter Browserablauf mit eigenen Datenbanken/Medienordnern bestanden: Upload von zwei lokal erzeugten Testillustrationen, Titel und Alt-Texte speichern, Mehrfachauswahl per Tastatur mit Fokus-Erhalt, Galerieeinfügen, Bildbeschriftung, Sortieren/Undo, responsive Spalten, Schatten/Hover/Einblendung und Bewegungsreduktion. Archivieren erhält URLs, Wiederherstellen erlaubt erneute Auswahl. Bilder und Bildquellen bleiben nach Speichern/Neuladen/Publizieren funktionsfähig. Bestehende Rechte-, Netzwerk-/Konflikt- und Editorprüfungen weiterhin erfolgreich.
- Keine axe-Verstöße in Medienauswahl und mobiler Mediathek sowie den bisherigen Login-/Seiten-/Editor- und öffentlichen Prüfungen. Desktop- und Mobil-Mediathek und öffentliche Galerieseite anhand der Screenshots geprüft. Alle drei bestehenden öffentlichen Seiten erneut mit/ohne JavaScript und bei 1440/390 px geprüft. Sandbox-Prüfgrenze weiterhin wie unten beschrieben; keine vollständige manuelle Screenreader-Abnahme.
- Lighthouse 13.4.1: drei mobile und drei echte Desktopläufe auf der veröffentlichten v3-Galerieseite; alle fünf Kategoriescores in jedem Lauf 100. LCP-Median mobil 937 ms, Desktop 279 ms, CLS 0, TBT 0 ms. PHP 8.2.12, SQLite, lokaler Produktionsmodus, GD-generierte Landschaftsillustrationen mit WebP-Varianten statt realer Kundenfotos. Rohdaten
reports/lighthouse-editor, Metadatendocs/quality/editor-media-lighthouse.json, Browserberichtdocs/quality/editor-media-browser.json. Reproduktion übernpm run test:editor -- --audit. - Migration 003 zuerst in Tests, anschließend lokal nach konsistentem SQLite-Backup angewendet. Keine Umschreibung echter Seitendokumente, keine Testuploads in den echten Medienordner, kein Browser-Neuladen des Nutzerentwurfs. Lokaler PHP-Prozess anschließend mit 8M Upload-/10M POST-/256M Speicherlimit gestartet. PHP-Format-, Twig-/YAML-/Container-, Composer- und Produktionsbuild-Prüfungen bestanden; Composer meldet keine bekannten Advisories.
Die öffentlichen Medien-URLs waren im ersten Browserlauf wegen des lokalen PHP-Servers mit .webp-Suffix nicht an den Frontcontroller weitergegeben worden. Erweiterungslose Routen beheben dies; tatsächliches Laden der Bilddateien wird jetzt ausdrücklich im Browser geprüft. Keine Hosting-/MySQL-/Restore-Abnahme, keine Felddaten und keine Aussage über beliebige hochgeladene Bilder oder Effekte auf Kundenwebsites.
Ergänzung: responsive Editorgestaltung, 12.09.2026
- 34 PHP-Tests / 120 Assertions unter PHP 8.2.12 und 8.4.22 erfolgreich. Zusätzlich zu den Sicherheits-/Revisionsprüfungen: v1/v2 lesen und speichern, originale Veröffentlichung erhalten, v1 wiederherstellen, validierte Gestaltungsklassen ohne Inline-CSS/JavaScript sowie Zurückweisung falscher Geräte, ungeeigneter Blockeigenschaften, unbekannter Tokens und zukünftiger Versionen.
- 9 JavaScript-Modelltests erfolgreich: ergänzt um idempotente, inhaltserhaltende Migration; Gerätevererbung/Reset/Undo; atomare Vorlagen mit neuen IDs und genau einer H1; Abgleich des generierten CSS mit dem zentralen Tokenmanifest.
- Erweiterter Playwright-Ablauf auf eigener Datenbank erfolgreich: einklappbare Struktur/Werkzeugkasten, Suche und Auswahl per Tastatur, Schriftgröße/Ausrichtung/Abstände auf Desktop/Tablet/Mobil, echte Iframebreiten, Vererbung und Zurücksetzen samt Undo, Zweispaltenvorlage mit mobilem Umbruch. Danach Speichern, Neuladen und Veröffentlichen; berechnete öffentliche Styles auf 1600/768/390 px gegen die Vorschauwerte geprüft. Bestehende Fehler-/Konflikt-/Drag-and-drop-Prüfungen bleiben Bestandteil des Ablaufs.
- Keine axe-Verstöße in Login, Seitenliste, Desktop-/Mobil-Editor und gestalteter öffentlicher Mobilseite. Screenshotkontrolle von Desktop-Editor, Mobil-Editor und veröffentlichter Mobilseite erfolgreich; kein horizontaler Überlauf. Die unten beschriebene Einschränkung der scriptgesperrten Frameprüfung gilt weiterhin. Kompaktbericht:
docs/quality/editor-design-browser.json. - Alle drei bestehenden öffentlichen v1-Beispielseiten erneut bei 1440/390 px geprüft; sechs erfolgreiche Accessibility-Prüfungen plus Tastatur- und Navigation ohne JavaScript.
- Lighthouse 13.4.1 auf der isolierten, veröffentlichten v2-Seite, einschließlich Design-CSS und eingefügter responsiver Abschnittsvorlage: drei mobile und drei echte Desktopläufe, alle fünf Kategoriescores in jedem Lauf 100. LCP-Median mobil 901 ms, Desktop 240 ms, CLS 0, TBT 0 ms. Produktionsmodus, PHP 8.2.12, SQLite und lokaler PHP-Server; Chromium/Profilparameter im Bericht
docs/quality/editor-design-lighthouse.json, Rohdaten unterreports/lighthouse-editor. Der Test läuft reproduzierbar mitnpm run test:editor -- --auditund ist in CI vorgesehen; externe CI weiterhin nicht ausgeführt. - PHP-Format-, Twig-/YAML-/Containerprüfungen, JavaScript-Syntaxprüfung, Diff-Prüfung und Produktionscacheaufbau erfolgreich. Die zusätzlichen Designressourcen werden nur für v2-Dokumente geladen. Auf dem PHP-Hosting ist kein Node-Prozess nötig.
Weiterhin kleine lokale Testinhalte: keine Pilotkundenabnahme, keine Felddaten/INP-Aussage, keine umfassende Screenreaderprüfung und kein Nachweis für beliebige Gestaltungsentscheidungen. PHP-Webhosting und MySQL/MariaDB bleiben ungeprüft. Der echte Seitenbestand und der bereits geöffnete Browserentwurf wurden nicht für Tests geändert.
Die folgenden Abschnitte dokumentieren die früheren Entwicklungsstände und deren damalige Messungen.
Ergänzung: erster visueller Editor, 12.09.2026
Die folgenden Ergebnisse betreffen den neuen Editor; die ursprüngliche Phase-0-Messung bleibt darunter als Ausgangsstand erhalten.
- 27 PHP-Tests, 105 Assertions, erfolgreich unter PHP 8.2.12 und 8.4.22. Ergänzt: geschützte Admin-/API-Routen, Login-CSRF und falsches Passwort, CSRF für alle Schreib-/Vorschauaktionen, Editor ohne Veröffentlichungsrecht, HTTP-422/409-Behandlung, konkrete Revisionsprüfung, privater Entwurf und anschließende Veröffentlichung, Logout-CSRF, Passwort-Rehash und Sessioninvalidierung bei Rollenänderung.
- 5 JavaScript-Modelltests für Undo/Redo samt Speicherpunkt, Zusammenfassung von Texteingaben, unveränderte History-Snapshots, neue IDs beim Duplizieren, Zyklenschutz beim Verschieben und identischen JSON-Roundtrip.
- End-to-End-Editorprüfung mit Playwright: echte Formularanmeldung, Klickauswahl im Iframe, Eigenschaftenänderung und Live-Vorschau, Undo/Redo, Einfügen/Duplizieren/Verschieben einschließlich Drag-and-drop/Löschen, Speichern und identisches Neuladen, Entwurfsprivatheit, separate Veröffentlichung, Escape/Fokusrückkehr im Dialog, abgefangener Netzwerkabbruch mit erneutem Speichern, 409-Konflikt ohne Verlust lokaler Änderungen, JSON-Download und bestätigtes Laden des Serverstands. Eigene Testdatenbank und Zufallszugänge unter
var/browser-tests; echte Seiten und Benutzer bleiben durch diese Tests unverändert. - axe-core: keine gefundenen Verstöße in Login, Seitenübersicht, Desktop- und Mobil-Editor sowie separat in der bearbeiteten öffentlichen Ausgabe. Die scriptgesperrte Vorschau kann den axe-Frameworker nicht ausführen. Der Frameinhalt wird deshalb in der Editor-axe-Prüfung ausgeschlossen und seine identische öffentliche Ausgabe separat geprüft; die Frameauswahl und Bearbeitung sind weiterhin funktional im realen Sandbox-Iframe getestet. Diese Einschränkung ist keine vollständige Barrierefreiheitsabnahme.
- Visuell geprüft: Editor-Desktop bei 1600 × 1100 und Mobil bei 390 × 844, Screenshots unter
reports/editor. Scrollbereich ist per Tastatur fokussierbar. Keine horizontalen Überläufe in der Mobilprüfung. - Öffentliche Browser-Regression: alle drei unveränderten Beispielseiten bei 1440 und 390 px erfolgreich, kein Editor-JavaScript und kein zusätzliches Session-Cookie auf der öffentlichen Route.
- Erneute Lighthouse-13.4.1-Messung mit drei echten Mobil-/Desktop-Läufen im Produktionsmodus: jeweils 100 in allen fünf Kategorien. LCP-Mediane jetzt mobil 803 ms, Desktop 252 ms, CLS 0 und TBT 0 ms. Gleiches kleines lokales Testszenario und dieselben Grenzen wie unten; keine reale Kundenabnahme oder Felddaten. Metadaten:
docs/quality/editor-public-lighthouse.json. - Composer Audit ohne bekannte Advisories; Composer-Validierung, PHP-Formatierung, Twig-/YAML-/Containerprüfung, JavaScript-Syntaxprüfung erfolgreich. CI wurde um Modell- und Editorprüfungen ergänzt, aber nicht extern ausgeführt. MySQL/MariaDB/Hosting bleiben ungetestet.
Der lokale Benutzer umut wurde getrennt von den Tests auf ausdrücklichen Nutzerwunsch angelegt und im In-App-Browser angemeldet. Keine Zugangsdaten in Quellen oder Dokumentation abgelegt.
Datum: 12.09.2026. Ziel: http://127.0.0.1:8080/. Diese Messung betrifft ausschließlich die lokale KantSites-Demoseite, keine bestehende Kundenwebsite und nicht kant-it.de.
Tatsächlich ausgeführte Prüfungen
- PHPUnit 11.5.56: 19 Tests, 35 Assertions erfolgreich unter PHP 8.2.12 und PHP 8.4.22. Dokument-Roundtrip, Entwurfsprivatheit, abgewiesene veraltete Schreibzugriffe, Transaktionsrollback, fremde Revisionen, Wiederherstellung, XSS-Maskierung, ungültige URLs/Designwerte/Block-IDs, Canonical, 404 und verweigerte HTTP-Schreibmethoden.
- Composer-Validierung, PHP-Formatprüfung, Twig-/YAML-/Containerprüfung und produktiver Cacheaufbau erfolgreich. Composer Audit und npm install meldeten keine bekannten Paketlücken zum Prüfzeitpunkt.
- Frische Kopie der für Git vorgesehenen Quellen unter
var/fresh-check:composer install --no-dev, Setup, erste Migration, Seeding zweimal, Produktionscache und Symfony-Request erfolgreich. Gespeicherter Inhalt erscheint mit HTTP 200; zweites Seeding verändert vorhandene Seiten nicht. - Playwright 1.63.0 / Chromium 153.0.8010.12 und axe-core 4.13.0:
/,/grundlagen,/projektstand, jeweils mit 1440 und 390 px Breite; keine axe-Verstöße in den ausgewählten WCAG-2-A/AA-, WCAG-2.1-AA- und Best-Practice-Regeln. Je Kombination 29 bestandene axe-Prüfungen. Kein horizontaler Überlauf oder JavaScript-Seitenfehler. - Automatisierte Tastaturprüfung des Sprunglinks und Navigation, zusätzlich Navigation mit deaktiviertem JavaScript erfolgreich. Desktop- und Mobil-Screenshots der Startseite visuell durchgesehen.
Lighthouse
Lighthouse 13.4.1, Chromium Headless 153.0.8010.12 unter Windows; PHP 8.4.22 mit APP_ENV=prod, APP_DEBUG=0, vorgewärmtem Symfony-Cache, SQLite, lokalem PHP-Entwicklungsserver. Vollständige gespeicherte HTML-Inhalte, keine externen Dienste, keine Editor-Ressourcen. Netzwerk-/CPU-Drosselung simuliert. Drei Läufe je Profil, Median:
| Profil | Leistung | Barrierefreiheit | Best Practices | SEO | Agentisches Browsing | LCP | CLS | TBT |
|---|---|---|---|---|---|---|---|---|
| Mobil | 100 | 100 | 100 | 100 | 100 | 797 ms | 0 | 0 ms |
| Desktop | 100 | 100 | 100 | 100 | 100 | 261 ms | 0 | 0 ms |
Alle sechs endgültigen Läufe hatten diese Kategoriescores. Mobil: 412 × 823 px, DPR 1,75, RTT 150 ms, 1.638,4 Kbit/s Durchsatz, CPU-Faktor 4. Desktop: 1350 × 940 px, DPR 1, RTT 40 ms, 10.240 Kbit/s Durchsatz, CPU-Faktor 1. Detailparameter und Umgebungsmetadaten stehen in docs/quality/lighthouse-summary.json. Das Skript prüft die tatsächliche formFactor-Einstellung und lehnt indexierungsgesperrte Antworten vor dem Audit ab.
Agentisches Browsing: Die anwendbaren Prüfungen agent-accessibility-tree und cumulative-layout-shift bestanden. webmcp-form-coverage, webmcp-registered-tools, webmcp-schema-validity und llms-txt waren nicht anwendbar, nicht als implementierte Funktionen bestanden. Es gibt noch keine Formulare, WebMCP-Tools oder llms.txt.
Grenzen und noch ausstehende Abnahme
- Die kleine Demoseite hat bewusst keine echten Kundenbilder, Blogbeiträge oder Formulare. Deshalb ist sie nur eine technische Regressionsbasis und erfüllt noch nicht die im Plan geforderte repräsentative Referenzsuite. Die Werte nicht als Leistungsnachweis für Kundenwebsites verwenden.
- INP und die Core-Web-Vitals-Feldwerte am 75. Perzentil sind unbekannt. Der gemessene TBT ist kein INP. Es gibt keine realen Nutzungsdaten.
- Manuelle Screenreader-Prüfung, vollständige manuelle Tastatur-/Kontrast-/Zoomprüfung, Dialoge, Formulare und responsive Editorabläufe fehlen. Visuelle Screenshotkontrolle und automatisierte axe-Prüfungen ersetzen sie nicht.
- MySQL-/MariaDB-Betrieb, Apache-Rewrites, tatsächliches PHP-Webhosting, HTTPS-Konfiguration, Restore und externe CI-Ausführung wurden nicht getestet. Ein MySQL-Smokejob ist vorbereitet.
- GEO, Auffindbarkeit und Zitierung in KI-Antworten wurden nicht geprüft. Keine Ranking- oder Zitiergarantie.
- Die rohe Auditserie und Browser-Screenshots liegen lokal in
reports/und sind nicht für Git vorgesehen. Die kompakte Zusammenfassung und dieser Bericht werden mit den Quellen abgelegt.
Im Verlauf behoben
Mobiler Textüberlauf bei langen deutschen Wörtern; fehlende Übernahme realer Prozessvariablen bei PHP-Konfiguration ohne E in variables_order (dadurch blieb Debug/noindex aktiv); anfänglich falsch übergebener Desktop-Preset an die Lighthouse-Programmierschnittstelle; unter Windows gesperrte temporäre Testdatenbank sowie Cleanup des anfänglichen Chrome-Launchers. Die endgültigen oben dokumentierten Prüfungen liefen nach diesen Korrekturen erfolgreich.