Commit Graph
43 Commits
Author SHA1 Message Date
kantarciandClaude Fable 5.1 5f7ea63b76 Put opening hours, service area and FAQ into the structured data
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
Settings gain opening hours per weekday and a list of places served;
LocalBusiness emits openingHoursSpecification (equal times grouped) and
areaServed. An accordion can be marked as FAQ (schema v23 property
`faq`), which turns its entries into a FAQPage built from the visible
title and text blocks. Elektro Bernhard gets the real office hours
(Mo–Fr 07:30–17:00), the service area from Karlsruhe to Offenburg and
two more questions. ADR 094.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 22:26:47 +02:00
kantarciandClaude Opus 5 73719bae4a Add three icons, a styleable menu button and a reliable back-to-top in 1.13.0
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
The icon set had no drawing for people, music or a house - the three pictures
the Tagespflege Moldovan template asks for. They join as `people`, `music` and
`home`; a test keeps the list and the drawings together, because a missing path
renders an empty `<path d="">`: invisible, without an error.

An icon block's own colour never reached its drawing: the embedded SVG carries
the same `block-icon` class as its wrapper and set the accent colour again.
`.block-icon .block-icon{color:inherit}` fixes it at the root.

The menu button becomes a thing you can shape. `burgerLabel` chooses symbol and
text, text only or symbol only (which keeps the name for screen readers), and
the new style group `menu` targets the button itself, the way `img` targets an
image and `controls` the slider. Inside the header the opened menu now lies
under the header across the full width instead of pushing the header apart -
on a phone that looked like a missing navigation.

The back-to-top button no longer depends on `animation-timeline: scroll()`. A
browser that parses the property but does not run the timeline left it in the
first frame of the animation: permanently invisible. Two classes from
scrolled.js decide now, and without a script the button simply stays visible.

Also: the Tagespflege Moldovan rebuild as its own installation, built only by
`scripts/seed-tagespflege-moldovan.php`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:11:36 +02:00
kantarciandClaude Fable 5.1 fd4cb75548 Add social profiles as a block and rebuild Elektro Bernhard in 1.12.0
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
Social profiles are maintained once under settings (one HTTPS address per
network, SocialProfiles::NETWORKS) and shown by the new `social` block
(document schema v23) wherever it stands: size, shape, layout, labels,
new tab and an optional subset of networks on the block; colour, hover,
spacing and alignment through the free block styles. The addresses also
feed sameAs in the structured data. Icons are own outline drawings in
the style of the existing icon set. ADR 093.

Elektro Bernhard is rebuilt with a dark hero over the team photo, a
transparent header that turns white on scroll, Lato, cards with shadows
and hover lift, a review slider with six real Google reviews, a dark
solar band, page headers on every subpage and staggered entrance
effects. Social profiles sit in the top bar and the footer. The site is
a second local reference installation next to the Kant-IT pilot
(var/elektro-bernhard.db, launch config on port 8088); the seed script
rebuilds it from scratch.

Checked: PHP suite 492 tests (only the documented old failure remains),
33 JS tests, Twig lint, PHP style, full editor browser check with axe.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 19:29:08 +02:00
kantarciandClaude Fable 5.1 3785d3dfef Give the header scrolled colours and equal card heights in 1.11.1
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
Cards, quotes and call-to-action bands side by side in a row are equal in
height again: the stacking margin meant for a column no longer applies inside
a row. The header can carry a second set of colours for the scrolled page,
the Flatsome transparent header: a "scrolled" state next to "hover", limited
to colours, shadow and opacity, marked by a small script only where it is
used, plus a setting that lets the header float over the first section.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 17:44:53 +02:00
kantarciandClaude Fable 5.1 a1f8b905cd Rebuild the editor around one sidebar and play motion by default in 1.11.0
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
The editor follows the Flatsome UX Builder: dark top bar with the device
switch, one sidebar with tabs for elements, structure and page, an element
view with breadcrumbs, property tabs and actions, element cards, a context
menu in the preview and keyboard shortcuts that also work inside the preview.

Entrance and hover effects play for every visitor unless the website chooses
to respect the browser's reduced-motion preference (setting "motion", class
"motion-respect" on <html>). Waiting blocks stay hidden until they scroll into
view and are shown at once when the reader jumps past them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 16:41:04 +02:00
kantarci cff468167b Use standard form buttons and resume entrance effects in 1.10.1
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
2026-09-14 15:22:42 +02:00
kantarci 37c2942d1d Add device visibility and responsive navigation for 1.10.0
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
2026-09-14 14:46:55 +02:00
kantarci 3391fea58b Add visual button presets, jump targets and menu controls
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
2026-09-14 13:47:49 +02:00
kantarci a3029966cb fix: expose accordion contents and add clear insert actions (1.8.3)
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
2026-09-14 12:53:16 +02:00
kantarci 8f475d1374 fix: remove automatically appended footer legal links (1.8.1)
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
2026-09-14 12:30:34 +02:00
kantarci 25fd388f80 fix: reliably reveal image link fields on selection (1.7.4)
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
2026-09-14 11:56:40 +02:00
kantarci 6d21c452bd feat: add new-tab links and removable media previews (1.7.3)
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
2026-09-14 11:48:44 +02:00
kantarci 0920e3cb83 Ergänzt Prozentregler für die responsive Bildbreite
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
2026-09-14 11:20:18 +02:00
kantarci 495b26896e Fassung 1.7.0: verlässliche Installation, übersichtliche Verwaltung und bedienbare Bewegung
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
2026-09-14 10:49:54 +02:00
kantarci 6a044e59e9 Fassung 1.6.2: sichtbare leere Layouts und direktes Befuellen im Editor
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
2026-09-14 09:22:23 +02:00
kantarci b783d9d1e5 Fassung 1.6.1: flexible Editorflaeche und passende Blockeigenschaften
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
2026-09-14 08:57:42 +02:00
kantarciandClaude Opus 5 7c3c8671a7 Fassung 1.5.4: der Werkzeugkasten bekommt Bilder und eine Suche
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
Die Elementwahl war eine Liste aus Schriftzeichen - "▣" fuer Sektion, "☰" fuer
Zeile. Jetzt traegt jeder der 34 Eintraege eine Strichzeichnung, die zeigt, was
er baut: die Sektion ein gefuelltes Band, "Zeile, 3 Spalten" tatsaechlich drei
Kaesten, das Bild einen Rahmen mit Bergzug.

Zeichnungen statt Bilddateien. Flatsome liefert je Element ein PNG mit.
Gezeichnet ist hier besser: library-previews.js ist ein paar hundert Byte statt
eines Ordners voller Bitmaps, die Formen nehmen die Farbe der Flaeche an, auf
der sie liegen - gesperrte Eintraege werden damit von selbst blass - und sie
bleiben auf jedem Bildschirm scharf. Die Zeilenvorschau wird gerechnet: zwei,
drei oder vier Kaesten aus derselben Funktion.

Suche. Ein Feld ueber der Liste filtert ueber alle Gruppen, gesucht wird ueber
Namen, internen Typ und Gruppennamen - wer "slider" eingibt, muss nicht wissen,
dass er unter "Gruppen" steht. Gruppen ohne Treffer verschwinden, darunter
steht wie viele von wie vielen uebrig sind.

Dabei bemerkt: es gab zwei Suchfelder namens "Element suchen" auf einem
Bildschirm, fuer eine Sprachausgabe nicht unterscheidbar. Sie heissen jetzt
nach dem, was sie durchsuchen.

Geprueft: der Browsertest zaehlt die Vorschaubilder gegen die Eintraege und
sucht nach Name, Gruppenname und etwas Nichtvorhandenem. npm test 28/28,
phpunit 452/452, npm run test:editor vollstaendig ohne axe-Verstoss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 08:08:31 +02:00
kantarciandClaude Opus 5 7225ae052e Fassung 1.5.2: die Optionen selbst
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
Drei Bedienungen, die Flatsome an jeder Option hat und die hier fehlten.

Geraeteschalter je Option. Bisher entschied ein einziger Schalter ueber der
Vorschau, welches Geraet das ganze Bedienfeld bearbeitet; "ist die Ueberschrift
auf dem Telefon kleiner" liess sich nur durch Umschalten und Hinsehen
beantworten. Jetzt traegt jede Option drei Chips (D, T, M): sie zeigen, wo ein
eigener Wert liegt, und ein Klick wechselt dorthin. Bedienfeld und Vorschau
wechseln gemeinsam - einen Wert fuer ein Geraet zu setzen, das man nicht
ansieht, ist blindes Aendern.

Abstand als Rahmen. Vier Felder untereinander, beschriftet "Oben, Rechts,
Unten, Links", zwangen zum Lesen. Jetzt sitzt jedes Feld an seiner Kante, die
Lage ist die Beschriftung; in der Mitte verkettet ein Schalter alle vier. Er
startet aus: er ersetzt den frueheren Knopf "Alle Seiten gleich setzen", und
das war eine bewusste Handlung. Seiten mit unterschiedlichen Einheiten gelten
als "gemischt" und bleiben unangetastet - ein gespeichertes 2rem wird nicht
still zu 2px.

Ziehfelder. Zahlenfelder lassen sich seitwaerts ziehen, Umschalt grob, Alt
fein. Tippen und Pfeiltasten bleiben unveraendert. Nur fuer Maus und Stift:
auf einem Tippgeraet ist ein seitliches Ziehen ueber ein Feld die Art, wie das
Bedienfeld gescrollt wird.

Dabei behoben: der Zug war nach einem Pixel zu Ende, weil jede Aenderung das
Bedienfeld neu zeichnete und damit das Feld ersetzte, an dem der Zeiger hing
(keepPanel). Der Kettenschalter verlor aus demselben Grund seinen Zustand. Und
das Gleichziehen nahm den Wert des ersten Feldes, auch wenn es leer war - ein
Druck auf die Kette loeschte damit die Seiten, die einen Wert hatten.

Geprueft: npm test 27/27, phpunit 452/452, npm run test:editor vollstaendig
mit neuem Abschnitt und ohne axe-Verstoss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 07:34:37 +02:00
kantarciandClaude Opus 5 0e2334d30f Fassung 1.5.1: der Werkzeugkasten kennt den Zusammenhang
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
Umuts Einwand: Zeile und Spalte standen oben in der Auswahl, als waeren sie
Seitenanfaenge. Sie gehoeren in den Inhalt - erst eine Sektion, dann eine Zeile
darin. Das war nicht nur eine Anzeigefrage: eine Zeile nahm bisher jedes Kind
an, eine Ueberschrift konnte neben den Spalten landen, und eine Spalte durfte
ueberall stehen. Die Struktur, die der Editor in seinem eigenen Hinweistext
beschreibt, galt fuer die Schaltflaechen nicht.

Uebernommen ist Flatsomes Regelmodell (Elements.php): ALLOW - eine Zeile nimmt
nur Spalten; REQUIRE - eine Spalte lebt nur in einer Zeile. Dazu ein Zusatz,
den Flatsome nicht hat: ROOT_NEEDS_CONTAINER - eine Zeile ist kein
Seitenanfang. In jedem Behaelter bleibt sie erlaubt, auch in einem Tab.

Daraus die Bedienung:

- Werkzeugkasten nach Aufbau gruppiert statt flacher Liste aus 31 Typen.
- Was nicht hingehoert, ist gesperrt und sagt beim Ueberfahren warum. Eine
  Regel, die man erklaert bekommt, lernt man; eine Schaltflaeche, die nur
  nicht mehr reagiert, drueckt man weiter.
- Was moeglich ist, sagt wohin es kommt.
- Die Zeile wird nach Spaltenzahl angeboten und bringt ihre Spalten mit; der
  separate Zeilenbereich ist entfallen.
- insertionTarget beantwortet "wohin kaeme das?", ohne etwas einzufuegen.
  Knopf, Einfuegepunkt, Ziehen und die Sperrlogik nutzen dieselbe Funktion -
  vorher entschied insertBlock allein, und insertRow hatte eine zweite Kopie
  derselben Platzierungslogik.

Ein Element, das der gewaehlte Behaelter nicht nimmt, wird nicht gesperrt,
sondern steigt auf, bis ein Elternteil es annimmt.

Nebenbei behoben: postnav fehlte seit Schema v18 in labels und icons, der
Strukturbaum zeigte dafuer "Unbekannt" und ein Fragezeichen.

Geprueft: npm test 27/27, phpunit 446/446, npm run test:editor vollstaendig
mit neuem Abschnitt und ohne axe-Verstoss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 07:13:25 +02:00
kantarciandClaude Opus 5 22e4ada830 Fassung 1.5.0: die Vorschau wird zur Arbeitsflaeche
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
Abgleich mit dem Flatsome UX Builder (docs/FLATSOME-ABGLEICH.md): die Gestaltung
ist Flatsome voraus, die Luecken liegen beim Elementkatalog und bei der
Bedienung. Umuts Entscheidung: Bedienung zuerst, Shop-Elemente ausgelassen.

Erste Haelfte der Bedienung:

- Werkzeugleiste am Element in der Vorschau. Sie nennt das Element, auf das sie
  wirkt - die Seitenleiste hat dieselben fuenf Aktionen, und zwei gleichnamige
  Bedienelemente auf einem Bildschirm sind fuer eine Sprachausgabe nicht
  unterscheidbar. Beide Wege rufen dieselben Funktionen auf.
- Auswahl- und Ueberfahrrahmen mit Beschriftung.
- Einfuegepunkte an Ober- und Unterkante: das naechste Element landet dort
  statt am Ende.
- Ziehen aus dem Werkzeugkasten in die Vorschau, mit Ablegemarke zwischen den
  Elementen und Rahmen um einen aufnehmenden Behaelter. Der Strukturbaum zieht
  in dieselbe Flaeche.

Die Ebene liegt ueber dem Rahmen, nicht darin: die Vorschau wird bei jeder
Aenderung ersetzt, eingezeichnete Bedienelemente waeren weg und stuenden in der
Auszeichnung, die die Vorschau wahrheitsgetreu zeigen soll. Leiste und
Pluszeichen werden gegenskaliert und bleiben in der Mobilvorschau fingergross.

Im Modell neu: insertBlockAt, moveBlockTo, dropList.

Dabei behoben: die Ebene war aria-hidden und enthielt fokussierbare
Schaltflaechen; canContain zerbrach an einem fehlenden Block beim Ziehen aus
dem Werkzeugkasten; beim Verschieben ans Listenende wurde der Index begrenzt,
bevor die Entnahme verrechnet war.

Geprueft: npm test 22/22, phpunit 434/434, npm run test:editor vollstaendig
mit neuem Abschnitt und ohne axe-Verstoss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 06:53:23 +02:00
kantarciandClaude Opus 5 de1e66350b Knopf nach oben, Bildbetrachter, Rechtszeile als Baustein (Schema v19)
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
Der Knopf "nach oben" ist ein Anker, kein Skript: er springt an den
Seitenanfang, eingeblendet ueber eine Scroll-Zeitachse. Abschaltbar und
vollstaendig einstellbar - Seite, Form, Groesse, Farben, Schwelle,
Beschriftung.

Bilder lassen sich vergroessern, je Bild waehlbar (nichts / vergroessern
/ Adresse), Galerien mit einem Schalter. Grundlage ist ein gewoehnlicher
Verweis auf die grosse Fassung: ohne JavaScript oeffnet er das Bild, mit
JavaScript einen dialog-Betrachter mit Blaettern, Escape und Pfeiltasten.
Das Skript laedt nur, wo es etwas zu tun hat.

Die Rechtszeile wird ein Baustein und steht damit im Fussbereich statt
als heller Streifen darunter. Die eingebaute Leiste erscheint nur noch,
wenn die Seite den Baustein nicht enthaelt.

Dabei gefunden: zwei Stylesheet-Regeln griffen seit drei
Veroeffentlichungen nicht mehr. Beim Entfernen alter Regeln waren
Selektorreste stehen geblieben, und CSS nimmt dann die naechste Regel
mit - betroffen waren der Einwilligungsdialog und die Rechtszeile. Ein
Test prueft jetzt jede CSS-Datei auf abgebrochene Selektoren.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 19:35:43 +02:00
kantarciandClaude Opus 5 6c477a52be Vorschau zeigt nie eine Seite ohne ihre Gestaltung
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
Gemessen: die Farben in der Vorschau und auf der veroeffentlichten
Seite waren immer identisch. Der Aufbau war das Problem - die
erzeugten Stile wurden im load-Ereignis des Rahmens angewandt, und das
feuert erst, wenn das letzte Bild geladen ist. Auf der nachgebauten
Startseite stand die Vorschau dadurch 1440 ms lang ohne eine einzige
Farbe da.

Jetzt wird angewandt, sobald das Dokument geparst ist; der Rahmen
bleibt bis dahin verdeckt; und gestaltet wird nur das neue Dokument -
der erste Anlauf gestaltete das alte und schaltete zu frueh sichtbar.

Die Editorkontrolle prueft dagegen das Verhalten statt der Zeit: der
Rahmen muss beim Aufbau verdeckt werden und danach wieder sichtbar.
Eine Zeitmessung haette auf der kleinen Testseite nichts gefunden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 16:08:12 +02:00
kantarciandClaude Opus 5 0d6c1a17af Vier Darstellungen fuer die Beitragsliste
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
Karten (Raster mit Bild oben), Liste (Bild links, Text rechts), Kompakt
(nur Titel und Datum) und Wechselseitig (Bild mal links, mal rechts).
Dieselben Daten, dasselbe Markup - nur eine Klasse wechselt.

Die erste Fassung von "Wechselseitig" war ein umgedrehter Flexkasten und
sah auch so aus. Jetzt sitzt das Bild in einer Karte mit Ecken, Schatten
und festem Verhaeltnis, der Text hat eine Nummer aus einem CSS-Zaehler,
eine begrenzte Zeilenlaenge und einen sichtbaren Verweis, und zwischen den
Reihen liegt eine feine Linie.

Zwei Details: die Karte ist das Listenelement, also zaehlt :nth-child auf
ihr - die erste Fassung wechselte deshalb gar nicht. Und die Umkehrung
laeuft ueber order statt row-reverse, damit auf dem Telefon sauber wieder
Bild ueber Text steht.

Geprueft: 399 Tests unter PHP 8.2 und 8.4, 18 JS-Tests, Editortest,
Browserpruefung, axe ohne Verstoss auf allen vier Darstellungen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 11:34:06 +02:00
kantarciandClaude Opus 5 1b22265a54 Beitragsnavigation als Baustein (Dokumentschema v18)
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
Umut: "Beitragsseite gefaellt mir nicht, sollte wie bei kant-it.de sein
oder besser. Falls noetig Plugin bauen."

Die Originalseite hat Galerie, Vor/Zurueck zwischen Projekten und einen
Abschlussaufruf. Galerie und Aufruf gab es laengst - sie waren nur nicht
benutzt. Die Navigation gab es nicht.

Kein Plugin: ein Plugin ist hier ein Bausteintyp, dessen Eigenschaften der
Kern aufbewahrt, aber nicht rendert - es koennte also nichts ausgeben,
solange es keine Laufzeit dafuer gibt. Und die Nachbarn eines Beitrags
stehen in derselben Tabelle wie die Beitragsliste, die der Kern schon
fuellt. Also ein Baustein: postnav.

Gespeichert sind zwei Beschriftungen, mehr nicht - welcher Beitrag vorher
und nachher kommt, entscheidet der Renderer. Gesucht wird innerhalb
derselben Kategorie, und am Rand wird nicht umgebrochen.

Ausserdem: die uebernommenen Projekttexte begannen mit dem wiederholten
Titel (20 Beitraege), und schmale Abschnitte standen links statt mittig -
max-width ohne margin:auto ist eine halbe Einstellung.

Geprueft: 396 Tests unter PHP 8.2 und 8.4, 18 JS-Tests, Editortest,
Browserpruefung, axe ohne Verstoss auf der Beitragsseite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 10:56:18 +02:00
kantarciandClaude Opus 5 5a5933f8cd Slider mit Autorotation, Beitragsliste mit Blaettern
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
Zwei Wuensche, zwei Bausteine.

Die Autorotation ist Sekunden, kein Haekchen: 0 heisst aus, ab 3 laeuft
sie. Sie braucht ein Skript - das zweite auf einer oeffentlichen Seite
nach den Tabs - und es kommt nur auf Seiten mit einem solchen Slider,
sonst bleibt script-src 'none'. Es laeuft nicht bei "weniger Bewegung",
hoert beim ersten Tippen, Klicken, Wischen oder Scrollen endgueltig auf
und pausiert bei Zeiger, Fokus, Hintergrundtab und ausserhalb des Bildes.
Ohne Skript bleibt der Slider vollstaendig bedienbar.

Die Beitragsliste kann blaettern statt abzuschneiden. Eine Auswahl auf der
Startseite zeigt die neuesten und hoert auf; eine Uebersichtsseite
blaettert und sagt, wie viele es sind. Das war die eigene Regel aus
Arbeitspaket M, die fuer diesen Baustein noch nicht galt.

Beim Bauen zweimal dieselbe Falle wie vorgestern: eine Variable war in der
Schliessung nicht gebunden. Einmal das Sprungziel des Sliders (-78 statt
666), einmal die Seitenzahl - die zweite fiel sofort auf, weil die Seite
mit 500 antwortete.

Geprueft: 395 Tests unter PHP 8.2 und 8.4, 18 JS-Tests, Editortest,
Browserpruefung, axe ohne Verstoss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 10:40:50 +02:00
kantarciandClaude Opus 5 e21dff91fe Slider mit Punkten, Karten als Karten, hervorgehobenes Wort
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
Umut hat den Nachbau Detail fuer Detail mit kant-it.de verglichen. Vier
Stellen, an denen das CMS etwas nicht konnte oder etwas Falsches tat.

Der Slider zeigte eine Rollleiste statt Punkte. Punkte zeichnet jetzt der
Browser selbst - scroll-marker-group und ::scroll-marker, ohne Skript, mit
erkennbarem aktivem Punkt. Wo ein Browser das noch nicht kennt, bleibt das
wischbare Schiebefeld. Pfeile gibt es bewusst nicht: Chrome legt
::scroll-button an den Seitenrand statt in den Slider. Und er rotiert
nicht von selbst, weil eine oeffentliche Seite kein JavaScript laedt.

Eine Beitragskarte war keine Karte, sondern eine lose Spalte. Jetzt weiss,
18px Ecken, Bild buendig oben im Verhaeltnis 16:10, Text darunter.

Die Theme-Schriftskala ueberschrieb die Groessen der Bausteine: jede
Kartenueberschrift war so gross wie eine Abschnittsueberschrift.

Eine Ueberschrift darf ab v17 ein Wort hervorheben. Dabei waere beinahe
eine Luecke entstanden: die Dokumentfassung war in der Schliessung des
Filters nicht gebunden, der Filter lief nie, die Ausgabe war schon
unescaped. Ein Test mit <script> in einer Ueberschrift hat es gezeigt.

Geprueft: 390 PHP-Tests unter 8.2 und 8.4, 18 JS-Tests, Editortest,
Browserpruefung, axe ohne Verstoss auf dem Nachbau.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 00:23:02 +02:00
kantarciandClaude Opus 5 70283db20a Dokumentschema v17: Projektraster, verlinktes Bild, klebender Kopfbereich
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
Alles aus dem Nachbau von kant-it.de, den Umut durchgesehen hat.

Eine Beitragsliste kann Datum, Autor, Auszug und Kategorie ausblenden und
sieht damit aus wie ein Projektraster statt wie ein Blogarchiv. Beinahe
lautlos danebengegangen: |default(true) macht in Twig aus einem
gespeicherten false ein true - die Einstellung haette sich speichern
lassen und nichts getan. Der Test prueft beide Richtungen.

Ein Bild darf verlinken, damit ein Logo auf die Startseite zeigt; die
Adresse geht durch dieselbe Pruefung wie jeder andere Link. Und der
Kopfbereich kann beim Scrollen oben bleiben - als Einstellung der
Website, weil nur das umschliessende Element kleben kann.

Der groesste Fund steckt im Editor: die Liste bekannter Schemafassungen
endete bei 12, waehrend Bausteine v13 bis v15 verlangen. In einem
aktuellen Dokument liess sich damit kein Baustein mehr einfuegen, und
Symbol, Fortschritt, Slider und externer Inhalt in gar keinem. Jetzt eine
Zahl an einer Stelle, mit einem Test ueber jeden Typ und jede Fassung.

Geprueft: 389 PHP-Tests unter 8.2 und 8.4, 18 JS-Tests, Editortest,
Browserpruefung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 00:02:23 +02:00
kantarciandClaude Opus 5 af3589c95c Seitenbreite wirkt, vier Menueplaetze, Seiten ohne Kopfbereich
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
Drei Fragen, drei unterschiedliche Antworten.

Die globale Seitenbreite war einstellbar und wirkte nur in eine Richtung:
site.css schrieb width:min(1180px,...), also schluckte die 1180 jeden
groesseren Wert aus dem Designbereich. Schmaler ging, breiter nicht, ohne
jede Meldung. Die Zahl kommt jetzt aus dem Theme. Das ist der dritte Fehler
dieser Art an einem Tag - nach der Rahmenstaerke und der Bildrundung -, und
alle drei hatten dieselbe Ursache: CSS, das nie gegen eine Erwartung geprueft
wurde.

Menueplaetze und Menueart waren vermischt. Wo ein Menue steht, bestimmt der
Block und war immer frei. Welche Eintraege es zeigt, bestimmt der Platz -
davon gab es zwei, jetzt vier (Haupt, zweite, Fusszeile, Rechtliches). Wie es
aussieht, war gar nicht einstellbar: jetzt waagerecht, untereinander oder
aufklappbar als Burger. Der Burger ist ein details-Element, denn ein Menue,
das ein Skript zum Oeffnen braucht, geht auf einer Seite ohne Skript nicht auf.

"Seiten ohne Menue" war nicht moeglich - der Kopfbereich war ein Dokument fuer
alle Seiten. Jetzt waehlt jede Seite: Standard, ein anderer Bereich, oder
keiner. Dafuer musste die Regel "es gibt genau einen Kopf- und Fussbereich"
fallen; sie war richtig, solange niemand waehlen konnte, und wurde falsch,
sobald man waehlen kann. Ein bestehender Test, der diese Regel zusicherte, ist
deshalb umgeschrieben und prueft jetzt die neue.

Gespeichert wird die Wahl, nicht das Ergebnis: leer heisst Standard, none
heisst keiner, sonst die Adresse. Ein Verweis auf einen geloeschten Bereich
faellt auf den Standard zurueck, statt die Seite stillschweigend ohne
Navigation auszuliefern.

Neu im Ausbauplan: ein einzelnes install.php, das das Releasearchiv
herunterlaedt und entpackt, damit niemand tausende Dateien per FTP hochladen
muss. Mit den Regeln, die darueber entscheiden, ob das eine Hilfe oder eine
Einladung ist: Adresse und SHA-256 stehen in der Datei und nicht im Formular,
HTTPS mit Zertifikatspruefung, Schutz gegen ZIP-Slip, Selbstloeschung danach.

336 PHP-Tests / 1354 Assertions, 17 JS-Modelltests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 21:15:03 +02:00
kantarciandClaude Opus 5 67b85751cf Randlose Abschnitte, volle Bildschirmhoehe, Vollbild-Hero
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
Umuts Frage: "Haben wir bilder usw als volles bild startseite? 100% hoehe
usw?" Die Teile gab es, die Kombination nicht - und zwei Sachen fehlten
wirklich.

Abschnittsbreiten: neu "randlos" (ohne Begrenzung, ohne Rand, von Kante zu
Kante) und "breit" (1600 px) neben normal und schmal. Vorher war jeder Inhalt
auf 1180 px begrenzt; ein Bild von Kante zu Kante war nicht moeglich.

Hoeheneinheiten: neu dvh, svh, lvh. 100vh ist auf dem Handy hoeher als der
Bildschirm - es meint die Ansicht ohne Adressleiste, und der untere Rand
verschwindet darunter. 100dvh ist das, was jemand meint, der "volle Hoehe"
sagt.

Und eine Vorlage "Vollbild-Hero", die die ganze Kombination auf einen Klick
setzt: randlos, 100dvh (mobil 80dvh), Inhalt senkrecht zentriert,
Hintergrundbild formatfuellend, dunkle Ueberlagerung damit der Text lesbar
bleibt, Ueberschrift, Text, Button. Die Teile waren alle da, aber diese
Kombination zu finden war eine Recherche.

328 PHP-Tests / 1329 Assertions, 17 JS-Modelltests. Geprueft: vier Breiten
angenommen und eine erfundene abgewiesen, sieben Hoehenangaben mit dvh/svh/lvh
und zwei ungueltige, ein randloser Abschnitt mit formatfuellendem Bild, und
die Hero-Vorlage Eigenschaft fuer Eigenschaft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 20:52:48 +02:00
kantarciandClaude Opus 5 7251b82f09 Designer: 93 Eigenschaften, neun Einblendungen, drei neue Bausteine
Umut fragte nach Zeilen, nach Rahmen und Rundungen - und ob der Designer so
aufgestellt ist wie Flatsome. Der Vergleich steht in
docs/DESIGNER-VERGLEICH.md, mit der Einschraenkung, dass Flatsome hier nicht
installierbar war: das ist Wissen, keine Messung.

Zwei echte Fehler kamen dabei heraus, beide vorher unbemerkt.

Eine Rahmenstaerke je Seite wurde zu border-width-top. Das ist kein CSS, der
Browser verwirft die Zeile stillschweigend - Rahmenstaerken je Seite hatten
nie eine Wirkung, und es gab keine Meldung, die darauf hingewiesen haette. Die
Schreibweise steht jetzt je Eigenschaft im Schema, weil padding-top dem Namen
folgt und border-top-width nicht.

Und eine Rundung auf einem Bildblock landete auf dem figure, waehrend das Bild
darin eckig blieb. Eigenschaften koennen jetzt auf das Bild im Block zielen
(target 'img' im Schema, eine zweite Regel im Compiler) - deshalb tut
object-fit ueberhaupt etwas, denn auf einem figure tut es nichts.

Von 50 auf 93 Eigenschaften: Bild (Ausschnitt, Bildmitte, Seitenverhaeltnis,
Hoehe, Ecken, Rahmen), Positionierung mit z-index, getrennte Zeilen- und
Spaltenabstaende, Flex je Element, Innen- und Textschatten, acht Bildfilter
als eine filter-Deklaration in fester Reihenfolge, Mischmodus, Zusatzrahmen,
Mauszeiger. Neun Einblendungen mit Verzoegerung, sieben Hover-Effekte, alle
innerhalb von prefers-reduced-motion.

Drei neue Bausteine (Dokumentschema v15): Symbol als eigenes Element,
Fortschritt mit role=meter und dem Wert im Markup statt nur in der
Balkenbreite, und ein Slider als Scrollbereich mit Einrasten - ohne
JavaScript, ohne Autoplay, mit Finger, Trackpad, Mausrad und Tastatur.

Zeilen waren nicht unauffindbar, sondern unbrauchbar leer: eine Zeile ohne
Spalten sieht aus wie nichts. Jetzt legt "Zeile, 2/3/4 Spalten" beides auf
einen Klick an, und im Werkzeugkasten steht, wie der Aufbau gemeint ist.

315 PHP-Tests / 1309 Assertions, 16 JS-Modelltests, axe auf dreizehn
Bildschirmen ohne Verstoesse. 16 Datensaetze rechnen jede Eigenschaftsform
gegen die erwartete Deklaration nach - die Pruefung, die die beiden Fehler
oben gefunden haette, wenn es sie vorher gegeben haette.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 20:37:49 +02:00
kantarciandClaude Opus 5 ee446f1ea1 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>
2026-09-12 19:27:41 +02:00
kantarciandClaude Opus 5 a22a7f7fd7 Eigenes CSS je Element für alle, eigenes Skript nur für Administratoren
Dokumentschema v13. Der neue Reiter "Erweitert" im Editor nimmt zu jedem
Element eigenes CSS und eigenes Skript auf.

Eigenes CSS parst `CustomCode` und schreibt es selbst wieder aus, mit einem
Selektor, den die Klasse setzt und der nie aus der Eingabe stammt. Erlaubt
sind Eigenschaften für das Element und verschachtelte Regeln mit `&`
(`&:hover`, `& > p`, `& .block-text`). Weil neu serialisiert wird, kann eine
überzählige `}` den Block nicht verlassen. Abgewiesen: @-Regeln,
Backslash-Escapes, `expression()`, fremde Selektoren und jede Adresse außer
einem einzelnen `/` oder `https://`. Das darf jeder mit Editorrolle.

Eigenes Skript ist etwas anderes: beliebiges JavaScript auf der
veröffentlichten Website. Deshalb nur für Administratoren, durchgesetzt beim
Schreiben über einen Vergleich mit dem gespeicherten Stand - ein Editor kann
eine Seite mit Skript weiter bearbeiten, das Skript aber nicht anfassen, auch
nicht über eine selbst gebaute Anfrage. Ausgeliefert wird es als
`/assets/seite/{id}.js` und nur für veröffentlichte Seiten, jedes Skript in
einer eigenen Closure mit gesuchtem `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.

Zwei echte Löcher kamen beim Testen heraus und sind behoben: `& .block-text`
wurde zu `#id.block-text`, weil das führende Leerzeichen wegtrimmt wurde, und
`url(//fremd.example/x.png)` kam durch, weil jede Adresse mit `/` erlaubt war.

201 PHP-Tests / 716 Assertions unter PHP 8.2.12 und 8.4.22, Playwright-
Editortest und öffentliche Browserprüfung grün. Nicht geprüft: der Reiter
"Erweitert" ist nicht von Hand bedient und nicht mit einem Screenreader
getestet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 17:17:16 +02:00
kantarciandClaude Opus 5 790f42213c Formatierter Text mit Werkzeugleiste und HTML-Ansicht (Schema v12)
Textblöcke dürfen ab v12 Auszeichnung tragen: fett, kursiv,
unterstrichen, durchgestrichen, Code, hervorgehoben, hoch- und
tiefgestellt, Absätze, Listen und Links.

Die Entscheidung, was erlaubt ist, fällt auf dem Server beim
Speichern - nicht im Editor und nicht beim Rendern. Was in der
Datenbank landet, ist damit schon sicher, also kann kein Renderer das
Filtern vergessen, und eine manipulierte Anfrage speichert nichts,
was der Editor nicht anbietet.

Nicht erlaubte Elemente werden ausgepackt, nicht gelöscht: der Text
bleibt, nur die Auszeichnung geht. script, style, iframe und
Verwandte verschwinden samt Inhalt, weil Auspacken ihren Code als
Text sichtbar machen würde. Attribute fallen weg außer href an a,
und auch das nur nach Adressprüfung.

Ausgegeben wird formatierter Text nur ab v12, dann in einem div statt
einem p, weil die Positivliste Absätze und Listen enthält. Ältere
Dokumente behalten Klartextsemantik und werden weiter maskiert.

Eine Inkonsistenz nebenbei behoben: ein Text mit einem < behielt
echte Zeilenumbrüche, während alles andere <br> benutzte.

Geprüft: 182 PHP-Tests / 685 Assertions unter PHP 8.2.12 und 8.4.22,
darunter dreizehn Fälle durch den Filter mit acht Angriffen, dazu
Editortest mit axe und öffentliche Browserprüfung. Die Werkzeugleiste
selbst ist nicht bedient und nicht mit einem Screenreader geprüft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 16:54:35 +02:00
kantarciandClaude Opus 5 d0938eec69 Kopf, Fuß und verknüpfte Sektionen als Blockdokumente (Paket G, Teil 1)
Migration 20260912001000 legt die Tabelle partial an: Blockdokumente,
die keine Seiten sind. Kopf- und Fußbereich je einmal,
wiederverwendbare Sektionen beliebig viele - im selben Editor
gestaltbar wie eine Seite, weil der Editor seine Schnittstelle aus
einem Datenattribut nimmt statt sie fest zu kennen.

Im Template steht keine Marke und keine Navigation mehr. Ein neuer
Block menu zeigt einen Menüplatz; die Einträge bleiben in der
Menüverwaltung.

Eine Seite braucht genau eine Hauptüberschrift, ein geteilter Bereich
keine - sonst hätte jede Seite, die ihn trägt, zwei. Geteilte
Bereiche haben keinen Entwurf und keine Veröffentlichung: sie sind
überall sichtbar, gespeichert heißt live.

Verknüpft statt kopiert: partialref speichert nur die Adresse, die
Blöcke bleiben im Bereich, und eine Änderung erreicht jede Seite, die
sie einbindet. Zyklen abgewiesen, Verschachtelung auf drei Ebenen
begrenzt, eine entfernte Sektion hinterlässt keine Lücke und der
Verweis bleibt erhalten. Die Abschnittsvorlagen kopieren weiterhin.

Ein echter Fehler kam dabei heraus, der jede dunkle Sektion mit
Spalten betraf: .block-column>.block-text:first-child setzt eine
Farbe für helle Hintergründe und gewinnt auf Spezifität gegen
.tone-ink - gemessen 1,87:1.

Geprüft: 165 PHP-Tests / 660 Assertions unter PHP 8.2.12 und 8.4.22,
15 JavaScript-Modelltests, Editortest mit axe ohne Verstöße,
öffentliche Browserprüfung, Migration nach Backup angewendet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 16:38:08 +02:00
kantarciandClaude Opus 5 ba56add678 Browsertests wiederhergestellt; drei echte Fehler gefunden
Der Playwright-Editortest war durch den Editorumbau kaputt: er
steuerte die abgeschafften Auswahllisten. Umgeschrieben auf die
freien Bedienelemente - Einheitenfelder, Vererbung über drei Geräte,
einzelnes Zurücksetzen, Palettenfarbe, Abstand je Seite, Hover-Regel,
freie Rasterspalten und die weiter vorhandenen Bewegungseffekte.

Dabei kamen drei Fehler heraus, die ohne Browserlauf unsichtbar sind:

1. Die frei gestalteten Werte wirkten in der Editorvorschau gar
   nicht. Ein srcdoc-Iframe erbt die Richtlinie des einbettenden
   Dokuments, und die Verwaltung verbietet Inline-Styles - das
   erzeugte style-Element wurde stillschweigend verworfen.
   Ausgeliefert wurde es korrekt, nur die Vorschau log. Jetzt als
   inertes template plus adoptedStyleSheets.
2. Die Einrückung der Unterseiten in der Seitenliste hat nie
   funktioniert; sie lief über ein style-Attribut, das dieselbe
   Richtlinie verwirft. Jetzt über Klassen.
3. Das Theme setzte alle Links auf die Akzentfarbe und überschrieb
   die kontextabhängigen Farben: 3,08:1 auf dunklem Grund. Die Regel
   gilt jetzt nur für Links in Textblöcken, die voreingestellte
   Linkfarbe liegt auf allen hellen Tönen über 4,5:1.

Geprüft: 155 PHP-Tests / 579 Assertions unter PHP 8.2.12 und 8.4.22,
15 JavaScript-Modelltests, vollständiger Editortest mit axe (null
Verstöße) und Lighthouse 13.4.1 mit je drei Läufen mobil und Desktop,
alle fünf Kategorien 100.

Offen: npm run test:browser schlägt wegen eines Inhalts fehl -
/grundlagen trägt einen im Editor gesetzten Textblock mit 2,75:1.
Nicht verändert, weil es eine Nutzerentscheidung ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 14:16:08 +02:00
kantarciandClaude Opus 5 270cbda9ac Direktbearbeitung, Kontrastwarnung und Gestaltungsvorlagen
Inline-Textbearbeitung ohne Skript in der Vorschau: der Iframe führt
weiterhin kein eigenes JavaScript aus, der Editor greift in sein
Dokument und setzt das Element auf contenteditable. Während der
Bearbeitung wird die Vorschau nicht neu geladen, sonst wäre der
Cursor weg; Eingaben werden zu einem Undo-Schritt zusammengefasst.
Neben dem Doppelklick startet eine Schaltfläche dasselbe ohne Maus.

Kontrast wird nach WCAG 2.1 berechnet und als Warnung in drei Stufen
gemeldet, nicht als Verbot - der Plan verlangt Prüfung, nicht
Bevormundung.

Gestaltungsvorlagen liegen im Theme und gelten seitenübergreifend.
Sie werden mit demselben Compiler geprüft wie ein Blockstil, also
kann über diesen Weg kein Wert hereinkommen, für den ein Block
abgewiesen würde. Dazu Kopieren und Einfügen zwischen Blöcken und
Bildauswahl für Hintergrundbilder über die Mediathek.

Geprüft: 155 PHP-Tests / 579 Assertions unter PHP 8.2.12 und 8.4.22,
15 JavaScript-Modelltests, Lint/Format/Container. Erstmals wurde der
neue Editor im laufenden Betrieb bedient: Direktbearbeitung und
Kontrastwarnung mit echten Werten ausgelöst, Teständerungen
verworfen. Weiterhin keine axe- oder Lighthouse-Messung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 13:20:01 +02:00
kantarciandClaude Opus 5 abf0bd2c6b Freie Gestaltung statt Tokenlisten (Dokumentschema v10)
Der bisherige Editor bot drei Farben, keine Schriftwahl und elf
Auswahllisten mit 44 festen Werten. ADR 008 hatte das mit Sicherheit
begründet - der Schluss war falsch: die Alternative zu beliebigem
CSS-Text ist nicht eine Auswahlliste, sondern ein typisiertes
Designmodell.

StyleSchema erklärt jede Eigenschaft einmal mit Typ, CSS-Entsprechung
und Grenzen. Validator, CSS-Erzeugung und Editorpanel lesen dieselbe
Definition, also kann der Editor nichts anbieten, was der Server
ablehnt. Rund fünfzig Eigenschaften in sieben Gruppen, je Block, je
Gerät und für den Hover-Zustand, mit Vererbung und einzelnem
Zurücksetzen.

Werte sind kurze Zeichenketten mit verankertem Muster, nie CSS-Text;
zusammengesetzte Deklarationen baut der Compiler selbst. Der Server
erzeugt daraus pro Seite ein blockgenaues Stylesheet, das über seinen
eigenen SHA-256-Hash erlaubt wird statt über unsafe-inline.

Theme unter /admin/theme: freie Farbpalette als @schlüssel, Schriften
aus Systemschrift oder Google Fonts, Grundtypografie mit modularer
Überschriftenskala. Google Fonts auf ausdrückliche Nutzerentscheidung;
die Richtlinie öffnet die Hosts nur, wenn wirklich eine eingestellt
ist.

Alte Tokenwerte aus v2 bis v9 bleiben gültig und im Editor unter
"Klassische Werte dieser Seite" bearbeitbar.

Geprüft: 154 PHP-Tests / 563 Assertions unter PHP 8.2.12 und 8.4.22,
15 JavaScript-Modelltests, Lint/Format/Container. Im Browser wurde nur
der Aufbau des Panels bestätigt, kein Gestaltungsvorgang von Hand
ausgeführt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 13:04:54 +02:00
kantarciandClaude Opus 5 d43bd91069 Formulare mit Validierung, Einwilligung und Spamschutz (Arbeitspaket D)
Migration 20260912000700 legt form und form_submission an. Der
Formularblock im Seiteninhalt enthält nur die Adresse: Felder,
Empfänger und Einwilligungstext liegen in der Datenbank, damit ein
gespeichertes Dokument nicht ändern kann, wonach gefragt wird oder
wohin eine Anfrage geht.

Serverseitige Validierung mit einer Meldung je Feld über
aria-describedby und aria-invalid; eine Ablehnung rendert die Seite
mit HTTP 422 und allen Eingaben neu, eine gültige Absendung wird mit
HTTP 303 zurückgeleitet. Alles ohne JavaScript.

Spamschutz ohne Dienst Dritter: Honeypot, signierter Zeitstempel
gegen zu schnelle und zu alte Absendungen, fünf Absendungen je
Absender und Stunde. Ein erkannter Bot bekommt dieselbe Antwort wie
ein Erfolg. Die Absenderadresse wird nie gespeichert, nur ein Hash.

Gespeichert wird vor dem Versand, damit ein kaputter Mailversand
keine Anfrage verliert. Kein CSRF-Token auf dem öffentlichen Weg,
weil das eine Sitzung und damit ein Cookie auf jeder öffentlichen
Seite bedeuten würde; Begründung in ADR 017. Dateiuploads fehlen
bewusst.

Ein echter Fehler von den Tests gefunden: das Stundenfenster des
Limits entstand aus lokaler Zeit, die Zeitstempel aber aus UTC - auf
einer Uhr vor UTC hätte das Limit nie gegriffen.

Geprüft: 117 PHP-Tests / 450 Assertions unter PHP 8.2.12 und 8.4.22,
14 JavaScript-Modelltests, Lint/Format/Container, composer audit.
Der E-Mail-Versand wurde nie wirklich ausgeführt; keine Browser- oder
Lighthouse-Läufe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 11:51:07 +02:00
kantarciandClaude Opus 5 c6ec00a906 Tabs als fortschreitende Verbesserung (Dokumentschema v7)
Auf Entscheidung von Umut werden Tabs jetzt mit JavaScript umgesetzt.
Die Regel "der Seiteninhalt braucht kein Browser-JavaScript" bleibt
dabei eingehalten: der Server liefert eine Ankerliste und alle Panels
mit eigenen Überschriften, versteckt nichts, und ohne Skript ist
jeder Inhalt lesbar und über die Tastatur erreichbar.

public/assets/tabs.js ergänzt tablist/tab/tabpanel, Auswahl per
Pfeiltasten, Home und Ende sowie aria-selected und wählt bei einem
passenden Sprungziel das zugehörige Panel.

Die strenge Richtlinie bleibt Voreinstellung: öffentliche Seiten
senden weiterhin script-src 'none'. Nur eine Seite mit Tab-Block
sendet script-src 'self' und bindet die eine externe Datei ein;
Inline-Skript ist nie erlaubt.

Geprüft: 109 PHP-Tests / 395 Assertions unter PHP 8.2.12 und 8.4.22,
14 JavaScript-Modelltests, Lint/Format/Container. Das Skript selbst
wurde nicht ausgeführt: Tastaturbedienung und ARIA-Verhalten sind
ohne Browserlauf ungeprüft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 11:41:36 +02:00
kantarciandClaude Opus 5 8600384f1a Zehn Blöcke für die Abschnitte der Pilotseite (Arbeitspaket C)
Dokumentschema v6 ergänzt iconcard, stat, quote, logos, cta, contact,
divider, spacer, accordion und accordionitem - die Abschnittsarten,
aus denen die Startseite von kant-it.de besteht.

Symbole liegen als Inline-SVG aus einer festen Liste im Template:
kein Symbolschriftsatz, keine externe Anfrage. Kontaktdaten werden zu
tel:- und mailto:-Verweisen mit bereinigter Nummer. Das Akkordeon
nutzt details/summary und braucht damit kein öffentliches
JavaScript.

Tabs sind bewusst nicht umgesetzt: ohne JavaScript gibt es dafür
keine zugängliche Lösung, und eine CSS-Variante über Radiobuttons
wird als Auswahlfeld statt als Tabliste angekündigt. Begründung in
ADR 015.

Zwei Fehler von den Tests gefunden und behoben: die Regel "ein
Akkordeon-Eintrag gehört in ein Akkordeon" griff nicht auf oberster
Dokumentebene, und ein JavaScript-Test suchte im vorherigen
Dokumentstand, weil history.document vor history.change ausgewertet
wurde.

Geprüft: 107 PHP-Tests / 380 Assertions unter PHP 8.2.12 und 8.4.22,
13 JavaScript-Modelltests, Lint/Format/Container. Keine Browser- oder
Lighthouse-Läufe; für die neuen Blöcke liegt damit keine visuelle
Kontrolle und keine Barrierefreiheitsprüfung vor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 11:34:48 +02:00
kantarciandClaude Opus 5 ebd5883593 Beiträge mit Archiven, Beitragsliste und Feed (Arbeitspaket B)
Migration 20260912000600 ergänzt page.excerpt, author,
featured_media_id und published_at sowie die Tabellen term und
page_term. Beitragsmetadaten beschreiben die Seite, nicht ihren
Inhalt, und liegen deshalb als Spalten statt im Blockdokument: das
Archiv sortiert und paginiert damit in SQL, statt für jede
Auflistung alle Dokumente zu dekodieren.

Kategorien und Schlagwörter teilen sich eine Tabelle mit einem
kind-Feld. Beim Löschen einer Seite verschwinden ihre Zuordnungen,
die Begriffe bleiben als wiederverwendbare Etiketten; ein leer
gewordenes Archiv antwortet weiter mit 200 und leerer Liste.

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. Archive unter /beitraege, /kategorie/{slug} und
/schlagwort/{slug}, Feed unter /feed.xml; alle vier Segmente sind
für Wurzelseiten reserviert.

Geprüft: 91 PHP-Tests / 347 Assertions unter PHP 8.2.12 und 8.4.22,
12 JavaScript-Modelltests, Lint/Format/Container, Migration zuerst
gegen eine Datenbankkopie. Keine Browser- oder Lighthouse-Läufe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 11:25:09 +02:00
kantarciandClaude Opus 5 8e0006f883 Unbekannte Blöcke erhalten statt abweisen (Dokumentschema v4)
Der Lesevalidator wies bisher jeden unbekannten Blocktyp ab, womit der
Fallback im Renderer unerreichbar war: eine Seite mit Bausteinen aus
einer deaktivierten Erweiterung wäre nicht mehr ladbar gewesen. Ab
Schema v4 gilt ein Typ mit Namensraum (acme.slider) als Baustein einer
Erweiterung und bleibt erhalten. Der Kern prüft weiterhin ID, Tiefe,
Blockanzahl und Dokumentgröße, aber bewusst nicht die Props - er kennt
das Schema der Erweiterung nicht.

Damit ungeprüfte Werte nie ausgegeben werden, rendert der Kern aus
einem solchen Block nichts: öffentlich nur ein HTML-Kommentar, in der
Editorvorschau ein Platzhalter. Im Editor bleiben die Blöcke
auswählbar, verschiebbar, duplizierbar und löschbar, aber nicht
bearbeitbar, und es lässt sich nichts in sie einfügen.

Testumgebung: Twig lädt Vorlagen jetzt automatisch neu. Ohne Debug
konnte eine kompilierte Vorlage im Cache den Ausgang eines Testlaufs
bestimmen.

Geprüft: 64 PHP-Tests / 229 Assertions unter PHP 8.2.12 und 8.4.22,
11 JavaScript-Modelltests, Lint/Format/Container. Keine Browser- oder
Lighthouse-Läufe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 10:37:30 +02:00
kantarciandClaude Opus 5 82b07820bc Kant CMS: Grundgerüst, visueller Editor, Mediathek
Symfony 7.4 / Twig / Doctrine DBAL auf herkömmlichem PHP-Webhosting.
Versionierte Blockdokumente (v1-v3) mit unveränderlichen Revisionen,
getrennten Entwürfen/Veröffentlichungen und optimistischer
Konflikterkennung. Visueller Editor mit Strukturbaum, Live-Vorschau,
responsiven Gerätewerten, Abschnittsvorlagen, Bildmediathek,
Galerien und Effekten. Öffentliche Ausgabe ohne Editor-JavaScript.

Geprüft: 41 PHP-Tests / 155 Assertions, 10 JavaScript-Modelltests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 10:19:05 +02:00