Files
KantSites/docs/STATUS.md
T
kantarciandClaude Opus 5 9f1ac39251
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s
Doku zu Schema v19: Knopf nach oben, Bildbetrachter, Rechtszeile, kaputte Stylesheet-Regeln
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 19:36:32 +02:00

75 KiB
Raw Blame History

Projektstatus

Stand: 12.09.2026. Das System heißt KantSites (vorher Arbeitstitel „Kant CMS“). Startseite von 18 auf 8 Datenbankabfragen, gemessenes Ladebudget, alle langen Listen blättern. Sicherung und Wiederherstellung, letztere nachgewiesen. Globale Seitenbreite wirkt jetzt auch nach oben, vier Menüplätze mit drei Menüarten, und jede Seite wählt ihren Kopf- und Fußbereich – auch „keiner“. 93 Gestaltungseigenschaften, neun Einblendungen, sieben Hover-Effekte, Symbol, Fortschritt und ein Slider ohne JavaScript. Update über Git mit Vorprüfung, Sicherung und Rückweg. Statistik ohne Wiedererkennung und damit ohne Einwilligung. Einwilligung mit tatsächlich zurückgehaltenen Einbettungen, Datenschutz und Impressum als Pflichtseiten. Benutzerverwaltung in der Oberfläche, Mediathek als eigene Seite mit Blättern. Die Verwaltung hat einen gemeinsamen Rahmen mit einer Navigation, die zeigt, wo man ist. Eigenes CSS je Element für alle, eigenes Skript nur für Administratoren und nur als eigene Datei. Formatierter Text mit Werkzeugleiste und HTML-Ansicht, serverseitig gegen eine Positivliste gefiltert. Kopf- und Fußbereich sind frei gestaltbare Blockdokumente, dazu verknüpfte wiederverwendbare Sektionen (Arbeitspaket G, Teil 1). Frei wählbare Startseite; /sitemap.xml und Geschwister waren lokal nie erreichbar und sind es jetzt. Seiten verschieben mit automatischen Weiterleitungen, Papierkorb, Fassungsverlauf und geplante Veröffentlichung (Arbeitspaket F). Browsertests wiederhergestellt und erweitert; dabei drei echte Fehler gefunden und behoben, darunter die in der Vorschau wirkungslose Gestaltung. Direktbearbeitung in der Vorschau, Kontrastwarnung, Gestaltungsvorlagen und Bildauswahl für Hintergrundbilder. Der Editor gestaltet frei statt über feste Auswahllisten: eigene Farbpalette, Schriften, und jede Eigenschaft je Block, je Gerät und für den Hover-Zustand frei einstellbar (Dokumentschema v10). SEO-Grundlage mit Sitemap, robots.txt, Weiterleitungen und strukturierten Daten (Arbeitspaket E). Formulare mit serverseitiger Validierung, Einwilligung, E-Mail-Versand und Spamschutz (Arbeitspaket D). Tabs als fortschreitende Verbesserung mit JavaScript (Dokumentschema v7). Zehn neue Blöcke für die Abschnitte der Pilotstartseite (Arbeitspaket C). Beiträge mit Datum, Autor, Auszug, Beitragsbild, Kategorien, Schlagwörtern, Archiven, einbettbarer Beitragsliste und RSS (Arbeitspaket B). Menüs mit Seiten-, Anker- und externen Zielen ersetzen die fest verdrahtete Navigation (Arbeitspaket A). Seiten und Beiträge lassen sich im Browser anlegen und löschen, mit Adresshierarchie bis vier Ebenen. Die vollständige Phase-1-Abnahme bleibt wegen des fehlenden UX-Builder-Referenzabgleichs offen.

Erster Commit angelegt (82b0782); das Projekt hat damit einen Rückfallpunkt. Noch kein Remote und kein Push.

Für den Livegang vorbereitet (13.09.2026): docs/LIVEGANG.md trennt, was geprüft ist, von dem, was nur auf dem echten Hosting geprüft werden kann, und nennt die Reihenfolge am Umzugstag. 14 Weiterleitungen von den alten WordPress-Adressen auf die neuen sind angelegt und beantwortet (/productsolutions → /projekte, die gekürzten Beitragsadressen, /category/allgemein); ohne sie hätte jede bei Google stehende Adresse nach dem Umzug mit 404 geantwortet. In der Datenschutzerklärung wurde der Abschnitt über Google Fonts an die Wirklichkeit angepasst (die Schriften kommen jetzt vom eigenen Server) und die Abschnitte über Google Maps und reCAPTCHA entfernt, weil beides nicht eingebunden ist – eine Erklärung, die Datenflüsse beschreibt, die es nicht gibt, ist so falsch wie eine, die welche verschweigt. Nicht geprüft und nicht prüfbar von hier: der E-Mail-Versand.

Nachbau nachgezogen (13.09.2026): Der Fußbereich ist jetzt vierspaltig wie im Original – Zeichen und Satz, „Leistungen", „Unternehmen", „Kontakt", darunter die Zeile mit Copyright. Die beiden Linklisten sind Menüs, keine Dokumentinhalte: sie lassen sich in der Verwaltung pflegen. Alle 29 Beiträge haben jetzt Text – die elf fehlenden sind neu geschrieben, denn auch im Original stehen dort nur Bildergalerien ohne Beschreibung. Die Karte „Bereit für den nächsten Schritt" hat 34 px Abstand zu den Kontaktzeilen darunter. Nicht erledigt: das TeamViewer-Logo im Fernwartungsbereich – dazu unten.

Vom Original übernommen (13.09.2026): die Meta-Beschreibung der Startseite im Wortlaut von kant-it.de, das Symbol der Website (dort 192 × 192) und die Bot-Regeln der robots.txt. Titel, Canonical, Open Graph, strukturierte Daten (LocalBusiness statt Yoasts ProfessionalService), Sitemap, robots.txt und llms.txt entstehen in KantSites aus dem Inhalt und stimmen mit dem Original überein. Beim Abgleich aufgefallen: das og:image des echten kant-it.de zeigt auf wp-content/uploads/kant-it-share.png – die Datei antwortet mit 404, beim Teilen erscheint dort also kein Bild.

Im Nachbau von kant-it.de gefunden und behoben: vier tote Verweise im Hero-Slider – die Adressen waren im Aufbauskript von Hand geschrieben, die Beiträge bekamen längere. Sie werden jetzt aus derselben Regel abgeleitet, mit der die Beiträge entstehen, und ein zweiter Lauf des Skripts aktualisiert vorhandene Seiten, statt sie zu überspringen. Eine Prüfung aller internen Verweise auf 404 gibt es im CMS noch nicht; gefunden wurden sie mit einem einmaligen Durchlauf im Browser.

Erledigt

  • AGENTS.md und ENTWICKLUNGSPLAN.md unverändert aus Downloads im Projektstamm abgelegt; SHA-256 jeweils mit dem Original identisch.
  • Leeres lokales Git-Projekt auf main initialisiert; Quellen und Lockfiles für den ersten Commit vorgemerkt. Noch kein Commit und kein Remote/Push.
  • Nutzerentscheidung „herkömmliches PHP-Webhosting“ übernommen. Symfony 7.4 / Twig / Doctrine gewählt; kein Python-/Django-Anwendungscode.
  • Start-/Build-/Prüfkommandos und Hostingvoraussetzungen in README, begründete Architektur und Datenmodell in ARCHITECTURE, Plananalyse/offene Anforderungen in REQUIREMENTS.
  • Erstes Datenbankschema, versionierte Blockdokumente, unveränderliche Revisionen über den Repository-Vertrag, getrennte Entwürfe/Veröffentlichungen und optimistische Schreibkonflikterkennung.
  • Drei gespeicherte öffentliche HTML-Demoseiten, lokale CSS-Ausgabe ohne JavaScript, Metadaten/Canonical, 404, Sprunglink und sichtbarer Fokus. /home leitet auf / um.
  • Idempotentes Demo-Seeding und lokaler CLI-Import validierter Entwürfe. Keine ungeschützte HTTP-Schreibschnittstelle.
  • Symfony-Security-Anmeldung, CSRF, Login-Throttling, geschützte Sessions und Rollen Editor/Publisher/Admin. Neue Migration ergänzt ausschließlich die Benutzertabelle. Passwort-Rehash hält Sessionbenutzer und Datenbank synchron; Rollenänderungen invalidieren bestehende Sitzungen.
  • Seitenübersicht und visueller Editor: Elementbibliothek, Strukturbaum, gemeinsame serverseitige Live-Vorschau, Eigenschaften, Drag-and-drop und Schaltflächen zum Verschieben/Verschachteln, Duplizieren/Löschen, lokales Undo/Redo.
  • Inhalt-/Designbereiche mit typabhängigen Abständen, Ausrichtung, Schriftgröße/-stärke, Zeilenhöhe, Spaltenaufteilung/-abstand und Ecken. Gerätewerte Desktop → Tablet → Mobil samt Vererbung, Einzel-/Gerätereset und Undo. Echte Vorschau-Layoutbreiten 1240/768/390 px mit visueller Skalierung.
  • Drei bearbeitbare Abschnittsvorlagen (Intro, zwei Leistungen, Kontaktaufruf), einklappbarer Werkzeugkasten, Struktursuche mit Vorfahren, einklappbare Teilbäume, Pfadnavigation und dauerhaft erreichbare Blockaktionen.
  • Dokumentformat v2, erhaltender idempotenter v1-Konverter, gemeinsame Tokenliste für Validator/Editor/CSS und dokumentierter Migrations-/Rückweg. Bestehende v1-Seiten werden beim Öffnen nicht geändert; keine neue DB-Migration erforderlich.
  • Dokumentformat v3 für Galerie, Bildbeschriftungen/-varianten und Effekte, mit erhaltendem Upgrade ohne Downgrade und Undo. v1/v2 bleiben unterstützt. Schatten, Hover-Anheben/Bildzoom und Einblenden beim Laden ohne öffentliches JavaScript; Bewegungsreduktion wird berücksichtigt.
  • Medienverwaltung im Editor und unter /admin/media: JPEG/PNG/WebP-Upload, echte Bildvalidierung, Größen-/Pixel-/Speichergrenzen, WebP-Varianten bis 480/960/1600/2400 px (ohne Hochskalieren, Hintergrundbilder geräteabhängig), Suche, Titel/Alt-Text, Archivieren/Wiederherstellen und Schreibkonflikterkennung. Bildauswahl für einzelne Bilder und Galerien, kontextbezogene Alt-Texte/dekorative Verwendung und Beschriftungen.
  • Neue Medientabelle durch Migration 20260912000300 lokal angewendet. Vorher konsistentes SQLite-Backup unter var/backups/before-media-20260912-051258.db. Bestehende Seiten/Benutzer nicht geändert. Lokal läuft PHP 8.4 mit 8M Upload-, 10M POST- und 256M Speicherlimit; originale Uploads werden nicht gespeichert.
  • Speichern/Laden von Entwürfen, separates Veröffentlichen mit Bestätigung, sichtbare Speicher-/Fehler-/Konfliktzustände, JSON-Sicherung und bewusster Server-Neuladedialog. Keine Tests schreiben in den echten Seitenbestand.
  • Auf ausdrücklichen Nutzerwunsch lokalen Administrator umut mit zufälligem Passwort angelegt und im In-App-Browser erfolgreich angemeldet. Das Passwort steht in keiner Projektdatei; nur der Hash in der lokalen Datenbank. Keine Browser-Passwortspeicherung ausgelöst.
  • Seitenerstellung und -löschung im Browser: POST /admin/pages (ab ROLE_EDITOR) legt Seite oder Beitrag mit gültigem Startdokument als privaten Entwurf an; POST /admin/pages/{id}/delete (nur ROLE_ADMIN) entfernt eine Seite mit allen Revisionen. Beide mit CSRF-Token, Fehlermeldungen als Flash und ohne JavaScript bedienbar.
  • Adresshierarchie: neue Spalten path, parent_id, type, created_at über Migration 20260912000400; websiteweit eindeutiger Pfad statt eindeutigem Slug, Tiefe bis vier Ebenen, Beiträge ohne Unterseiten, reservierte Adressen und Adressableitung aus dem Titel. Öffentliche Route bedient verschachtelte Pfade wie /leistungen/webdesign; ein Lookahead hält /admin, /media und /assets aus dem Auffangmuster.
  • Ladeverhalten gemessen statt vermutet (ADR 039, Arbeitspaket M): ein Zähler liefert die Datenbankabfragen je Anfrage im Kopf X-Kant-Queries (außerhalb der Produktion). Die erste Messung zeigte 18 Abfragen auf der Startseite, weil Einstellungen und Theme je Aufrufer erneut gelesen wurden; beide merken sich ihren Stand jetzt für die Dauer einer Anfrage – 18 → 8. Die Browserprüfung misst je Seite HTML, CSS, Anfragen, Skripte und Abfragen gegen Obergrenzen: Startseite 7,4 KB HTML, 22,7 KB CSS, 2 Anfragen, 0 Skripte.
  • Das erste Bild einer Seite lädt sofort, alles darunter weiterhin verzögert. Es ist meistens das größte Ding über der Falz.
  • Slider mit Punkten ohne Skript (ADR 044): ::scroll-marker zeichnet je Folie einen Punkt, der aktive ist erkennbar, die Rollleiste entfällt; ältere Browser behalten das wischbare Schiebefeld. Beitragskarten sind echte Karten (Bild 16:10, 18 px Ecken). Überschriften dürfen ein Wort hervorheben (<mark>, in Akzentfarbe). Behoben: die Theme-Schriftskala überschrieb die Größen in Karten und Aufruf-Bändern.
  • „Weiterlesen" ist jetzt ein Link. In der wechselseitigen Beitragsliste stand dort eine reine Beschriftung: sie sah aus wie ein Knopf und war keiner. Der Titel steckt für Vorlesesoftware im Linktext, damit nicht zwölf Links gleich heißen.
  • Dokumentschema v19: Baustein Rechtszeile (Impressum, Datenschutz, „Einwilligung ändern") für den Fußbereich – gestaltbar und an der richtigen Stelle statt als heller Streifen unter einem dunklen Fuß; die eingebaute Leiste erscheint nur noch, wenn die Seite den Baustein nicht hat. Dazu „Beim Klick" je Bild (nichts / vergrößern / Adresse) und „Bilder vergrößerbar" je Galerie.
  • Bildbetrachter (ADR 063): ohne JavaScript ein Verweis auf die große Bildfassung, mit JavaScript ein Betrachter über der Seite – <dialog> mit Blättern, Escape, Pfeiltasten und Zähler. Das Skript lädt nur auf Seiten, die ein vergrößerbares Bild enthalten.
  • Knopf „nach oben" (ADR 062), abschaltbar und vollständig einstellbar: Seite, Form, Größe, Farben, Schwelle, Beschriftung. Ein Anker ohne Skript; eingeblendet über eine Scroll-Zeitachse, wo der Browser sie kennt.
  • Behoben: zwei Stylesheet-Regeln griffen seit drei Veröffentlichungen nicht mehr (ADR 064). Beim Entfernen alter Regeln waren Selektorreste stehen geblieben; CSS nimmt dann die nächste Regel mit. Betroffen waren der Einwilligungsdialog und die Rechtszeile – beide standen ungestaltet unter dem Fuß. Ein Test prüft jetzt jede CSS-Datei auf abgebrochene Selektoren.
  • Menüs kosten nicht mehr je eine Abfrage. Jedes Menü holte die Seitenliste selbst; mit vier Menüs im Fuß waren das vier gleiche Abfragen je Seitenaufruf. Jetzt einmal je Anfrage gemerkt – Startseite des Nachbaus 21 → 18 Abfragen.
  • Behoben: die Vorschau zeigte beim Aufbau bis zu 1440 ms lang eine Seite ohne Gestaltung (ADR 061). Die Stile wurden erst angewandt, wenn das letzte Bild geladen war. Jetzt sitzen sie, sobald das Dokument geparst ist, und der Rahmen bleibt bis dahin verdeckt. Die Farben selbst stimmten immer – Vorschau und veröffentlichte Seite geben nachweislich dieselben berechneten Werte.
  • Cloudflare Turnstile für Formulare, optional (ADR 059): aus, bis in den Einstellungen beide Schlüssel stehen; dann erscheint die Prüfung in jedem Formular, und die Sicherheitsrichtlinie öffnet sich nur auf Seiten mit Formular für challenges.cloudflare.com. Antwortet Cloudflare nicht, wird die Anfrage trotzdem angenommen. Die eingebauten drei Prüfungen ohne Dritte bleiben unabhängig davon bestehen. Der Preis steht in der Verwaltung dabei: das Widget braucht JavaScript.
  • Behoben: die Fehlerseite eines Formulars hatte keine Gestaltung (ADR 060). Wer ein Pflichtfeld vergaß, bekam eine nackte Seite – der Formularcode baute sie selbst auf und ließ Theme, Blockstile und Schriften weg. Jetzt rendert derselbe Controller wie sonst auch.
  • Die Schriften liegen im Repository (public/assets/fonts/, mit lato-OFL.txt und LIZENZ.md daneben, wie die Open Font License es verlangt): auf einem frischen Server fehlt damit nichts, und es wird nie versehentlich von Google geladen. Andere Installationen holen ihre eigenen mit cms:fonts:fetch.
  • docs/NEUE-WEBSITE.md: die Anleitung, mit der eine neue Kundenwebsite entsteht – Reihenfolge, Dokumentformat, Bilder, SEO, Prüfläufe, und am Ende die fünf Fehler, die in diesem Projekt immer wieder passiert sind.
  • Schutzkopfzeilen ergänzt und geprüft: Permissions-Policy (Kamera, Mikrofon, Standort und Sensoren abgeschaltet) auf öffentlichen Seiten und in der Verwaltung; X-Powered-By wird entfernt – der Server nannte bisher in jeder Antwort seine genaue PHP-Fassung. Die Browserprüfung misst die Kopfzeilen jetzt, statt sie anzunehmen.
  • Behoben: der Editor kannte Schema v17, der Validator v18. In einem aktuellen Dokument war die Beitragsnavigation nicht einfügbar. Ein Test liest die höchste Fassung jetzt aus dem Validator und vergleicht sie mit der des Editors – dieselbe Falle war schon bei v13 zugeschnappt.
  • Getrennter Titel für Suchergebnisse (Migration 20260913000100): jede Seite und jeder Beitrag kann einen eigenen <title> tragen, unabhängig von der Überschrift auf der Seite. Leer heißt weiterhin: der Titel der Seite gilt. Er zählt auch für og:title.
  • Schriften kommen vom eigenen Server (ADR 057): ein Knopf im Designbereich oder php bin/console cms:fonts:fetch lädt die gewählten Google-Schnitte als WOFF2 nach public/assets/fonts und schreibt die @font-face-Regeln daneben. Damit lädt keine Seite mehr etwas von Google – das spart zwei fremde Verbindungen nacheinander (gemessen 820 ms) und die datenschutzrechtliche Angreifbarkeit gleich mit. Ohne Dateien bleibt es beim bisherigen Verweis.
  • Ein Stylesheet statt vier, und eine .htaccess, die etwas tut (ADR 056): gebündelt, ohne Kommentare, mit Prüfsumme im Dateinamen; Kompression, ein Jahr Cache für Dateien mit Fassung oder Kennung in der Adresse, Schutz vor dem Ausliefern interner Dateien, HTTPS-Umleitung und HSTS vorbereitet und auskommentiert. Der Entwicklungsserver sendet dieselben Kopfzeilen, damit lokale Messungen etwas bedeuten.
  • Bilder in der Größe, in der sie erscheinen (ADR 058): ein Hintergrundbild, das nur für „Desktop“ gesetzt wurde, gilt auf dem Telefon in der Telefongröße (gemessen 189 KB → 40 KB); <img> nennt seine feste Breite, wenn es eine hat, und sonst sizes="auto"; fetchpriority="high" liegt auf dem ersten Bild des Inhalts statt auf dem Logo im Kopfbereich.
  • Lighthouse gegen den Nachbau von kant-it.de (docs/quality/lighthouse-kantit.json, vier Adressen, je drei Läufe, Median): Barrierefreiheit, Best Practices, SEO und „agentic browsing“ 100 auf allen geprüften Seiten, mobil wie am Schreibtisch. Performance: Projekte-, Beitrags- und Impressumsseite 100/100, Startseite 98 mobil / 96 am Schreibtisch – dort liegen vier Sliderbilder und ein großflächiges Hintergrundbild über der Falz. Gemessen im Produktionsmodus mit denselben Kopfzeilen, die public/.htaccess setzt; keine Felddaten und keine Messung auf echtem Hosting.
  • Verweise werden geprüft (npm run test:links): folgt der Sitemap, sammelt jeden internen Verweis samt Bildern, Stylesheets und Hintergrundbildern und meldet jede Antwort ab 400. Im Nachbau 408 Adressen, kein toter Verweis.
  • Das Vorschaubild beim Teilen erscheint jetzt tatsächlich (ADR 056): og:image wird aus dem Feld der Seite aufgelöst, ersatzweise aus dem Beitragsbild – vorher speicherte das Feld und bewirkte nichts, keine KantSites-Seite hatte ein Teilen-Bild. Dazu og:site_name, og:locale, og:image:alt, twitter:card (klein ohne Bild, groß mit) und das Bild im strukturierten Datensatz eines Beitrags. Archive haben jetzt ebenfalls Open-Graph-Angaben.
  • Eigene robots.txt-Zeilen: 200 statt 30, Leerzeilen bleiben (ADR 056), damit sich Regeln je Bot in Blöcken schreiben lassen – etwa welche KI-Crawler lesen dürfen. Ein Sitemap-Index ist bewusst nicht gebaut: nötig wird er ab 50.000 Adressen.
  • Beiträge sind optional (ADR 053): ohne einen einzigen veröffentlichten Beitrag antworten /beitraege und /feed.xml mit 404, der Feedverweis fehlt im Kopf, die Sitemap kennt kein Archiv, und ein Beitragslisten-Baustein zeigt öffentlich nichts – der Hinweis „hier erscheinen Beiträge“ bleibt nur im Editor. Ein Kategorie- oder Schlagwortarchiv verschwindet ebenso, sobald es nichts mehr zu zeigen hat; der Begriff selbst bleibt. Dabei behoben: die Beitragsliste fragte je Beitrag einzeln nach Bild und Begriffen – jetzt je eine Abfrage für die ganze Liste, Startseite des Nachbaus 22 → 16 Abfragen.
  • Unterstriche nur noch im Fließtext (ADR 054), dort mit Schalter im Designbereich („Links im Fließtext unterstreichen“, Standard an). Karten, Menü, Kontaktzeilen, Rechtszeile und der „Ansehen“-Streifen über Kartenbildern haben keinen mehr; beim Überfahren erscheint er überall. Die aktuelle Seite im Menü wird über das Schriftgewicht kenntlich – die Akzentfarbe fiel im dunklen Fußmenü durch die Kontrastprüfung.
  • Eigenes Symbol der Website (ADR 055): ein Bild aus der Mediathek in den Einstellungen wählen, beim Speichern entstehen daraus quadratische PNG-Dateien in 32 und 180 px (/favicon.png, /apple-touch-icon.png). Ohne Auswahl bleibt es beim mitgelieferten Zeichen.
  • Die Browserprüfung prüft jetzt jede Installation, nicht nur die Demo: die geprüften Seiten kommen aus der Sitemap, Tastatur- und Ohne-JavaScript-Weg folgen dem ersten Verweis im Inhalt statt festen Linktexten der Demo. Das Ladebudget trennt Bilder (Inhalt) vom Beiwerk (≤ 12 Anfragen) und deckelt stattdessen das übertragene Gewicht (1,5 MB); Skripte werden gegen die Richtlinie der Seite gezählt, strukturierte Daten zählen nicht mit. Der Nachbau von kant-it.de besteht die vollständige Prüfung ohne Befund.
  • Einblendungen laufen beim Scrollen (ADR 052): animation-timeline: view() hinter Bewegungsschranke und @supports; auf dem Scrollweg nur Bewegung, keine Deckkraft, damit Text außerhalb des Blicks lesbar bleibt. Die drei Beitragsvorlagen bringen sie mit.
  • Vier Darstellungen der Beitragsliste (ADR 051): Karten, Liste, Kompakt und Wechselseitig – am Baustein einstellbar, dieselben Daten, nur andere Regeln.
  • Drei Aufbauten für neue Beiträge (ADR 050): „Bildkopf“, „Klassisch“ und „Magazin“, wählbar beim Anlegen. Startpunkte, keine Schablonen – jeder Block bleibt änderbar.
  • Dokumentschema v18 (ADR 049): Baustein „Beitragsnavigation“ – Vor/Zurück zwischen Beiträgen derselben Kategorie, vom Renderer gefüllt, ohne Umbruch am Rand. Dazu Autorotation für den Slider (Sekunden, eigenes Skript nur auf Seiten mit einem solchen Slider) und Blättern in der Beitragsliste.
  • Dokumentschema v17 (ADR 043): eine Beitragsliste kann Datum, Auszug und Kategorie ausblenden und damit als Projektraster erscheinen; ein Bild kann verlinken (Logo auf die Startseite). Dazu die Einstellung „Kopfbereich beim Scrollen oben halten“. Behoben: im Editor ließ sich in Dokumenten ab v13 kein Baustein mehr einfügen.
  • Die Gestaltung färbt jetzt auch die Bausteine (ADR 042): Symbole, Knöpfe, Rahmen, ruhiger Text, Fokusring und Einwilligungsdialog nehmen die Farben des Themes statt fester Werte aus site.css. Der Einwilligungsdialog lässt sich zusätzlich eigens färben über eine Palettenfarbe mit dem Schlüssel consent. Überschriften werden nicht mehr getrennt.
  • Installer (Arbeitspaket N, ADR 041): /install führt in sechs Schritten von einer leeren Installation zu einer Website – Systemprüfung, Datenbank (SQLite oder MySQL, Verbindung sofort geprüft), Migration im Prozess ohne Konsole, Website mit Startseite, Kopf-/Fußbereich, Menü sowie Impressum und Datenschutzgerüst, erstes Administratorkonto, Abschlussliste. Solange keine Installation existiert, führt jede Adresse dorthin; sobald ein Konto existiert, antwortet /install mit 404. Davor liegt scripts/install.php: eine einzelne Datei, die das Releasearchiv mit fester Adresse und fester SHA-256 lädt, gegen ZIP-Slip gesichert entpackt und sich danach selbst löscht.
  • Fassungsverlauf, Einsendungen und Weiterleitungen blättern statt bei 30, 50 beziehungsweise 2000 Einträgen stillschweigend aufzuhören.
  • Sicherung und Wiederherstellung (ADR 038, Arbeitspaket O): cms:backup schreibt Datenbank (über VACUUM INTO, nicht als Dateikopie) und Medienordner nach var/backups/, mit Manifest samt Prüfsumme, und rotiert die alten. In der Verwaltung gibt es die Übersicht mit Zustand je Sicherung und einen Knopf zum Anlegen. Zurückspielen nur auf der Konsole (cms:restore): Prüfsumme, Fassungsvergleich, Sicherheitskopie des aktuellen Stands, Wartungszustand, Datenbank ersetzen, Medien ergänzen statt ersetzen. Nicht enthalten: .env, vendor/, Quellcode – steht so im Manifest.
  • Seiten ohne Menü, andere Köpfe je Seite (ADR 037, Dokumentschema v16): jede Seite wählt Kopf- und Fußbereich – Standard, ein anderer Bereich oder keiner, für eine Landingpage ohne Navigation. Dafür sind mehrere Kopf- und Fußbereiche erlaubt, jeder mit eigener Adresse; der erste bleibt default. Ein Verweis auf einen gelöschten Bereich fällt auf den Standard zurück statt die Navigation stillschweigend zu verlieren.
  • Vier Menüplätze statt zwei (Hauptnavigation, zweite Navigation, Fußzeile, Rechtliches) und drei Menüarten: waagerecht, untereinander, aufklappbar als Burger. Der Burger ist ein details-Element und öffnet ohne JavaScript.
  • Die globale Seitenbreite wirkt jetzt auch nach oben. containerWidth im Designbereich gab es, aber site.css deckelte bei 1180 px – schmaler ging, breiter nicht. Dritter Fehler dieser Art an einem Tag: eine Einstellung, die sich speichern ließ und nichts tat.
  • Vollflächige Bilder und volle Bildschirmhöhe: Abschnitte können randlos sein (ohne Begrenzung, ohne Rand, von Kante zu Kante) oder breit (1600 px). Für die Höhe gibt es jetzt die Einheiten dvh, svh, lvh – 100vh ist auf dem Handy höher als der Bildschirm, 100dvh ist das, was gemeint ist. Die Vorlage „Vollbild-Hero“ setzt die ganze Kombination auf einen Klick: randlos, 100dvh (mobil 80dvh), Inhalt senkrecht zentriert, Hintergrundbild formatfüllend, dunkle Überlagerung, Überschrift, Text, Button.
  • Designer ausgebaut (ADR 036, Dokumentschema v15): 93 Gestaltungseigenschaften statt 50, je Gerät und teils für Hover. Neu: Bild-Eigenschaften, die auf das Bild im Block wirken (Ausschnitt, Bildmitte, Seitenverhältnis, Höhe, Ecken, Rahmen), Positionierung mit z-index, getrennte Zeilen- und Spaltenabstände, Flex-Eigenschaften, Innen- und Textschatten, acht Bildfilter, Mischmodus, Zusatzrahmen. Neun Einblendungen mit Verzögerung, sieben Hover-Effekte, alle innerhalb von prefers-reduced-motion. Drei neue Bausteine: Symbol, Fortschritt (mit role="meter") und Slider als Scrollbereich mit Einrasten – ohne JavaScript, ohne Autoplay. „Zeile, 2/3/4 Spalten“ legt eine Zeile samt Spalten auf einen Klick an. Der Vergleich mit Flatsome steht in docs/DESIGNER-VERGLEICH.md, mit dem was fehlt und warum.
  • Zwei Fehler dabei gefunden und behoben: Rahmenstärken je Seite erzeugten border-width-top – kein gültiges CSS, vom Browser stillschweigend verworfen, also ohne jede Wirkung. Und eine Rundung auf einem Bildblock rundete den Rahmen, nicht das Bild.
  • Update über Git (ADR 035, Arbeitspaket N/UPDATE.md): cms:update und ein Bildschirm „System“ zeigen Fassung, Commit, verfügbaren Tag und eine Vorprüfung, die jede Bedingung einzeln nennt – unter anderem, ob Datenbank und Medienordner von Git ausgenommen sind. Der Ablauf: sichern, Wartungszustand (503 mit Retry-After, /admin bleibt offen), Checkout des Tags, Fassung prüfen, Composer, Migration, Cache, Rauchtest als eigener Prozess (cms:health). Scheitert ein Schritt, wird auf den vorherigen Commit zurückgesetzt, die Datenbank nur dann zurückgeschrieben, wenn die Migration schon begonnen hatte – und wenn der alte Stand antwortet, geht die Website wieder online. --check, --dry-run, --to=v1.2.0 und --maintenance=an|aus gibt es auf der Konsole.
  • Statistik (ADR 034, Arbeitspaket L): Aufrufe je Tag und Stunde, meistaufgerufene Seiten, Verweise von außen und nicht gefundene Adressen, als CSV exportierbar. Gespeichert wird ein Zähler je (Tag, Stunde, Pfad, Status, Verweis-Domain), kein Datensatz je Aufruf – keine IP-Adresse, keine Kennung, kein Cookie, auch nicht gehasht. Deshalb braucht diese Messung keine Einwilligung. Diagramme zeichnet der Server als SVG, ohne Skript. Was sie nicht kann, steht auf dem Bildschirm: Aufrufe statt Besucher, keine Verweildauer, keine Absprungrate, kein Klickweg, kein Land. Nach 60 Tagen werden Stunden zu Tageswerten verschmolzen, nach 425 Tagen gelöscht (cms:stats:prune).
  • Einwilligung (ADR 032, Dokumentschema v14): serverseitig gerendertes Banner ohne JavaScript, „Alle akzeptieren“ und „Nur notwendige“ gleich groß nebeneinander, Auswahl je Gruppe im Aufklappfeld. Die Entscheidung steht in einem eigenen Cookie – keine Kennung, kein Serverabgleich, ein halbes Jahr. Unter /einwilligung jederzeit änderbar, von jeder Seite verlinkt. Der neue Block „Externer Inhalt“ lädt ohne Einwilligung nichts: kein iframe, keine Adresse im Markup, frame-src 'none'. Der Platzhalter nennt den Anbieter und gewährt auf Knopfdruck genau diese Gruppe. Ist der Hinweis abgeschaltet, laden die Inhalte – sonst würde das Abschalten jede Seite stillschweigend leeren.
  • Datenschutz und Impressum sind Pflicht, nicht Einstellung (ADR 033): fehlen sie, warnt die Verwaltung und legt sie auf Knopfdruck als Gerüst mit NOCH AUSZUFÜLLEN-Markierungen an. Verlinkt werden sie aus dem Template, nicht aus dem Fußbereich, damit der Link nicht versehentlich gelöscht werden kann.
  • Kopf- und Fußbereich lagen falsch im Layout. Umut hat es im Screenshot gesehen: die Wortmarke stand als Buchstabenkolonne in einem 60 Pixel breiten Kasten. Zwei Ursachen, beide behoben – .site-header war noch ein Flexcontainer für das alte, handgeschriebene Markup und quetschte die Sektion darin zusammen, und design.css band alle Designklassen an #main, sodass Kopf- und Fußbereich außerhalb davon jede Designeinstellung ignorierten.
  • Benutzerverwaltung (ADR 030): Konten anlegen, Rolle ändern, Passwort setzen, Konto löschen – nur für Administratoren. Eine Rolle je Konto (Administrator, Veröffentlicher, Redakteur). Ein Passwort oder eine Rolle zu ändern meldet jede offene Sitzung dieses Kontos ab, weil die Sitzung Hash und Rollen gegen die Datenbank prüft; nur die Sitzung, die ihr eigenes Passwort ändert, bleibt angemeldet. Niemand kann sein eigenes Konto löschen oder herabstufen, deshalb bleibt immer ein Administrator übrig. Das eigene Passwort darf jeder ändern, aber nur mit dem aktuellen. Die Liste zeigt letzte Anmeldung, Passwortdatum und Anlagedatum.
  • Mediathek als Seite (ADR 031): /admin/media zeigt die Bilder direkt, 24 je Seite, mit Blättern und Archivfilter. Hochladen und Bildangaben über gewöhnliche Formulare, ohne JavaScript. Hochgeladen wird über eine Ablagefläche: Bilder hineinziehen oder klicken; darunter steht, welche Dateien gewählt sind und welche übersprungen wurden. Darunter liegt ein echtes, per Tastatur erreichbares Dateifeld – ohne JavaScript bleibt es der Dateidialog, und abgeschickt wird immer erst auf Knopfdruck. Der Dialog bleibt für die Bildauswahl im Editor.
  • Verwaltung neu gestaltet (ADR 029): ein Rahmen für alle Bildschirme mit fester Seitenleiste, aktivem Eintrag über aria-current, Titel, einem Satz Erklärung und Platz für die Hauptaktion. Vorher trug jede Seite ihre eigene Kopfzeile und eine eigene, unvollständige Linkliste. Je Seite eine Zeile mit dem Alltäglichen und einem Aufklappfeld „Einstellungen“, das an seinem Platz öffnet, statt sechs Kästen, die über den Rand hinausragten. Tabellen scrollen seitlich, statt die Karte aus dem Fenster zu schieben. Die Editorregeln stehen jetzt in editor.css, das nur Editor und Mediathek laden.
  • Verwaltung neu gestaltet (ADR 029): ein Rahmen für alle Bildschirme mit fester Seitenleiste, aktivem Eintrag über aria-current, Titel, einem Satz Erklärung und Platz für die Hauptaktion. Vorher trug jede Seite ihre eigene Kopfzeile und eine eigene, unvollständige Linkliste. Je Seite eine Zeile mit dem Alltäglichen und einem Aufklappfeld „Einstellungen“, das an seinem Platz öffnet, statt sechs Kästen, die über den Rand hinausragten. Tabellen scrollen seitlich. Der Editor behält seinen Aufbau und übernimmt die neue Gestaltung; seine Regeln stehen jetzt in editor.css, das nur Editor und Mediathek laden.
  • Eigenes CSS je Element (Dokumentschema v13) im neuen Reiter „Erweitert“: Eigenschaften für das Element und verschachtelte Regeln mit &. Der Selektor wird vom Server gesetzt, die Ausgabe neu serialisiert – eine überzählige } kann den Block nicht verlassen. Abgewiesen: @-Regeln, Backslash-Escapes, expression(), fremde Selektoren und jede Adresse außer einem einzelnen / oder https://. Für jeden mit Editorrolle.
  • Eigenes Skript je Element nur für Administratoren. Durchgesetzt beim Schreiben durch Vergleich mit dem gespeicherten Stand – ein Editor kann eine Seite mit Skript weiter bearbeiten, das Skript aber nicht anfassen, auch nicht über eine eigene Anfrage. Ausgeliefert als /assets/seite/{id}.js nur für veröffentlichte Seiten, jedes Skript in einer eigenen Closure mit element und try/catch. Nur eine Seite mit eigenem Skript sendet script-src 'self', jede andere behält script-src 'none'; inline ist nirgends erlaubt. In der Editorvorschau wird nichts ausgeführt.
  • Formatierter Text in Textblöcken (Dokumentschema v12): fett, kursiv, unterstrichen, durchgestrichen, Code, hervorgehoben, hoch-/tiefgestellt, Absätze, Listen und Links. Im Editor eine Werkzeugleiste plus HTML-Ansicht; eingefügter Inhalt kommt als reiner Text an. Gefiltert wird auf dem Server beim Speichern, nicht im Editor und nicht beim Rendern – was in der Datenbank liegt, ist schon sicher. Nicht erlaubte Elemente werden ausgepackt, der Text bleibt; script, style, iframe und Verwandte werden samt Inhalt entfernt. Attribute fallen weg außer href nach Adressprüfung. Ältere Dokumente behalten Klartextsemantik und werden weiter maskiert.
  • Kopf- und Fußbereich sind Blockdokumente unter /admin/partials, im selben Editor gestaltbar wie eine Seite. Im Template steht keine Marke und keine Navigation mehr; ein neuer Block menu zeigt einen Menüplatz. Geteilte Bereiche haben keinen Entwurf und keine Veröffentlichung – gespeichert heißt live – und dürfen keine Hauptüberschrift enthalten, weil jede Seite ihre eigene bringt.
  • Wiederverwendbare Sektionen werden verknüpft, nicht kopiert (Block partialref, Dokumentschema v11): die Seite speichert nur die Adresse, eine Änderung erreicht jede Seite, die sie einbindet. Zyklen werden abgewiesen, Verschachtelung auf drei Ebenen begrenzt, eine entfernte Sektion hinterlässt keine Lücke und der Verweis bleibt gespeichert. Die Abschnittsvorlagen kopieren weiterhin – beide Wege stehen bewusst nebeneinander.
  • Frei wählbare Startseite unter Einstellungen. Es gibt jetzt eine Quelle dafür – SiteSettings::homePath() und publicPath(); das Literal home kommt im Anwendungscode nicht mehr vor. Die gewählte Seite muss veröffentlicht und nicht im Papierkorb sein, ihre eigene Adresse leitet dauerhaft auf /, und solange sie die Wurzel ist, lässt sie sich nicht umbenennen oder löschen.
  • /sitemap.xml, /robots.txt, /llms.txt und /feed.xml waren lokal nie erreichbar, obwohl jeder Kernel-Test sie bestand: der eingebaute PHP-Server antwortet für fehlende Pfade mit Dateiendung selbst mit 404. bin/dev-router.php bildet die Rewrite-Regel des Hostings nach; Start- und CI-Befehl nutzen es, und der Browsertest ruft die vier Adressen jetzt über HTTP auf.
  • Barrierefreiheitsbefunde werden nach Ursache getrennt: ein Kontrastfehler aus Theme oder Stylesheet bricht den Lauf ab, einer aus einer im Editor gesetzten Blockfarbe wird bei jedem Lauf mit Seite, Farbe und Verhältnis ausgegeben und in reports/browser.json geschrieben. Stillschweigend durchgelassen wird nichts.
  • Seiten umbenennen und verschieben zieht den ganzen Teilbaum mit und hinterlässt für jede alte Adresse eine dauerhafte Weiterleitung. Kollisionen, Tiefengrenze und das Verschieben unter eigene Unterseiten werden vorher abgewiesen; alles in einer Transaktion.
  • Papierkorb statt sofortigem Löschen für die Editorrolle: alle Fassungen bleiben, öffentlich 404, verschwunden aus Navigation, Archiven, Feed, Sitemap, llms.txt und Editorliste. Unterseiten gehen mit; beim Wiederherstellen muss das Elternteil zuerst zurück. Endgültiges Löschen bleibt der Administratorrolle.
  • Fassungsverlauf je Seite unter /admin/pages/{id}/revisions mit Wiederherstellen. Das überschreibt nichts: die alte Fassung wird als neuer Entwurf gespeichert.
  • revision.seq behebt einen echten Fehler: die Reihenfolge des Verlaufs war nicht eindeutig, weil created_at nur Sekunden kennt und mehrere Speichervorgänge in dieselbe Sekunde fallen. Jede Fassung hat jetzt einen je Seite aufsteigenden Zähler.
  • Geplante Veröffentlichung über publish_at und den Cron-Befehl cms:publish-due. Ohne Cron bleibt die Seite ein Entwurf. Zeiten in UTC; Seiten im Papierkorb werden nie durch den Zeitplan veröffentlicht.
  • Die erzeugten Stile wirkten in der Editorvorschau nicht. Ein srcdoc-Iframe erbt die Richtlinie der Verwaltung, die Inline-Styles verbietet; das Stylesheet wurde stillschweigend verworfen. Die Vorschau liefert es jetzt als inertes <template>, der Editor wendet es über adoptedStyleSheets an. Ausgeliefert wurde es die ganze Zeit korrekt – nur die Vorschau log.
  • Die Einrückung der Unterseiten in der Seitenliste hat nie funktioniert: sie lief über ein style-Attribut, das dieselbe Richtlinie verwirft. Jetzt über Klassen.
  • Das Theme überschrieb alle Linkfarben und erzeugte damit 3,08:1 auf dunklem Grund. Die Regel gilt jetzt nur für Links in Textblöcken; die voreingestellte Linkfarbe #a4510f liegt auf allen hellen Tönen über 4,5:1.
  • Bewegungseffekte (Schatten, Hover, Einblendung) bleiben als eigener Panelabschnitt für jeden Block: sie sind Keyframes und lassen sich mit freien Deklarationen nicht ausdrücken. Die alten Tokenwerte erscheinen nur noch, wo eine Seite sie trägt.
  • Direktbearbeitung in der Vorschau: Doppelklick auf Überschrift, Text, Zitat, Aufruf-Band, Symbolkarte, Akkordeon-Eintrag, Tab-Titel oder Kennzahl bearbeitet den Text an Ort und Stelle; Escape beendet, Eingaben werden zu einem Undo-Schritt zusammengefasst. Die Vorschau führt dabei weiterhin kein eigenes JavaScript aus – der Editor greift in ihr Dokument. Eine Schaltfläche im Panel startet dasselbe ohne Maus.
  • Kontrastwarnung im Designpanel: Verhältnis zwischen wirksamer Text- und Hintergrundfarbe nach WCAG 2.1 mit drei Stufen. Eine Warnung, kein Verbot.
  • Gestaltungsvorlagen im Theme: eine Gestaltung unter einem Namen speichern und auf jedem Block jeder Seite anwenden, dazu Kopieren und Einfügen zwischen Blöcken innerhalb der Sitzung. Vorlagen werden mit demselben Compiler geprüft wie Blockstile.
  • Hintergrundbilder werden über die Mediathek gewählt statt über eine eingetippte ID.
  • Freie Gestaltung (Dokumentschema v10). StyleSchema erklärt jede Eigenschaft einmal mit Typ, CSS-Entsprechung und Grenzen; Validator, CSS-Erzeugung und Editorpanel lesen dieselbe Definition. Rund fünfzig Eigenschaften in sieben Gruppen: Typografie (Schriftart, Größe, Stärke, Lage, Zeilenhöhe, Buchstaben- und Wortabstand, Ausrichtung, Schreibweise, Textlinie, Farbe), Hintergrund (Farbe, Verlauf, Bild mit Größe/Ausschnitt/Wiederholung/Parallax, Überlagerung), Abstände je Seite, Größen, Rahmen je Seite und Ecken je Ecke, Layout (Flex, Raster, Verteilung, Abstand, Reihenfolge) und Wirkung (Deckkraft, freier Schatten, Verschieben, Skalieren, Drehen, Übergangsdauer). Werte je Gerät mit Vererbung Desktop → Tablet → Mobil und einzeln zurücksetzbar; farbige, numerische und Bewegungswerte zusätzlich für den Hover-Zustand.
  • Theme unter /admin/theme: frei definierbare Farbpalette (bis 40 eigene Farben, im Editor als @schlüssel), Schriften aus Systemschrift oder Google Fonts mit Auswahl der Schnitte, und die Grundtypografie aus Schrift, Grundgröße, Zeilenhöhe, Überschriftenskala, Inhaltsbreite sowie Text-, Hintergrund- und Linkfarbe. Eine Palettenfarbe zu ändern wirkt überall, wo sie verwendet wird.
  • Der Server erzeugt pro Seite ein blockgenaues Stylesheet mit Media Queries und :hover,:focus-within. Es steht inline und ist über seinen eigenen SHA-256-Hash erlaubt, nicht über unsafe-inline. Google Fonts auf ausdrückliche Nutzerentscheidung – das bedeutet eine Anfrage an Google je Seitenaufruf; die Richtlinie öffnet die Hosts nur, wenn tatsächlich eine Google-Schrift eingestellt ist.
  • SEO: Indexierungssteuerung und Vorschaubild je Seite, Unternehmensdaten unter /admin/settings, sitemap.xml, robots.txt, Weiterleitungen mit 301 und 410, optionale llms.txt, Brotkrumen-Block (Dokumentschema v9) sowie strukturierte Daten für Organization/LocalBusiness, Article und BreadcrumbList. Alles Maschinenlesbare wird aus dem veröffentlichten Bestand abgeleitet: eine nicht indexierbare Seite verschwindet gleichzeitig aus der Sitemap und bekommt ein noindex-Meta. Ohne gepflegte Unternehmensdaten wird kein leerer Organization-Block ausgegeben. llms.txt ist standardmäßig aus.
  • Dokumentschema v8: Formulare. Verwaltung unter /admin/forms mit Feldtypen Text, E-Mail, Telefon, Mehrzeiliges, Auswahl und Einwilligung, Empfänger, Betreff, Antwortadresse und Erfolgsmeldung. Der Formularblock im Seiteninhalt enthält nur die Adresse – Felder und Empfänger liegen in der Datenbank, damit gespeicherter Inhalt nicht ändern kann, wohin eine Anfrage geht. Serverseitige Validierung mit einer Meldung je Feld über aria-describedby/aria-invalid, Eingaben bleiben bei Ablehnung erhalten (HTTP 422), gültige Absendung per HTTP 303 zurück auf die Seite. Spamschutz ohne Dienst Dritter: Honeypot, signierter Zeitstempel und fünf Absendungen je Absender und Stunde. Die Absenderadresse wird nie gespeichert, nur ein Hash; der Zeitpunkt der Einwilligung getrennt. Gespeichert wird vor dem Versand, damit ein kaputter Mailversand keine Anfrage verliert; nicht versendete Einsendungen sind in der Verwaltung gekennzeichnet. Voreingestellter Transport sendmail, per MAILER_DSN auf SMTP umstellbar. Kein CSRF-Token auf dem öffentlichen Weg, weil dafür eine Sitzung und damit ein Cookie auf jeder öffentlichen Seite nötig wäre; Begründung in ADR 017.
  • Dokumentschema v7: Tabs. Der Server liefert Ankerliste und alle Panels mit Überschriften, also vollständigen Inhalt ohne JavaScript; public/assets/tabs.js macht daraus ein echtes Tab-Widget mit tablist/tab/tabpanel und Pfeiltastenbedienung. Die strenge Richtlinie bleibt Voreinstellung: öffentliche Seiten senden weiterhin script-src 'none', nur eine Seite mit Tab-Block sendet script-src 'self'. Inline-Skript ist nie erlaubt. In der Editorvorschau erscheinen Tabs untereinander, weil die Vorschau kein JavaScript ausführt; ein Hinweis im Eigenschaftenpanel sagt das.
  • Dokumentschema v6 mit zehn Blöcken für die Pilotseite: Symbolkarte, Kennzahl, Kundenstimme mit Bewertung, Logoleiste, Aufruf-Band, Kontaktdaten, Trennlinie, Abstand, Akkordeon und Akkordeon-Eintrag. Symbole als Inline-SVG aus einer festen Liste, kein Symbolschriftsatz und keine externe Anfrage. Kontaktdaten werden zu tel:- und mailto:-Verweisen. Akkordeon über details/summary, also ohne öffentliches JavaScript. Tabs sind bewusst nicht umgesetzt – ohne JavaScript gibt es dafür keine zugängliche Lösung; Begründung in ADR 015.
  • Beiträge: Datum, Autor, Auszug und Beitragsbild als Seitenspalten, gepflegt über ein Formular in der Seitenübersicht. Kategorien und Schlagwörter als Begriffe mit eigenen Archiven unter /kategorie/{slug} und /schlagwort/{slug}, Gesamtübersicht unter /beitraege mit Paginierung über ?seite=N, RSS unter /feed.xml. Der Block postlist (Dokumentschema v5) speichert nur Anzahl und Filter; die Beiträge stellt der Controller beim Ausliefern zusammen, damit ein gespeichertes Dokument keinen unveröffentlichten Beitrag zeigen kann.
  • Menüverwaltung unter /admin/menus für die Plätze Hauptnavigation und Fußzeile. Ein Eintrag verweist auf eine Seite, auf ein Sprungziel innerhalb einer Seite oder auf eine Adresse (HTTPS, lokaler Pfad, mailto:, tel:). Zwei Ebenen, bis 60 Einträge, optimistische Konflikterkennung. Bedienung über eine nummerierte Zeilenliste, vollständig ohne JavaScript; Untermenüs in der Ausgabe über details/summary. Seitenverweise speichern die Seiten-ID, nicht den Pfad – ein Eintrag folgt einer umbenannten Seite und überlebt eine gelöschte.
  • Dokumentformat v4: Blocktypen mit Namensraum (acme.slider) gelten als Bausteine einer Erweiterung und werden erhalten statt abgewiesen. Öffentlich rendert der Kern aus ihnen nichts außer einem HTML-Kommentar, in der Editorvorschau einen Platzhalter. Im Editor bleiben sie auswählbar, verschiebbar, duplizierbar und löschbar, aber nicht bearbeitbar. v1 bis v3 bleiben unverändert unterstützt.
  • Login-Throttling nutzt in der Testumgebung einen Array-Cache. Zuvor überdauerten die Zähler den Testlauf und sperrten die Anmeldung nach wenigen Wiederholungen aus, was als Testfehler erschien.
  • Lokale PHP-/Browser-/Lighthouse-Prüfungen und minimale GitHub-Actions-Konfiguration einschließlich vorbereitetem MySQL-Smokejob.

Geprüft

  • 201 PHP-Tests / 716 Assertions unter PHP 8.2.12 und 8.4.22 erfolgreich; zusätzlich 15 JavaScript-Modelltests, der vollständige Playwright-Editortest und die öffentliche Browserprüfung. Abgedeckt sind Migration/Erhaltung, Versionen, ungültige Geräte-/Typ-/Design-/Effektwerte, Vererbung/Reset/Undo, Vorlage-/Galerie-IDs, Uploadvalidierung und Neuencodierung, Metadatenkonflikte, Archivierung sowie sichere Bildquellen.
  • Neu geprüft (15 Tests): privater Entwurf nach dem Anlegen, verschachtelte Pfade mit gleichem Slug unter verschiedenen Eltern, abgewiesene Adressen (Großbuchstaben, Schrägstrich, leer, reserviert, unbekannter Typ, fehlendes Elternteil) ohne Schreibzugriff, doppelte Adresse, Tiefengrenze, Beiträge ohne Unterseiten, Löschen mit allen Revisionen samt Schutz für Elternseiten und veraltete Versionen, sowie dass die CMS-Routen nicht vom öffentlichen Auffangmuster verschluckt werden. Über HTTP zusätzlich: anonyme Schreibversuche, CSRF für Anlegen und Löschen, Adressableitung aus dem Titel, kein Löschangebot und HTTP 403 für die Editorrolle, erfolgreiches Löschen als Administrator.
  • Verwaltung geprüft: axe ohne Verstöße auf Anmeldung, Seitenübersicht und Editor (Desktop und Mobil), 201 PHP-Tests grün. Nicht geprüft: kein Screenreader, und die Bildschirme Menüs, Formulare, Bereiche, Design, Einstellungen und Fassungen sind nur von Hand angesehen, nicht automatisiert auf Barrierefreiheit geprüft – die Browserprüfung deckt sie nicht ab.
  • Ladeverhalten geprüft: drei Tests – 30 Fassungen ergeben zwei Seiten mit richtiger Reihenfolge und richtigem Rest, eine Seite jenseits des Endes zeigt die letzte statt einer leeren; das erste Bild trägt loading="eager" und fetchpriority="high", das zweite lazy; und die Startseite bleibt unter zwölf Abfragen. Dazu das Ladebudget in der Browserprüfung.
  • Wiederherstellung nachgewiesen, nicht nur gebaut – das war der älteste offene Punkt aus Arbeitspaket I. Acht Tests gegen eine wegwerfbare Installation, darunter der eigentliche: Sicherung anlegen, Seite und Bilddatei löschen, zurückspielen, beides ist wieder da. Dazu von Hand auf der Entwicklungsinstallation: Testseite angelegt (5 Seiten), gesichert, gelöscht (4), zurückgespielt (5, Seite mit ihrer Adresse wieder da), Testseite entfernt (4). Ebenfalls geprüft: eine manipulierte Sicherung wird abgewiesen, eine aus einer neueren Fassung nur mit --force, Rotation behält die neuesten, und eine nach der Sicherung hochgeladene Datei überlebt die Wiederherstellung.
  • Seitenbereiche geprüft: Standard, anderer Bereich, „keiner“ (dann steht weder site-header noch site-footer im HTML, die Seite selbst aber schon), ein Verweis auf einen gelöschten Bereich fällt auf den Standard zurück, eine veraltete Fassungsnummer und eine ungültige Adresse werden abgewiesen. Menüarten: drei angenommen, eine erfundene abgewiesen, Burger als details – und die Seite behält script-src 'none'. Seitenbreite: die Regel in site.css nimmt den Theme-Wert, und ein größerer Wert erscheint als --k-container im Seiten-Stylesheet.
  • Vollbild geprüft: vier Abschnittsbreiten werden angenommen und eine erfundene abgewiesen; sieben Höhenangaben, darunter dvh, svh und lvh, und zwei ungültige; ein randloser Abschnitt mit formatfüllendem Bild erzeugt #id{width:100%} und #id img{object-fit:cover;height:100dvh}. Die Hero-Vorlage ist im JavaScript-Modelltest nachgerechnet, Eigenschaft für Eigenschaft.
  • Designer geprüft: 16 Datensätze prüfen, dass jede Eigenschaftsform genau die versprochene Deklaration erzeugt – Rahmen je Seite in der richtigen Schreibweise, Ecken, Positionierung, Flex, getrennte Abstände, Innenschatten, Textschatten, Filter in fester Reihenfolge, Mischmodus, und die Bild-Eigenschaften in einer zweiten Regel #id img{…}. Jeder davon muss außerdem den Validator überleben, sonst bietet der Editor etwas an, das nicht gespeichert werden kann. Ein Test hält Schema und Editorpanel zusammen: eine Gruppe, die das Panel nicht kennt, würde ihre Eigenschaften in einem unbenannten Aufklappfeld verstecken.
  • Neue Bausteine geprüft: vier Darstellungen (dekoratives Symbol vor Screenreadern verborgen, sprechendes Symbol mit Text, Fortschritt mit role="meter" und Wert im Markup, Slider mit Klasse je Gerät) und acht abgewiesene Eingaben (Symbolgröße außerhalb der Liste, unbekanntes Symbol, sprechendes Symbol ohne Beschriftung, dekoratives mit Beschriftung, Fortschritt über 100, Fortschritt als Text, Slider mit sieben Folien, Slider ohne Gerätangabe). Keiner der drei braucht ein Skript: die Seite behält script-src 'none'.
  • Updater geprüft: sechs Tests gegen echte Git-Repositorys in einem Temp-Verzeichnis – Vorprüfung benennt geänderte Dateien und eine nicht ausgenommene Datenbank, ein Update wechselt den Tag in der geprüften Reihenfolge und hebt den Wartungszustand auf, ein gescheiterter Schritt setzt Code und Datenbank zurück und bringt die Website auf dem alten Stand wieder online, ein Probelauf verändert nichts, ein unbekannter Tag wird beim Checkout abgewiesen, und eine bereits installierte Fassung ist kein Fehler. Zusätzlich am echten Repository durchgespielt (siehe QUALITY).
  • Statistik geprüft: 32 Tests, darunter die Spaltenliste der Tabelle gegen die Zusage „keine Spalte, aus der eine Person hervorgeht“, 14 Anfragearten (Verwaltung, Bild, Stylesheet, Feed, Weiterleitung, POST, Googlebot, Überwachungsdienst, Headless, curl – alle nicht gezählt), sieben Verweisformen (nur der Host bleibt, die eigene Domain gilt nicht als Verweis), sechs Adressformen (Query verworfen, erfundene 404 gesammelt) und das Verschmelzen und Löschen alter Tage. Dazu durch echte Anfragen: fünf Aufrufe werden ein Zähler, ein 404 zählt nicht als Aufruf, Verwaltung und Feed zählen nicht.
  • Einwilligung geprüft: 26 PHP-Tests, darunter sieben Cookiezustände (gewährt, abgelehnt, andere Gruppe, abgelaufen, ältere Fassung der Frage, Unsinn, unbekannte Gruppe) und zehn abgewiesene Einbettungsadressen (http, protokollrelativ, javascript:, data:, mit Port, mit Zugangsdaten, Leerzeichen im Host, ohne Titel, unbekannte Gruppe, zu geringe Höhe). Im Browsertest zusätzlich: Banner erscheint, kein iframe und keine Adresse im Markup, Einwilligen über den Platzhalter lädt den Inhalt, Widerruf hält ihn wieder zurück, axe ohne Verstöße auf Banner und Einwilligungsseite.
  • Verwaltung geprüft: axe ohne Verstöße auf elf Bildschirmen – Anmeldung, Seitenübersicht, Benutzer, eigenes Konto, Mediathek, Menüs, Formulare, Bereiche, Design, Einstellungen und Editor in Desktop und Mobil. Vorher waren es drei.
  • Benutzerverwaltung geprüft: 16 Tests, darunter zwei gleichzeitige Sitzungen, die zeigen, dass ein zurückgesetztes Passwort und eine geänderte Rolle die andere Sitzung abmelden, während die handelnde angemeldet bleibt. Acht abgewiesene Kontoanlagen (zu kurzes Passwort, mehr als 72 Bytes, Nullbyte, drei ungültige Namen, Doppelname, unbekannte Rolle) legen kein Konto an. Jeder Schreibweg braucht ein CSRF-Token und ist ohne Administratorrolle 403.
  • Mediathek geprüft: Upload über das Formular mit zwei Dateien in einem Absenden, CSRF-Pflicht, Bildangaben mit Versionskonflikt, Archivfilter, Blättern bei 26 Bildern (24 auf Seite eins, korrekte Sortierung neueste zuerst, ?seite=99 wird auf die letzte Seite begrenzt) und Rückkehr auf dieselbe Seite nach dem Speichern. Die Ablagefläche ist im Browsertest geprüft (gewählte Dateien erscheinen im echten Dateifeld und werden benannt) und von Hand mit einem echten Drop, bei dem eine Nicht-Bilddatei übersprungen wurde.
  • Updateverfahren geplant, nicht gebaut: docs/UPDATE.md beschreibt, wie eine neue Version über einen Git-Tag gezogen wird – Vorprüfung, Sicherung, Wartungszustand, Checkout, Migration, Rauchtest, Rückweg. Zwei Entscheidungen hängen am Hosting: Composer auf dem Server oder vendor/ im Tag, und ob es überhaupt Shell-Zugriff gibt.
  • Nicht geprüft: kein Screenreader.
  • Eigener Code geprüft: fünf CSS-Formen werden korrekt auf das Element bezogen, darunter & .block-text mit erhaltenem Nachfahren-Leerzeichen. Zehn abgewiesene CSS-Eingaben erreichen kein Dokument: Ausbruch mit }, fremder Selektor, @import, @media, javascript:-Adresse, protokollrelative Adresse, Backslash-Escape, expression(), Eigenschaft ohne Wert und unsinniger Eigenschaftsname. Eigenes CSS erscheint im Seiten-Stylesheet, eigenes Skript nur als Datei mit script-src 'self' ausschließlich auf dieser Seite; eine Seite ohne eigenes Skript behält script-src 'none' und liefert keine Datei. Ein Skript aus einem unveröffentlichten Entwurf wird nicht ausgeliefert. Der Rollenvergleich weist Ändern, Entfernen und Hinzufügen eines Skripts ab und lässt unveränderte Skripte durch.
  • Formatierter Text geprüft: dreizehn Fälle durch den Filter, darunter erlaubte Auszeichnung und Listen, ein script samt Inhalt entfernt und der Text danach erhalten, Ereignisattribut entfernt, class/style entfernt und das Element ausgepackt, javascript:-Link zu Text geworden, Bild mit onerror entfernt, iframe entfernt, unausgeglichene Auszeichnung geschlossen, lokaler Link erhalten, externer Link mit rel="noopener", Klartext maskiert und Umbruch zu <br>. Dazu: gefiltert wird beim Speichern (die Datenbank enthält schon die sichere Fassung), ein nach dem Filtern leerer Textblock wird abgewiesen ohne zu schreiben, ab v12 erscheint Auszeichnung als Auszeichnung in einem div, vor v12 maskiert in einem p, und in einem geteilten Bereich gilt derselbe Filter.
  • Bereiche geprüft: die eingesetzten Kopf- und Fußbereiche erscheinen als gewöhnliche Blöcke, der Navigationsblock zeigt das Menü, und eine Änderung am Kopfbereich erreicht beide Seiten gleichzeitig. Ein leerer 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, usedBy nennt beide Seiten, und nach dem Entfernen bleiben die Seiten heil und der Verweis erhalten. Abgewiesen werden: Hauptüberschrift in einem geteilten Bereich, Sektion mit Selbstbezug, zweiter Kopfbereich und das Löschen von Kopf- oder Fußbereich.
  • Startseite geprüft: eine andere veröffentlichte Seite wird zur Wurzel, 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 derselben Entscheidung. Solange eine Seite die Wurzel ist, werden Umbenennen und Papierkorb abgewiesen. Drei ungültige Wurzelangaben (nicht vorhanden, leer, Großbuchstaben) ändern nichts.
  • Öffentliche Browserprüfung wieder grün, inklusive der vier maschinenlesbaren Adressen über HTTP mit richtigem Inhaltstyp. Sechs Seiten-/Breitenkombinationen ohne Code-Verstoß; die redaktionelle Feststellung zu /grundlagen wird ausgegeben.
  • Lighthouse 13.4.1: je drei Läufe mobil und Desktop, alle fünf Kategorien 100 mit Startseite, Theme, gehashtem Stylesheet und Routerskript.
  • Seitenverwaltung geprüft: Verschieben ändert drei Adressen über zwei Ebenen, jede neue antwortet mit 200 und jede alte mit 301 auf das richtige Ziel, Slugs und Elternbeziehungen der Unterseiten bleiben erhalten. Vier Fälle werden abgewiesen, ohne etwas zu bewegen oder eine Weiterleitung zu erfinden: in die eigene Unterseite, in sich selbst, auf eine vergebene Adresse und mit einem unbrauchbaren Slug; dazu die Startseite. Papierkorb geprüft: Teilbaum geht mit, öffentlich 404, verschwunden aus Navigation, Sitemap, Archiv, Feed und Editorliste, Kind kann nicht vor dem Elternteil zurück, Wiederherstellen stellt nur die gewählte Seite zurück. Fassungen geprüft: Reihenfolge neueste zuerst, Wiederherstellen fügt eine Fassung hinzu statt zu überschreiben, eine fremde Fassung wird abgewiesen. Zeitplan geprüft: ein künftiger Zeitpunkt veröffentlicht nichts, ein vergangener genau einmal, danach ist der Zeitpunkt verbraucht, und eine Seite im Papierkorb wird nie veröffentlicht.
  • Der vollständige Browser-End-to-End-Test läuft wieder und deckt jetzt das neue System ab. npm run test:editor war durch den Umbau kaputt (er steuerte die abgeschafften Auswahllisten) und wurde auf die freien Bedienelemente umgeschrieben: Einheitenfelder, Vererbung über drei Geräte, einzelnes Zurücksetzen, Palettenfarbe, Abstand je Seite, Hover-Regel über den Template-Weg, freie Rasterspalten und die weiterhin vorhandenen Bewegungseffekte. axe meldet null Verstöße auf Login, Seitenliste, Editor in Desktop- und Mobilbreite, Medienauswahl und der bearbeiteten veröffentlichten Seite.
  • Lighthouse 13.4.1 auf der Startseite mit dem neuen Theme-System: je drei Läufe mobil und Desktop, alle fünf Kategorien 100. Das ist die erste Messung seit dem Umbau des Editors.
  • Im laufenden Editor durchgespielt: Doppelklick setzt das Element auf contenteditable="plaintext-only", eine Eingabe landet im Modell (Speicherstatus wechselt auf „Ungespeicherte Änderungen“, der Strukturbaum zeigt den neuen Text), und das Verlassen beendet die Bearbeitung sauber. Die Kontrastwarnung meldete bei #cccccc auf #ffffff korrekt „Kontrast 1.6:1 – zu wenig“. Die Schaltflächen zum Kopieren und Einfügen erscheinen mit richtigem Aktivierungszustand. Die Teständerungen wurden verworfen und nicht gespeichert.
  • Gestaltungsvorlagen über HTTP geprüft: anonymer Zugriff führt zur Anmeldung, CSRF-Token ist Pflicht, ein Stil mit eingeschleuster Deklaration und ein leerer Name werden mit HTTP 422 abgewiesen ohne zu schreiben, Speichern und Entfernen funktionieren, und das Designpanel erhält Vokabular, Palette und Vorlagen aus einer Quelle.
  • Freie Gestaltung geprüft: ein v10-Dokument mit Farben, Abständen je Seite, Ecken je Ecke, Schatten, Hover und eigenem Mobilwert wird unverändert gespeichert und zu blockgenauem CSS samt Media Query und Hover-Regel. Vierzehn abgewiesene Eingaben schreiben nichts: unbekannte Eigenschaft, unbekanntes Gerät, Farbe als Wort, Farbe als Funktion, Länge ohne Einheit, Länge als calc(), ein eingeschleustes ;position:fixed, Auswahlwert außerhalb der Liste, Zahl außerhalb des Bereichs, Seitenwert als Einzelwert, unbekannte Seite, Hover auf einer Eigenschaft ohne Hover, Schriftschlüssel mit Anführungszeichen und Hintergrundbild als Pfad. Zusätzlich geprüft, dass freie Stile Schema v10 verlangen.
  • Sicherheitsrichtlinie geprüft: das erzeugte Stylesheet wird über seinen eigenen SHA-256-Hash erlaubt, unsafe-inline kommt nicht vor und Skripte bleiben aus. Ohne Google-Schrift wird kein fremder Host erlaubt und keiner kontaktiert; mit Google-Schrift erscheinen fonts.googleapis.com in style-src und fonts.gstatic.com in font-src.
  • Theme geprüft: Palettenfarben werden zu CSS-Variablen und normalisiert, die Schriftvariable enthält Familie und Ersatz, Grundgröße, Zeilenhöhe und Inhaltsbreite wirken auf jeder Seite. Acht ungültige Themes schreiben nichts: Farbe als Wort, doppelter Schlüssel, Schriftname als Stapel, Google-Schrift ohne Namen, Grundfarbe ohne Paletteneintrag, Grundgröße ohne Einheit, Zeilenhöhe außerhalb des Bereichs und leere Palette.
  • Im Editormodell geprüft: Vererbung vom größeren Gerät, einzelnes Zurücksetzen, das Entfernen leerer Reste, Kopieren der Gestaltung ohne geteilte Objekte und ein vollständiges Undo auf den Ausgangszustand.
  • SEO geprüft: die Sitemap ist wohlgeformtes XML und enthält weder eine noindex-Seite noch einen Entwurf, dafür Beitragsübersicht und Begriffsarchiv; robots.txt verweist auf sie und sperrt /admin; eine nicht indexierbare Seite trägt zusätzlich ein noindex-Meta. Weiterleitungen antworten vor dem 404 mit 301 beziehungsweise 410, eine vorhandene Seite gewinnt gegen eine gleichnamige Weiterleitung, und Selbstbezug, Kette, Großbuchstaben sowie ein anderer Statuscode werden abgewiesen. Strukturierte Daten entstehen nur aus gepflegten Werten: ohne Angaben kein Block, danach LocalBusiness mit Anschrift und entdoppelten Profilen, Article mit Autor aus den Beitragsdaten und BreadcrumbList aus der Hierarchie. llms.txt antwortet ausgeschaltet mit 404 und listet eingeschaltet weder eine noindex-Seite noch einen Entwurf. Fünf ungültige Unternehmensangaben schreiben nichts, und in robots.txt überleben weder Markup noch eine zweite Sitemap-Zeile.
  • Formulare geprüft: Ausgabe ohne Skript, Honeypot außerhalb der Tabreihenfolge, gültige Absendung wird gespeichert und per HTTP 303 zurückgeleitet, Einwilligungszeitpunkt festgehalten, keine Absenderadresse in der Zeile sondern ein 64-stelliger Hash, Erfolgsmeldung auf der Zielseite. Fehlerhafte Absendung: HTTP 422, nichts gespeichert, vier Meldungen an den richtigen Feldern mit aria-describedby und aria-invalid, genau eine Zusammenfassung mit role=alert, alle Eingaben erhalten. Vier Spamfälle (gefüllter Honeypot, zu schnell, gefälschte Signatur, zu alter Zeitstempel) werden still verworfen und wie ein Erfolg beantwortet. Das Limit stoppt die sechste Absendung innerhalb einer Stunde. Die Formularverwaltung verlangt Anmeldung, Editorrolle und CSRF-Token und weist eine ungültige Empfängeradresse mit Meldung ab.
  • Tabs geprüft: beide Panels samt Inhalt und Überschrift stehen ohne JavaScript im HTML und sind serverseitig nicht versteckt, die Ankerliste verweist auf die Panels, das Skript wird als externe Datei geladen und nie inline. Die Richtlinie sendet script-src 'self' ausschließlich auf der Seite mit Tab-Block; eine Seite ohne Tabs und die 404-Seite behalten script-src 'none' und laden kein Skript. Ein Tab außerhalb einer Tabgruppe, eine Tabgruppe mit Textkind und Tabs in Schema v6 werden abgewiesen. Im Modell: eine neue Tabgruppe bringt zwei Tabs mit eigenen IDs mit, nimmt nur Tabs auf, und ein Tab lässt sich weder in eine Sektion noch in ein Akkordeon einfügen.
  • Neue Blöcke geprüft: eine Seite aus allen zehn Abschnittsarten wird unverändert gespeichert, veröffentlicht und ausgegeben; Kontaktdaten werden zu tel:- und mailto:-Verweisen mit bereinigter Nummer, das Akkordeon ist ein echtes details-Element, Symbole sind Inline-SVG, die Bewertung ist für Screenreader ausgeschrieben, und die Ausgabe enthält kein script. Vierzehn abgewiesene Eingaben schreiben nichts: unbekanntes Symbol, fehlender Titel, javascript:-Ziel, Bewertung außerhalb 0–5 und als Zeichenkette, leerer Kontaktblock, ungültige Telefonnummer und E-Mail-Adresse, unbekannte Abstandsgröße, unerlaubtes Linkschema, Text in Logoleiste und Akkordeon, Akkordeon-Eintrag ohne Akkordeon sowie Kinder an einer Trennlinie. Zusätzlich geprüft, dass die neuen Blöcke in Schema v5 weiterhin abgewiesen werden.
  • Beiträge geprüft: Sortierung nach Datum mit Paginierung und Begrenzung zu großer Seitenzahlen, Seiten und unveröffentlichte Beiträge bleiben aus dem Archiv, Kategorie- und Schlagwortarchive einschließlich getrennter Namensräume, erneutes Speichern ersetzt die Zuordnung statt sie zu ergänzen, ein leer gewordenes Archiv antwortet weiter mit HTTP 200 und leerer Liste, Löschen löst die Zuordnungen und lässt die Begriffe bestehen, Veröffentlichen stempelt ein fehlendes Datum und lässt ein gepflegtes unangetastet, Seiten werden nie gestempelt. Sechs abgewiesene Metadateneingaben schreiben nichts und erhöhen die Version nicht. Die Beitragsliste zeigt nur Beiträge des gefilterten Begriffs, und das gespeicherte Dokument enthält weiterhin ausschließlich Anzahl und Filter. Der Feed ist wohlgeformtes XML mit absoluten Adressen und enthält keinen unveröffentlichten Beitrag.
  • Menüs geprüft: Seiten-, Anker- und externe Ziele einschließlich tel: in der Ausgabe, aria-current nur auf der tatsächlich aktuellen Seite und nicht auf Ankereinträgen, gelöschte und unveröffentlichte Seiten fallen aus der Navigation ohne die übrigen Einträge zu verlieren, Kinder eines übersprungenen Eintrags rücken nach, gespeicherte Einträge bleiben erhalten und erscheinen nach dem Veröffentlichen wieder. Zehn abgewiesene Eingaben (leere und überlange Beschriftung, unbekannte Zielart, fehlende Seite, ungültige Sprungziele, javascript:, http:, protokollrelative Adresse, dritte Ebene) schreiben nichts. Über HTTP zusätzlich: anonymer Schreibversuch, CSRF, veraltete Version, Aufbau des Baums aus flachen Formularzeilen mit Position und Ebene, normalisiertes Sprungziel und die Bestätigung, dass die Navigation nicht mehr aus dem Template stammt.
  • Plugin-Erhalt geprüft: ein v4-Dokument mit acme.slider samt verschachteltem Text wird Byte für Byte gespeichert, veröffentlicht und wieder geladen; weder Props noch Kindinhalte noch eine javascript:-URL erscheinen in der öffentlichen Ausgabe, die übrige Seite rendert normal. Fehlerhafte Namensräume und Plugin-Blöcke in v1 bis v3 werden weiterhin abgewiesen, ohne zu schreiben. Im JavaScript-Modell zusätzlich: Verschieben, Duplizieren mit neuen IDs, unverändertes Undo, kein Einfügen in den Baustein und keine Erzeugung über die Elementbibliothek.
  • Testumgebung: tests/bootstrap.php verwirft var/cache/test einmal pro Lauf. Ohne Debug prüft Symfony weder den kompilierten Container noch die Vorlagen auf Aktualität; das hat zweimal ein falsches Ergebnis erzeugt (eine Vorlagenänderung wurde übergangen, später schlug ein geänderter Konstruktor aus einem veralteten Container fehl). Zusätzlich lädt Twig in der Testumgebung automatisch neu.
  • Migration 20260912000600 zuerst gegen eine Kopie der lokalen Datenbank ausgeführt und das Ergebnis kontrolliert: acht Anweisungen, vorhandene Seiten und Dokumente unverändert, neue Tabellen term und page_term, Sortierindex angelegt. Danach nach Backup unter var/backups/before-posts-*.db lokal angewendet.
  • Migration 20260912000500 zuerst gegen eine Kopie der lokalen Datenbank ausgeführt, dann nach Backup unter var/backups/before-menus-*.db lokal angewendet. Seeding legt fehlende Menüs an und lässt vorhandene unverändert; zweimal hintereinander ausgeführt.
  • Migration 20260912000400 zuerst gegen eine Kopie der lokalen Datenbank geprüft und die erzeugten Anweisungen kontrolliert: vier reine ALTER TABLE … ADD COLUMN, kein Tabellenneuaufbau. Danach nach konsistentem Backup unter var/backups/before-hierarchy-20260912-102402.db lokal angewendet; Backfill, Indexumstellung und unveränderte Dokumente überprüft. Wiederholtes Seeding und Produktionsbuild erfolgreich.
  • Composer-/Format-/Twig-/YAML-/Containerprüfungen, Migration, wiederholtes Seeding und Produktionsbuild erfolgreich.
  • Frische Quellkopie ohne bestehende DB/Secrets/Dev-Abhängigkeiten erfolgreich eingerichtet; gespeicherte Seite als HTTP 200 gerendert.
  • Browserprüfung aller drei öffentlichen Seiten mobil und Desktop; keine axe-Verstöße, keine Überläufe, funktionierende Sprunglink-/Navigationsabläufe auch ohne JavaScript.
  • Editor-End-to-End in isolierter Installation: Anmeldung, Auswahl im Iframe, Texteingabe, Undo/Redo, Einfügen/Duplizieren/Verschieben/Drag-and-drop/Löschen, identisches Neuladen, private Entwürfe, Veröffentlichung, Dialog-Fokus/Escape, simulierter Netzwerkfehler mit Wiederholung, 409-Konflikt mit JSON-Export und Server-Neuladen. Einschränkungen der axe-Frameprüfung sind in QUALITY dokumentiert.
  • Ausbau im Browser geprüft: Struktursuche und Auswahl per Tastatur, Einklappen, Abstände, Schriftwerte und Vererbung in echten Gerätebreiten, Rücksetzen/Undo, responsive Zweispaltenvorlage und identische Styles nach Speichern/Publizieren auf allen drei Geräten.
  • Editoroberfläche, Login und Seitenübersicht ohne axe-Verstöße; identisch gerenderter bearbeiteter öffentlicher Inhalt separat geprüft. Desktop- und Mobil-Screenshots visuell durchgesehen.
  • Lighthouse-Startseite: jeweils drei echte mobile und Desktop-Läufe, Median in allen fünf Kategorien 100. Nur lokaler Prototyp; keine Kundenwebsite-Abnahme. Umfang und Grenzen siehe QUALITY.
  • Gestaltete v2-Testseite mit Design-CSS und responsiver Abschnittsvorlage: zusätzliche sechs Lighthouse-Läufe, alle fünf Kategorien jeweils 100; LCP-Median mobil 901 ms/Desktop 240 ms, CLS/TBT 0. Echte Seitenbestände und geöffnete Browserentwürfe unangetastet. Bericht: docs/quality/editor-design-lighthouse.json.
  • v3-Galerieseite mit echten optimierten Testbildern und Effekten: sechs Lighthouse-Läufe, alle fünf Kategorien jeweils 100; LCP-Median mobil 937 ms/Desktop 279 ms, CLS/TBT 0. Upload, Metadaten, Mehrfachauswahl per Tastatur, Bildbeschriftung, Sortier-Undo, Archivieren/Wiederherstellen, Bewegungsreduktion und öffentliche Bilder im isolierten Browserablauf bestanden. Keine axe-Verstöße in Desktop-/Mobil-Mediathek; Screenshots geprüft. Berichte: docs/quality/editor-media-browser.json und editor-media-lighthouse.json.
  • Keine bekannten Dependency-Advisories im ausgeführten Composer-Audit/npm-Installationsaudit.

Bekannte Einschränkungen

  • Gestaltung über geprüfte Tokens, keine beliebigen Pixelwerte, eigenen Schriften oder freien Farben. Noch keine Inline-Textbearbeitung, Formulare, dynamischen Menüs, Plugin-/Themeverwaltung oder WordPress-Import. Abschnittsvorlagen sind lokale Blockrezepte, keine globale Templateverwaltung.
  • Mediathek derzeit für statische Bilder: keine Videos/PDFs/SVGs, Lightbox/Slideshow, freie Bildzuschnitte, Ordner, Paginierung oder physische Löschung. Bild-URLs sind öffentlich; Archivieren schützt keine vertraulichen Dateien. Originale werden durch optimierte Varianten ersetzt. Einblendungen starten beim Laden, nicht beim Scrollen.
  • Sektionen bieten die vorhandenen Farb-/Breitentokens geräteübergreifend. Benutzerverwaltung und Passwortänderung sind noch nicht als Browseroberfläche verfügbar.
  • Offene redaktionelle Feststellung: /grundlagen trägt einen im Editor gesetzten Textblock in #d08080 auf hellem Grund – 2,75:1, unter der AA-Schwelle. Die Farbe wurde nicht verändert, weil sie eine Nutzerentscheidung ist; die Prüfung nennt sie bei jedem Lauf, und die Kontrastwarnung im Editor meldet sie ebenfalls.
  • Aus Umuts erweitertem Auftrag noch offen (Paket G2 im Ausbauplan): die Neugestaltung der Verwaltung.
  • Eigenes CSS kennt keine Gerätevarianten – dafür sind die Vorschaugrößen im Designbereich da. Eigenes Skript hat keine Fassungsverwaltung außer der Seitenhistorie und keine Prüfung auf Syntaxfehler; ein fehlerhaftes Skript schreibt in die Browserkonsole und lässt die Seite sonst unangetastet.
  • Formatierter Text gilt nur für Textblöcke. Überschrift, Button, Zitat und die Titel von Karten, Tabs und Akkordeon bleiben Klartext; Auszeichnung in einer Überschrift bringt mehr Ärger als Nutzen. Die Werkzeugleiste ist nicht mit einem Screenreader geprüft.
  • Offen: der Papierkorb wird nicht automatisch geleert, es gibt keine Aufbewahrungsfrist, und Weiterleitungen aus einem Verschiebevorgang lassen sich nur einzeln in den Einstellungen entfernen.
  • Weiterhin keine Erprobung mit einem Screenreader. Bei der Direktbearbeitung wiegt das: dass der Fokus sinnvoll wandert und der Zustandswechsel angekündigt wird, ist durch axe nicht abgedeckt.
  • Gestaltungsvorlagen lassen sich in der Oberfläche nur anlegen und anwenden, nicht umbenennen; das Entfernen geht bisher nur über die Schnittstelle. Es gibt keine Vorschau einer Vorlage.
  • SEO-Titel und -Beschreibung sind weiterhin die Dokumentfelder; getrennte SEO-Titel gibt es nicht. Das Vorschaubild wird über seine Mediathek-ID eingetragen und noch nicht als og:image aufgelöst. Weiterleitungen werden nur bei genauer Übereinstimmung des Pfades gefunden, ohne Muster und ohne Berücksichtigung von Abfrageparametern; Seiten umbenennen erzeugt noch keine automatische Weiterleitung (Paket F).
  • Dateiuploads in Formularen fehlen – Anhänge brauchen einen nicht öffentlichen Ablageort mit Zugriffsschutz und eine eigene Typprüfung; Begründung in ADR 017. Ebenfalls offen: Formulare lassen sich nicht löschen oder umbenennen, Einsendungen nicht exportieren oder löschen, und es gibt keine Aufbewahrungsfrist. Der tatsächliche E-Mail-Versand ist nie ausgeführt worden: die Tests nutzen einen Transport, der nichts sendet.
  • Das Tab-Skript ist nicht im Browser geprüft: Pfeiltastenbedienung, aria-selected, das Verstecken der Panels und die Auswahl über ein Sprungziel sind nur im Code umgesetzt, nicht ausgeführt. Geprüft ist bisher ausschließlich die serverseitig erzeugte Auszeichnung und die Sicherheitsrichtlinie.
  • Die neuen Blöcke lassen sich nicht in einer Vorlage bündeln: die drei Abschnittsvorlagen sind unverändert. Die Logoleiste hat keine Graustufen- oder Größenoption, die Kundenstimme kein Bild, die Symbolkarte keine eigene Farbe.
  • Beiträge haben noch keine Vorschau des Beitragsbilds in der Verwaltung: das Bild wird über seine Mediathek-ID eingetragen. Es gibt keine Begriffsverwaltung (Umbenennen, Zusammenführen, Löschen ungenutzter Begriffe), keine Beitragssuche und keine Archivbeschreibungen. Die Paginierung der Übersicht ist auf zehn Beiträge je Seite festgelegt.
  • Menüs kennen nur die beiden festen Plätze Hauptnavigation und Fußzeile; weitere Plätze, eigene Menüs pro Seite und automatisch aus der Hierarchie erzeugte Einträge gibt es nicht. Die Einträge werden über Position und Ebene sortiert, nicht per Drag-and-drop.
  • Seiten lassen sich anlegen und löschen, aber noch nicht umbenennen oder verschieben: eine Adressänderung müsste die Pfade aller Unterseiten mitziehen und Weiterleitungen anlegen. Beiträge werden gespeichert und ausgegeben, haben aber noch keine Übersichtsseite, keine Sortierung nach Datum und keine strukturierten Daten. Die Hauptnavigation ist weiterhin fest im Template; verschachtelte Seiten erscheinen dort nicht automatisch.
  • Für diesen Schritt wurden bewusst keine Browser-, Lighthouse- oder axe-Läufe ausgeführt (Nutzerentscheidung). Oberfläche und Ausgabe der neuen Formulare sind nur über die Funktionstests geprüft, nicht visuell.
  • SQLite tatsächlich getestet. MySQL-/MariaDB-Kompatibilität und CI erst vorbereitet, nicht nachgewiesen; Anbieter-/Tarifdetails und Livebetrieb offen.
  • Der Erhaltungsvertrag für Plugin-Blöcke steht, ein Pluginsystem nicht: Registrierung, Hooks, Abhängigkeiten und Ressourcenladen folgen in Phase 4. Kinder eines Plugin-Blocks werden gespeichert, aber nicht gerendert. Kern-Designtokens gelten für sie nicht.
  • Kein Inhaltscache, nur Symfony-Programmcache. Seiten senden no-store; Veröffentlichung ist dadurch ohne Cacheinvalidierungsverzögerung sichtbar.
  • Noch keine repräsentativen Kundeninhalte/Bilder/Blog-/Formularseite, keine Felddaten und keine vollständige manuelle Barrierefreiheitsprüfung.
  • Die vor der Hostingantwort erzeugte .venv bleibt ungenutzt und von Git ausgeschlossen. Die automatische Freigabeprüfung blockierte ihren Löschversuch mit „blocked by policy“; keine Umgehung versucht. Auch var/fresh-check, DB, Secrets und Berichte sind lokal ignoriert.

Nächster konkreter Schritt

Den Editor mit einem Screenreader prüfen und die übrigen Verwaltungsbildschirme in die automatische Barrierefreiheitsprüfung aufnehmen. Danach der Rest von Arbeitspaket G (Inline-Ausbau, globale Bereiche für Header und Footer, wiederverwendbare Sektionen). Danach Arbeitspaket F aus docs/AUSBAUPLAN.md: Seiten umbenennen und verschieben mit Aktualisierung aller Kindpfade und automatischer Weiterleitung, frei wählbare Startseite, geplantes Veröffentlichen, Revisionsliste mit Wiederherstellung und ein Papierkorb statt sofortigem Löschen.

kant-it.de ist seit 12.09.2026 als Pilotwebsite bestimmt. Der öffentliche Bestand wurde erhoben (WordPress 7.1, Flatsome 3.20.9 mit eigenem Child-Theme, WPForms Lite, Complianz, Google-Rezensionen, eigenes Plugin kant-nova-chat) und die noch offene Arbeit daraus in docs/AUSBAUPLAN.md in elf Arbeitspakete aufgeschlüsselt. Erhoben wurde ausschließlich die öffentlich ausgelieferte Startseite; ohne Backendzugang sind Beitragsbestand, Formularkonfiguration, Benutzer und Flatsome-Shortcodes nicht inventarisierbar. Keine externe Veröffentlichung erfolgt.

Lokale Vorschau

Öffentlich: http://127.0.0.1:8080/. Verwaltung: http://127.0.0.1:8080/admin. PHP 8.4.22 im Symfony-Produktionsmodus; der Browser wurde als umut angemeldet. Der Prozess ist sitzungsabhängig; zum erneuten Start README verwenden.