Einwilligung, die tatsächlich zurückhält, und Pflichtseiten
Ein Hinweis, der nur fragt und sonst nichts ändert, ist Theater. Deshalb zwei Hälften, und die zweite ist die wichtigere. Die Frage: serverseitig gerendert, per Formular beantwortet, ohne JavaScript - die öffentlichen Seiten laufen mit script-src 'none', und ein Banner mit Skript wäre das eine, was diese Regel bricht. "Alle akzeptieren" und "Nur notwendige" sind dieselbe Art Knopf, gleich groß, nebeneinander. Die Entscheidung steht in einem eigenen Cookie: Fassung der Frage, gewährte Gruppen, Zeitpunkt. Keine Kennung, kein Serverabgleich, ein halbes Jahr. Kein CSRF-Token, absichtlich: die Anfrage ändert nichts auf dem Server, und ein Token bräuchte für jeden Besucher eine Sitzung - genau das, was ein Einwilligungshinweis vermeiden soll. Geprüft wird stattdessen das Rücksprungziel. Das Zurückhalten: der neue Block "Externer Inhalt" (Dokumentschema v14) lädt ohne Einwilligung nichts - kein iframe, keine Adresse im Markup, frame-src 'none'. Der Platzhalter nennt den Anbieter; sein Knopf gewährt genau diese Gruppe und nimmt die vorher gewährten mit. Erst danach kommt der Host in die Sicherheitsrichtlinie, und nur dieser. Im Editor bleibt es immer ein Platzhalter. Datenschutz und Impressum sind keine Einstellung mehr: fehlen sie, warnt die Verwaltung und legt sie auf Knopfdruck als Gerüst an, mit NOCH AUSZUFÜLLEN an jeder Pflichtangabe. Den Text schreibt das CMS nicht - das ist eine rechtliche Aussage über eine Firma. Verlinkt werden beide aus dem Template, nicht aus dem Fußbereich: ein Pflichtlink, den man löschen kann, ist keiner. Dazu der Fehler, den Umut im Screenshot gesehen hat: die Wortmarke stand als Buchstabenkolonne in einem 60 Pixel breiten Kasten. .site-header war noch ein Flexcontainer aus der Zeit des handgeschriebenen Markups und quetschte die Sektion zusammen, und design.css band jede Designklasse an #main - wo Kopf- und Fußbereich seit ADR 026 nicht mehr liegen. Beides behoben. Neu im Ausbauplan: Statistik (serverseitige, wiedererkennungsfreie Zählung, die deshalb keine Einwilligung braucht), Inhalte und Ladeverhalten prüfen (Blättern überall, minimal laden, Ladebudget), Installer (Schritt für Schritt im Browser, Migration inklusive). 245 PHP-Tests / 976 Assertions unter PHP 8.2.12 und 8.4.22. Der Browsertest fand zwei Fehler von mir: grauer Text auf dunklem Fußbereich mit 2,24:1, und das fixierte Banner verdeckte den Einwilligungsknopf am Seitenende. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
84d471acd9
commit
ee446f1ea1
30 files changed
+1298
-154
No files matched your search
@@ -395,3 +395,27 @@ Jetzt rendert `/admin/media` die Bilder selbst, 24 je Seite, neueste zuerst, mit
|
||||
Hochgeladen wird über eine Ablagefläche, weil Umut das Auswahlfeld des Browsers zu Recht hässlich fand. Darunter liegt weiter ein echtes `input[type=file]`, nur unsichtbar und trotzdem fokussierbar; die Fläche ist dessen `label`, und der Fokusring wird über `:focus-within` auf die Fläche gezeichnet. Ohne JavaScript bleibt genau das übrig: ein Dateifeld mit Beschriftung. Das Skript ergänzt Ziehen, benennt die gewählten Dateien und überspringt alles, was kein JPEG, PNG oder WebP ist – abgeschickt wird nie von selbst, der Knopf bleibt die Stelle, an der etwas passiert. Ein `required` hat das Feld nicht: der Browser kann seine Meldung nicht an etwas Unsichtbares hängen, und der Server weist einen leeren Upload ohnehin mit einem lesbaren Satz ab.
|
||||
|
||||
Der Dialog bleibt, was er ist: der Weg, beim Bearbeiten ein Bild auszuwählen. Zwei Wege zum gleichen Bestand mit verschiedenen Aufgaben – `MediaLibrary::list()` bleibt für den Dialog neben `page()` bestehen, weil der Dialog seinen eigenen Filter mitbringt.
|
||||
|
||||
## ADR 032 – Einwilligung: das Banner ist der kleinere Teil (Dokumentschema v14, 12.09.2026)
|
||||
|
||||
Ein Einwilligungshinweis, der nur fragt und sonst nichts ändert, ist Theater: die Inhalte laden trotzdem, und die Frage war Dekoration. Deshalb besteht diese Umsetzung aus zwei Hälften, und die wichtigere ist die zweite.
|
||||
|
||||
**Die Frage.** Serverseitig gerendert, beantwortet durch ein Formular. Kein JavaScript – die öffentlichen Seiten laufen mit `script-src 'none'`, und ein Banner, das ein Skript braucht, wäre das eine, was diese Regel bricht. „Alle akzeptieren“ und „Nur notwendige“ sind dieselbe Art Knopf, nebeneinander, gleich groß; die Auswahl je Gruppe liegt in einem Aufklappfeld. Die Entscheidung steht in **einem** eigenen Cookie: Fassung der Frage, gewährte Gruppen, Zeitpunkt. Keine Kennung, kein Serverabgleich, ein halbes Jahr, dann wird erneut gefragt. Nicht signiert, und zwar absichtlich: das Cookie beschreibt, was dieser Browser gewählt hat, ein gefälschter Wert ändert also nur, was dieser Browser sieht.
|
||||
|
||||
**Das Zurückhalten.** Ein neuer Block `embed` (Dokumentschema v14) hält Inhalte anderer Anbieter. Ohne Einwilligung entsteht **keine Anfrage**: kein iframe, keine Adresse im Markup, kein `frame-src` in der Richtlinie. An seiner Stelle steht ein Platzhalter, der den Anbieter nennt und einen Knopf trägt, der genau diese Gruppe gewährt – und die vorher gewährten mitnimmt, statt sie zu überschreiben. Erst nach der Einwilligung wird der Host der Sicherheitsrichtlinie hinzugefügt, und auch dann nur der Host dieses einen Anbieters. Im Editor bleibt es immer ein Platzhalter: die Vorschau soll nichts von außen laden.
|
||||
|
||||
Der Server prüft die Adresse beim Speichern, nicht beim Ausliefern: nur HTTPS, ein einfacher Hostname, kein Port, keine Zugangsdaten. Der Grund ist, dass diese Adresse in eine Sicherheitsrichtlinie eingesetzt wird – ein Leerzeichen darin wäre eine zweite erlaubte Quelle.
|
||||
|
||||
**Kein CSRF-Token am Einwilligungsformular.** Die Anfrage ändert nichts auf dem Server; sie setzt ein Cookie, das nur den absendenden Browser betrifft. Ein Token bräuchte eine Sitzung, und für jeden Besucher eine Sitzung zu beginnen ist genau das, was ein Einwilligungshinweis vermeiden soll. Geprüft wird stattdessen das Rücksprungziel, damit aus dem Knopf keine Weiterleitung auf fremde Adressen wird.
|
||||
|
||||
**Ohne Grund keine Frage.** Ist der Hinweis abgeschaltet, gilt jede Gruppe als gewährt und die Inhalte laden. Sonst würde das Abschalten des Banners stillschweigend jede Seite leeren, die etwas einbettet.
|
||||
|
||||
## ADR 033 – Datenschutz und Impressum sind keine Einstellung (12.09.2026)
|
||||
|
||||
Umut: „datenschutz und Impressum einbauen sind keine option“. Richtig – in Deutschland sind beide Pflicht und müssen von jeder Seite aus unmittelbar erreichbar sein. Also:
|
||||
|
||||
- Fehlt eine der beiden, **warnt die Verwaltung** auf dem Einstellungsbildschirm, und ein Knopf legt die fehlenden Seiten an und verknüpft sie. Vorhandene Seiten werden nie überschrieben; sie tragen womöglich längst den echten Text.
|
||||
- Die angelegten Seiten sind ein **Gerüst mit markierten Lücken**: jede Pflichtangabe steht als Abschnitt da, mit `NOCH AUSZUFÜLLEN` an der Stelle, wo eine Angabe über ein reales Unternehmen hingehört. Das CMS kann die Struktur vorbereiten, nicht die Erklärung schreiben – das ist eine rechtliche Aussage über eine Firma, und ein erfundener Text wäre schlimmer als eine leere Seite.
|
||||
- Beide werden **von jeder Seite verlinkt**, aus dem Template und nicht aus dem Fußbereich. Der Fußbereich ist ein frei bearbeitbares Blockdokument; ein Pflichtlink, den man versehentlich löschen kann, ist kein Pflichtlink. Die Links liegen mit dem Link „Einwilligung ändern“ in einem benannten Landmark – loser Text außerhalb aller Landmarks ist auch das, was axe zu Recht beanstandet.
|
||||
|
||||
Eine Pfadangabe wird beim Speichern geprüft: zeigt sie auf eine Seite, die es nicht gibt, wird sie abgewiesen.
|
||||
@@ -157,6 +157,49 @@ Anbieter und Tarif festlegen. MySQL oder MariaDB tatsächlich nachweisen statt n
|
||||
|
||||
Abnahme: Die Anwendung läuft auf dem Zielhosting mit MySQL. Messungen mit realen Inhalten liegen vor, einschließlich der Bedingungen.
|
||||
|
||||
### L – Statistik (Nutzerauftrag vom 12.09.2026)
|
||||
|
||||
*Braucht: nichts.*
|
||||
|
||||
Umut: „Als todo noch statistik kannst du das einbauen. Wieviel wann wo wie die seite benutzt haben?“ Ja – und zwar so, dass sie **keine Einwilligung braucht**, denn eine Messung, die niemanden wiedererkennt, ist keine Verarbeitung, über die zu fragen wäre. Das ist der Unterschied zu Google Analytics und der Grund, warum das Banner davon unberührt bleibt.
|
||||
|
||||
**Erhoben wird serverseitig, beim Ausliefern der Seite:** Tag und Stunde (UTC), Pfad, Antwortstatus, ob es ein Erstaufruf oder eine Folgeseite war (aus dem Referrer derselben Website), Herkunftsdomain bei externem Referrer, Gerätegröße-Klasse aus keinem Cookie sondern aus nichts – das geht nicht, also entfällt „wo auf der Seite geklickt wurde“ ersatzlos, solange kein Skript läuft.
|
||||
|
||||
**Gespeichert wird kein Datensatz je Aufruf, sondern ein Zähler:** eine Tabelle `stat_hit` mit `(day, hour, path, status, referrer_host)` und `count`, hochgezählt per `INSERT ... ON CONFLICT DO UPDATE`. Keine IP-Adresse, kein Kennzeichen, kein Cookie, keine Sitzung – auch nicht gehasht, denn ein Hash einer IP-Adresse bleibt ein Personenbezug. Dadurch wächst die Tabelle mit der Zahl der Seiten, nicht mit der Zahl der Besuche.
|
||||
|
||||
**Was das beantwortet:** wie viele Aufrufe wann, welche Seiten, woher verlinkt, welche Adressen 404 liefern, wie sich das über Wochen entwickelt.
|
||||
**Was das nicht beantwortet, und zwar nie:** Besucher gegen Aufrufe (ohne Wiedererkennung nicht unterscheidbar), Verweildauer, Absprungrate, Klickpfade einzelner Personen, Land oder Stadt. Wer das braucht, braucht Wiedererkennung, und damit eine Einwilligung – dann wäre es ein eigener Baustein in der Gruppe `statistics`, die dafür schon existiert.
|
||||
|
||||
**Umsetzung:** ein Abonnent, der nach der Antwort zählt (nur `text/html`, nur Status 200/404, Verwaltung und Assets ausgenommen, Bots per User-Agent-Muster verworfen), ein Bildschirm „Statistik“ mit Tages- und Wochensicht als serverseitig gezeichnetes SVG-Balkendiagramm ohne JavaScript, Aufbewahrung 14 Monate mit Verdichtung auf Tageswerte nach 60 Tagen, und ein Export als CSV. Abnahme: ein Aufruf erhöht genau einen Zähler; ein Aufruf der Verwaltung erhöht keinen; die Tabelle enthält nach 1000 Aufrufen keine Spalte, aus der eine Person hervorgeht.
|
||||
|
||||
### M – Inhalte und Ladeverhalten prüfen (Nutzerauftrag vom 12.09.2026)
|
||||
|
||||
*Braucht: nichts.*
|
||||
|
||||
Umut: „alle inhalte prüfen immer pagination und minimal laden“. Als durchgehende Regel, nicht als einmalige Aufräumaktion:
|
||||
|
||||
- **Jede Liste blättert.** Beitragsarchiv (zehn je Seite) und Mediathek (24 je Seite) tun es. Zu prüfen und zu ändern: Seitenübersicht, Fassungsliste (feste Obergrenze 30 statt Blättern), Formulareinsendungen (feste Obergrenze 50), Benutzerliste, Weiterleitungen, Menüeinträge. Eine feste Obergrenze ist kein Blättern: sie verschweigt, dass etwas fehlt.
|
||||
- **Bilder minimal.** `loading="lazy"` und `width`/`height` überall, `srcset` mit den vorhandenen Breiten statt einer Größe für alle, und kein Bild über der Falz mit `lazy` (das verzögert das Wichtigste).
|
||||
- **Ein Ladebudget je Seite**, in der Browserprüfung nachgemessen statt geschätzt: HTML, CSS und Bilder je Seite mit einer Obergrenze, die bricht, wenn sie überschritten wird. Heute lädt eine öffentliche Seite kein JavaScript, zwei bis drei Stylesheets und die Bilder – das soll so bleiben und nachweisbar sein.
|
||||
- **Abfragen je Seite zählen.** Eine Seite mit zehn verknüpften Sektionen darf nicht zehn Einzelabfragen auslösen. Messen, dann zusammenfassen.
|
||||
|
||||
Abnahme: keine Liste in der Verwaltung, die mehr Einträge hat als sie zeigt, ohne das zu sagen und ohne Blättern. Ein automatischer Test, der die Größe der Startseite und die Anzahl der Datenbankabfragen prüft.
|
||||
|
||||
### N – Installer (Nutzerauftrag vom 12.09.2026)
|
||||
|
||||
*Braucht: die Hostingentscheidung aus Arbeitspaket J für den Schritt „Datenbank“.*
|
||||
|
||||
Umut: „Einen Installer brauche ich noch wie wordpress schritt für schritt alles einrichten migration ausführen usw.“ Heute braucht eine Installation `bin/setup.php` und Konsolenzugriff – auf geteiltem Hosting ist das genau die Hürde, an der es scheitert.
|
||||
|
||||
**Ablauf, wie bei WordPress, aber ohne dessen Nachlässigkeiten:** eine Seite unter `/install`, die nur antwortet, solange keine Installation existiert, und danach dauerhaft 404 liefert. Schritte: (1) Systemprüfung – PHP-Version, benötigte Erweiterungen, Schreibrechte auf `var/` und den Medienordner, ob `public/` wirklich der Dokumentenstamm ist; jede Prüfung mit dem Satz, was zu tun ist, wenn sie fehlschlägt. (2) Datenbank – SQLite-Datei oder MySQL-Zugangsdaten, Verbindung sofort geprüft statt erst beim Speichern. (3) Migration ausführen, mit Ausgabe der angewandten Versionen. (4) Erstes Administratorkonto – Name und Passwort, dieselben Regeln wie in der Benutzerverwaltung. (5) Website – Name, Adresse, Sprache; dazu Kopf- und Fußbereich, Startseite sowie Datenschutz- und Impressumsgerüst anlegen. (6) Fertig: Anmeldung, und eine Liste dessen, was noch auszufüllen ist.
|
||||
|
||||
**Die drei Punkte, an denen WordPress-Installer regelmäßig zum Problem werden, und was hier anders läuft:**
|
||||
- **Der Installer schreibt `.env`,** braucht dafür Schreibrechte im Projektstamm und sagt es, statt die Datei stillschweigend nicht zu schreiben. `APP_SECRET` wird erzeugt, nicht abgefragt.
|
||||
- **Er ist nach dem ersten Durchlauf tot.** Gesperrt wird über den Zustand der Datenbank (existiert ein Konto?), nicht über eine Datei, die jemand löschen kann.
|
||||
- **Er legt keine Zugangsdaten in ein Protokoll und zeigt kein Passwort erneut an.**
|
||||
|
||||
Abnahme: eine leere Installation ist im Browser in sechs Schritten betriebsbereit, ohne Konsole. Ein zweiter Aufruf von `/install` liefert 404. Die Systemprüfung schlägt bei fehlenden Schreibrechten fehl und sagt, welcher Pfad fehlt. Getestet gegen ein leeres Verzeichnis und eine leere Datenbank, nicht gegen die Entwicklungsinstallation.
|
||||
|
||||
### K – Migration von kant-it.de
|
||||
|
||||
*Braucht: B, C, D, E, F, H, J und Backendzugang.*
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# Qualitätsbericht – erster ausführbarer Prototyp
|
||||
|
||||
## 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-ink` und 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-header` war noch ein Flexcontainer aus der Zeit des handgeschriebenen Markups, und `design.css` band 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.
|
||||
|
||||
+5
-1
@@ -1,6 +1,6 @@
|
||||
# Projektstatus
|
||||
|
||||
Stand: 12.09.2026. Das System heißt **KantSites** (vorher Arbeitstitel „Kant CMS“). **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.
|
||||
Stand: 12.09.2026. Das System heißt **KantSites** (vorher Arbeitstitel „Kant CMS“). **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.
|
||||
|
||||
@@ -25,6 +25,9 @@ Erster Commit angelegt (`82b0782`); das Projekt hat damit einen Rückfallpunkt.
|
||||
- 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.
|
||||
- **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.
|
||||
@@ -68,6 +71,7 @@ Erster Commit angelegt (`82b0782`); das Projekt hat damit einen Rückfallpunkt.
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
Reference in new issue
Block a user